core/homeassistant/components/camera/prefs.py

109 lines
4.1 KiB
Python

"""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."""
_preload_prefs: dict[str, dict[str, bool | Orientation]]
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_load(self) -> None:
"""Initialize the camera preferences."""
self._preload_prefs = await self._store.async_load() or {}
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
self._preload_prefs[entity_id] = {PREF_PRELOAD_STREAM: preload_stream}
await self._store.async_save(self._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 {}
settings = DynamicStreamSettings(
preload_stream=cast(
bool,
self._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