import yaml from pathlib import Path from pydantic import BaseModel CONFIG_PATH = Path(__file__).parent.parent / "config.yaml" class Go2RTCConfig(BaseModel): url: str = "http://localhost:1985" class FrigateConfig(BaseModel): url: str = "http://localhost:5000" class MQTTConfig(BaseModel): host: str = "localhost" port: int = 1883 topic_prefix: str = "frigate" username: str = "" password: str = "" class CameraConfig(BaseModel): name: str display_name: str = "" enabled: bool = True order: int = 0 class AlertConfig(BaseModel): enabled: bool = False auto_dismiss_seconds: int = 30 suppression_seconds: int = 60 cameras: list[str] = [] detection_types: list[str] = ["person"] class GridConfig(BaseModel): columns: int | None = None aspect_ratio: str = "16:9" gap: int = 4 class AppConfig(BaseModel): title: str = "Camera Viewer" go2rtc: Go2RTCConfig = Go2RTCConfig() frigate: FrigateConfig = FrigateConfig() mqtt: MQTTConfig = MQTTConfig() cameras: list[CameraConfig] = [] alerts: AlertConfig = AlertConfig() grid: GridConfig = GridConfig() _config: AppConfig | None = None def load_config() -> AppConfig: global _config if not CONFIG_PATH.exists(): _config = AppConfig() return _config with open(CONFIG_PATH) as f: data = yaml.safe_load(f) or {} _config = AppConfig(**data) return _config def save_config(config: AppConfig) -> None: global _config _config = config data = config.model_dump() with open(CONFIG_PATH, "w") as f: yaml.dump(data, f, default_flow_style=False, sort_keys=False) def get_config() -> AppConfig: global _config if _config is None: return load_config() return _config