vigilar/vigilar/web/templates/index.html
Aaron D. Lee 845a85d618 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>
2026-04-02 23:11:27 -04:00

148 lines
5.6 KiB
HTML

{% extends "base.html" %}
{% block title %}Vigilar — Dashboard{% endblock %}
{% block content %}
<div class="row g-3 mb-3">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="bi bi-grid-fill me-2"></i>Live Cameras</h5>
<a href="/kiosk/" class="btn btn-sm btn-outline-light" target="_blank">
<i class="bi bi-fullscreen me-1"></i>Kiosk Mode
</a>
</div>
</div>
</div>
<!-- 2x2 Camera Grid -->
<div class="row g-2" id="camera-grid">
{% for camera in cameras %}
<div class="col-md-6">
<div class="card bg-dark border-secondary camera-card">
<div class="card-body p-0 position-relative">
<div class="camera-feed ratio ratio-16x9">
<video id="feed-{{ camera.id }}" class="w-100" autoplay muted playsinline>
</video>
<div class="camera-offline-overlay d-flex align-items-center justify-content-center">
<div class="text-center text-muted">
<i class="bi bi-camera-video-off fs-1"></i>
<p class="mt-2 mb-0">{{ camera.display_name }}</p>
<small>Connecting...</small>
</div>
</div>
</div>
<!-- Overlay -->
<div class="camera-overlay">
<span class="camera-name">{{ camera.display_name }}</span>
<span class="camera-time" id="time-{{ camera.id }}">--:--</span>
</div>
<div class="camera-motion-dot d-none" id="motion-{{ camera.id }}">
<span class="motion-indicator"></span>
</div>
</div>
</div>
</div>
{% endfor %}
{% if not cameras %}
<div class="col-12">
<div class="alert alert-secondary text-center">
<i class="bi bi-camera-video-off me-2"></i>
No cameras configured. Edit <code>config/vigilar.toml</code> to add cameras.
</div>
</div>
{% endif %}
</div>
<!-- Quick Status Cards -->
<div class="row g-2 mt-3">
<div class="col-md-3">
<div class="card bg-dark border-secondary">
<div class="card-body py-2">
<div class="d-flex align-items-center">
<i class="bi bi-shield-check fs-4 me-3 text-success"></i>
<div>
<small class="text-muted">System</small>
<div id="system-status" class="fw-bold">Disarmed</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-dark border-secondary">
<div class="card-body py-2">
<div class="d-flex align-items-center">
<i class="bi bi-camera-video fs-4 me-3 text-info"></i>
<div>
<small class="text-muted">Cameras</small>
<div id="cameras-online" class="fw-bold">{{ cameras|length }} configured</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-dark border-secondary">
<div class="card-body py-2">
<div class="d-flex align-items-center">
<i class="bi bi-broadcast fs-4 me-3 text-warning"></i>
<div>
<small class="text-muted">Sensors</small>
<div id="sensors-online" class="fw-bold">--</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-dark border-secondary">
<div class="card-body py-2">
<div class="d-flex align-items-center">
<i class="bi bi-battery-full fs-4 me-3 text-success"></i>
<div>
<small class="text-muted">UPS</small>
<div id="ups-status" class="fw-bold">--</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Recent Events -->
<div class="row mt-3">
<div class="col-12">
<div class="card bg-dark border-secondary">
<div class="card-header d-flex justify-content-between align-items-center">
<span><i class="bi bi-list-ul me-2"></i>Recent Events</span>
<a href="/events/" class="btn btn-sm btn-outline-light">View All</a>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-dark table-hover mb-0">
<thead>
<tr>
<th>Time</th>
<th>Type</th>
<th>Source</th>
<th>Severity</th>
</tr>
</thead>
<tbody id="recent-events">
<tr>
<td colspan="4" class="text-center text-muted py-3">
No events yet
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="{{ url_for('static', filename='js/grid.js') }}"></script>
{% endblock %}