Initial commit: Vigilar DIY home security system

Phase 1 (Foundation): project skeleton, TOML config + Pydantic validation,
MQTT bus wrapper, SQLite schema (9 tables), Click CLI, process supervisor.

Phase 2 (Camera): RTSP capture via OpenCV, MOG2 motion detection with
configurable sensitivity/zones, adaptive FPS recording (2fps idle/30fps
motion) via FFmpeg subprocess, HLS live streaming, pre-motion ring buffer.

Phase 3 (Web UI): Flask + Bootstrap 5 dark theme, 6 blueprints, Jinja2
templates (dashboard, kiosk 2x2 grid, events, sensors, recordings, settings),
PWA with service worker + Web Push, full admin settings UI with config
persistence.

Remote Access: WireGuard tunnel configs, nginx reverse proxy with HLS
caching + rate limiting, bandwidth-optimized remote HLS stream (426x240
@ 500kbps), DO droplet setup script, certbot TLS.

29 tests passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aaron D. Lee
2026-04-02 23:11:27 -04:00
commit 845a85d618
69 changed files with 7061 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
{% extends "base.html" %}
{% block title %}Vigilar — Recordings{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="mb-0"><i class="bi bi-camera-video me-2"></i>Recordings</h5>
<select class="form-select form-select-sm" id="filter-camera" style="width: auto;">
<option value="">All Cameras</option>
</select>
</div>
<div class="card bg-dark border-secondary">
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-dark table-hover mb-0">
<thead>
<tr>
<th>Camera</th>
<th>Started</th>
<th>Duration</th>
<th>Trigger</th>
<th>Size</th>
<th></th>
</tr>
</thead>
<tbody id="recordings-list">
{% for rec in recordings %}
<tr>
<td>{{ rec.camera_id }}</td>
<td>{{ rec.started_at }}</td>
<td>{{ rec.duration_s }}s</td>
<td><span class="badge bg-secondary">{{ rec.trigger }}</span></td>
<td>{{ rec.file_size }}</td>
<td>
<a href="/recordings/{{ rec.id }}/download" class="btn btn-sm btn-outline-light">
<i class="bi bi-download"></i>
</a>
</td>
</tr>
{% else %}
<tr>
<td colspan="6" class="text-center text-muted py-3">No recordings found</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}