vigilar/vigilar/storage/db.py
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

54 lines
1.5 KiB
Python

"""Database engine setup and initialization."""
import logging
from pathlib import Path
from sqlalchemy import create_engine, event, text
from sqlalchemy.engine import Engine
from vigilar.storage.schema import metadata
log = logging.getLogger(__name__)
_engine: Engine | None = None
def _set_wal_mode(dbapi_conn: object, connection_record: object) -> None:
"""Enable WAL mode for concurrent read/write support."""
cursor = dbapi_conn.cursor() # type: ignore[union-attr]
cursor.execute("PRAGMA journal_mode=WAL")
cursor.execute("PRAGMA synchronous=NORMAL")
cursor.execute("PRAGMA busy_timeout=5000")
cursor.close()
def get_engine(db_path: str | Path) -> Engine:
"""Get or create the SQLAlchemy engine."""
global _engine
if _engine is not None:
return _engine
db_path = Path(db_path)
db_path.parent.mkdir(parents=True, exist_ok=True)
url = f"sqlite:///{db_path}"
_engine = create_engine(url, echo=False, pool_pre_ping=True)
event.listen(_engine, "connect", _set_wal_mode)
log.info("Database engine created: %s", db_path)
return _engine
def init_db(db_path: str | Path) -> Engine:
"""Initialize the database: create engine, create all tables."""
engine = get_engine(db_path)
metadata.create_all(engine)
log.info("Database tables initialized")
return engine
def get_db_path(data_dir: str) -> Path:
"""Return the standard database file path."""
return Path(data_dir) / "vigilar.db"