core/homeassistant/components/camera/prefs.py

101 lines
3.9 KiB
Python

"""Preference management for camera component."""
from __future__ import annotations
from dataclasses import asdict, dataclass
from typing import Final, Union, 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, Union[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 = 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