"""Preference management for camera component.""" from __future__ import annotations from collections.abc import Mapping from dataclasses import asdict, dataclass from typing import Final, cast from homeassistant.components.stream import Orientation from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity_registry as er from homeassistant.helpers.storage import Store from homeassistant.helpers.typing import UNDEFINED, UndefinedType from .const import DOMAIN, PREF_ORIENTATION, PREF_PRELOAD_STREAM STORAGE_KEY: Final = DOMAIN STORAGE_VERSION: Final = 1 @dataclass class DynamicStreamSettings: """Stream settings which are managed and updated by the camera entity.""" preload_stream: bool = False orientation: Orientation = Orientation.NO_TRANSFORM class CameraPreferences: """Handle camera preferences.""" def __init__(self, hass: HomeAssistant) -> None: """Initialize camera prefs.""" self._hass = hass # The orientation prefs are stored in in the entity registry options # The preload_stream prefs are stored in this Store self._store = Store[dict[str, dict[str, bool | Orientation]]]( hass, STORAGE_VERSION, STORAGE_KEY ) self._dynamic_stream_settings_by_entity_id: dict[ str, DynamicStreamSettings ] = {} async def async_update( self, entity_id: str, *, preload_stream: bool | UndefinedType = UNDEFINED, orientation: Orientation | UndefinedType = UNDEFINED, ) -> dict[str, bool | Orientation]: """Update camera preferences. Also update the DynamicStreamSettings if they exist. preload_stream is stored in a Store orientation is stored in the Entity Registry Returns a dict with the preferences on success. Raises HomeAssistantError on failure. """ dynamic_stream_settings = self._dynamic_stream_settings_by_entity_id.get( entity_id ) if preload_stream is not UNDEFINED: if dynamic_stream_settings: dynamic_stream_settings.preload_stream = preload_stream preload_prefs = await self._store.async_load() or {} preload_prefs[entity_id] = {PREF_PRELOAD_STREAM: preload_stream} await self._store.async_save(preload_prefs) if orientation is not UNDEFINED: if (registry := er.async_get(self._hass)).async_get(entity_id): registry.async_update_entity_options( entity_id, DOMAIN, {PREF_ORIENTATION: orientation} ) else: raise HomeAssistantError( "Orientation is only supported on entities set up through config" " flows" ) if dynamic_stream_settings: dynamic_stream_settings.orientation = orientation return asdict(await self.get_dynamic_stream_settings(entity_id)) async def get_dynamic_stream_settings( self, entity_id: str ) -> DynamicStreamSettings: """Get the DynamicStreamSettings for the entity.""" if settings := self._dynamic_stream_settings_by_entity_id.get(entity_id): return settings # Get preload stream setting from prefs # Get orientation setting from entity registry reg_entry = er.async_get(self._hass).async_get(entity_id) er_prefs: Mapping = reg_entry.options.get(DOMAIN, {}) if reg_entry else {} preload_prefs = await self._store.async_load() or {} settings = DynamicStreamSettings( preload_stream=cast( bool, preload_prefs.get(entity_id, {}).get(PREF_PRELOAD_STREAM, False) ), orientation=er_prefs.get(PREF_ORIENTATION, Orientation.NO_TRANSFORM), ) self._dynamic_stream_settings_by_entity_id[entity_id] = settings return settings