"""Settings schema registry. The single source of truth for which runtime settings exist. The settings panel is rendered from this list, so adding a new integration/provider only requires adding entries here — no frontend or model changes. Field types: ``string``, ``secret``, ``boolean``, ``choice``, ``number``. Optional keys: - ``depends_on``: ``{"other.key": ["value_a", "value_b"]}`` — field is shown only when every referenced setting currently holds one of the listed values. - ``options``: list of strings or ``{"value", "label"}`` dicts (for ``choice``). """ from apps.live_monitoring.protocols import ( DEFAULT_PROTOCOL, PROTOCOL_KEYS, STREAM_PROTOCOLS, protocol_choice_options, ) def _camera_settings() -> list: """Build Live Monitoring settings from the protocol catalog. Shared defaults always appear. Protocol-specific fields use ``depends_on`` so the settings panel stays dynamic as standards are added to the catalog. """ entries = [ { "key": "camera.enabled", "label": "Enable live camera monitoring", "type": "boolean", "category": "Live Monitoring", "default": True, }, { "key": "camera.default_protocol", "label": "Default stream protocol", "type": "choice", "category": "Live Monitoring", "options": protocol_choice_options(), "default": DEFAULT_PROTOCOL, }, { "key": "camera.stream_ttl_seconds", "label": "Stream access token TTL (seconds)", "type": "number", "category": "Live Monitoring", "default": 3600, }, { "key": "camera.prefer_secure", "label": "Prefer secure schemes (HTTPS / RTSPS / RTMPS)", "type": "boolean", "category": "Live Monitoring", "default": True, }, { "key": "camera.media_gateway_url", "label": "Media gateway base URL", "type": "string", "category": "Live Monitoring", "default": "", "placeholder": "https://media.example.com", }, { "key": "camera.media_gateway_path_template", "label": "Gateway path template", "type": "string", "category": "Live Monitoring", "default": "{camera_id}/index.m3u8", "placeholder": "{camera_id}/index.m3u8", }, { "key": "camera.default_username", "label": "Default camera username", "type": "string", "category": "Live Monitoring", "default": "", }, { "key": "camera.default_password", "label": "Default camera password", "type": "secret", "category": "Live Monitoring", "default": "", }, { "key": "camera.default_auth_method", "label": "Default stream auth method", "type": "choice", "category": "Live Monitoring", "options": [ {"value": "none", "label": "None"}, {"value": "basic", "label": "HTTP Basic"}, {"value": "digest", "label": "HTTP Digest"}, {"value": "bearer", "label": "Bearer token"}, {"value": "query_token", "label": "Query token"}, {"value": "ws_username_token", "label": "WS-UsernameToken (ONVIF)"}, {"value": "passphrase", "label": "Passphrase (SRT)"}, ], "default": "none", }, ] # Protocol-specific defaults — visibility follows camera.default_protocol. for key in PROTOCOL_KEYS: meta = STREAM_PROTOCOLS[key] dep = {"camera.default_protocol": [key]} entries.append( { "key": f"camera.{key}.default_port", "label": f"{meta['label']} — default port", "type": "number", "category": "Live Monitoring", "default": meta["default_port"], "depends_on": dep, } ) entries.append( { "key": f"camera.{key}.default_path", "label": f"{meta['label']} — default path", "type": "string", "category": "Live Monitoring", "default": meta["default_path"], "placeholder": meta["default_path"] or "/", "depends_on": dep, } ) if meta.get("transports"): entries.append( { "key": f"camera.{key}.transport", "label": f"{meta['label']} — transport", "type": "choice", "category": "Live Monitoring", "options": list(meta["transports"]), "default": meta["transports"][0], "depends_on": dep, } ) # WebRTC needs ICE servers when selected. entries.append( { "key": "camera.webrtc.ice_servers", "label": "WebRTC ICE servers (JSON)", "type": "string", "category": "Live Monitoring", "default": '[{"urls":"stun:stun.l.google.com:19302"}]', "placeholder": '[{"urls":"stun:stun.l.google.com:19302"}]', "depends_on": {"camera.default_protocol": ["webrtc"]}, } ) # ONVIF profile token when ONVIF is the default. entries.append( { "key": "camera.onvif.profile_token", "label": "ONVIF media profile token", "type": "string", "category": "Live Monitoring", "default": "", "placeholder": "Profile_1", "depends_on": {"camera.default_protocol": ["onvif"]}, } ) # SRT passphrase (secret) when SRT is selected. entries.append( { "key": "camera.srt.passphrase", "label": "SRT passphrase", "type": "secret", "category": "Live Monitoring", "default": "", "depends_on": {"camera.default_protocol": ["srt"]}, } ) return entries SETTINGS_SCHEMA = [ # --- Odoo integration --- {"key": "odoo.enabled", "label": "Enable Odoo integration", "type": "boolean", "category": "Odoo", "default": False}, {"key": "odoo.url", "label": "Odoo URL", "type": "string", "category": "Odoo", "default": "", "placeholder": "https://odoo.example.com"}, {"key": "odoo.database", "label": "Database", "type": "string", "category": "Odoo", "default": ""}, {"key": "odoo.username", "label": "Username", "type": "string", "category": "Odoo", "default": ""}, {"key": "odoo.auth_method", "label": "Auth method", "type": "choice", "category": "Odoo", "options": ["password", "api_key"], "default": "password"}, {"key": "odoo.password", "label": "Password", "type": "secret", "category": "Odoo", "default": ""}, {"key": "odoo.api_key", "label": "API key", "type": "secret", "category": "Odoo", "default": ""}, # --- SMS provider --- {"key": "sms.provider", "label": "SMS provider", "type": "choice", "category": "SMS", "options": ["mock", "http"], "default": "mock"}, {"key": "sms.endpoint", "label": "HTTP endpoint", "type": "string", "category": "SMS", "default": "", "placeholder": "https://sms.provider.example/api/send"}, {"key": "sms.api_key", "label": "API key", "type": "secret", "category": "SMS", "default": ""}, {"key": "sms.sender", "label": "Sender number", "type": "string", "category": "SMS", "default": ""}, # --- Reservation schedule (dynamic slot generation) --- {"key": "reservation.working_hours_start", "label": "Working hours start", "type": "string", "category": "Reservation", "default": "08:00", "placeholder": "HH:MM"}, {"key": "reservation.working_hours_end", "label": "Working hours end", "type": "string", "category": "Reservation", "default": "17:00", "placeholder": "HH:MM"}, {"key": "reservation.slot_duration_minutes", "label": "Slot duration (minutes)", "type": "number", "category": "Reservation", "default": 30}, {"key": "reservation.default_capacity", "label": "Default capacity per slot", "type": "number", "category": "Reservation", "default": 2}, # --- Live camera monitoring (protocol catalog driven) --- *_camera_settings(), ] SCHEMA_BY_KEY = {entry["key"]: entry for entry in SETTINGS_SCHEMA}