"""SQLite-Helfer für den Collector (Schema-Init + Schreibzugriffe).""" import os import sqlite3 from datetime import datetime from pathlib import Path SCHEMA_PATH = Path(__file__).with_name("schema.sql") def get_db_path() -> str: return os.environ.get("DB_PATH", "/data/charges.db") def connect() -> sqlite3.Connection: path = get_db_path() Path(path).parent.mkdir(parents=True, exist_ok=True) conn = sqlite3.connect(path) conn.row_factory = sqlite3.Row # Bewusst KEIN WAL: Der web-Container liest die DB read-only aus einem # anderen Prozess. Eine readonly-Verbindung kann eine WAL-Datenbank ohne # aktiven Writer/-shm nicht öffnen ("attempt to write a readonly database"). # Rollback-Journal (Default) lässt readonly-Reads jederzeit zu. return conn def init_db() -> None: """Legt Schema idempotent an und setzt install_date beim ersten Start.""" schema = SCHEMA_PATH.read_text(encoding="utf-8") conn = connect() try: conn.executescript(schema) conn.execute( "INSERT OR IGNORE INTO meta (key, value) VALUES ('install_date', ?)", (datetime.now().isoformat(timespec="seconds"),), ) conn.commit() finally: conn.close() def insert_charge(start_time: str, end_time: str, duration_s: int, energy_wh: float) -> None: conn = connect() try: conn.execute( """INSERT INTO charges (start_time, end_time, duration_s, energy_wh, created_at) VALUES (?, ?, ?, ?, ?)""", (start_time, end_time, duration_s, energy_wh, datetime.now().isoformat(timespec="seconds")), ) conn.commit() finally: conn.close()