149 lines
4.7 KiB
Python
149 lines
4.7 KiB
Python
"""Helper classes for Yandex Smart Home integration."""
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.core import Context, HomeAssistant, callback
|
|
from homeassistant.helpers.entityfilter import EntityFilter
|
|
from homeassistant.helpers.storage import Store
|
|
from homeassistant.helpers.typing import ConfigType
|
|
|
|
from . import const
|
|
from .const import DOMAIN, NOTIFIERS, STORE_CACHE_ATTRS
|
|
|
|
|
|
class Config:
|
|
"""Hold the configuration for Yandex Smart Home."""
|
|
|
|
def __init__(self,
|
|
hass: HomeAssistant,
|
|
entry: ConfigEntry,
|
|
entity_config: dict[str, Any] | None = None,
|
|
entity_filter: EntityFilter | None = None):
|
|
"""Initialize the configuration."""
|
|
self._hass = hass
|
|
self._data = entry.data
|
|
self._options = entry.options
|
|
self._entity_filter = entity_filter
|
|
|
|
self.cache: CacheStore | None = None
|
|
self.entity_config = entity_config or {}
|
|
|
|
async def async_init(self):
|
|
self.cache = CacheStore(self._hass)
|
|
await self.cache.async_load()
|
|
|
|
@property
|
|
def is_reporting_state(self) -> bool:
|
|
"""Return if we're actively reporting states."""
|
|
if self.is_cloud_connection:
|
|
return True
|
|
|
|
return bool(self._hass.data[DOMAIN][NOTIFIERS])
|
|
|
|
@property
|
|
def is_cloud_connection(self) -> bool:
|
|
return self._data[const.CONF_CONNECTION_TYPE] == const.CONNECTION_TYPE_CLOUD
|
|
|
|
@property
|
|
def is_direct_connection(self) -> bool:
|
|
return self._data[const.CONF_CONNECTION_TYPE] == const.CONNECTION_TYPE_DIRECT
|
|
|
|
@property
|
|
def use_cloud_stream(self) -> bool:
|
|
return self._options[const.CONF_CLOUD_STREAM]
|
|
|
|
@property
|
|
def cloud_instance_id(self) -> str | None:
|
|
return self._data[const.CONF_CLOUD_INSTANCE][const.CONF_CLOUD_INSTANCE_ID]
|
|
|
|
@property
|
|
def cloud_connection_token(self) -> str | None:
|
|
return self._data[const.CONF_CLOUD_INSTANCE][const.CONF_CLOUD_INSTANCE_CONNECTION_TOKEN]
|
|
|
|
@property
|
|
def user_id(self) -> str | None:
|
|
"""User id for service calls, used only in cloud connection."""
|
|
return self._options.get(const.CONF_USER_ID)
|
|
|
|
@property
|
|
def pressure_unit(self) -> str:
|
|
return self._options[const.CONF_PRESSURE_UNIT]
|
|
|
|
@property
|
|
def beta(self) -> bool:
|
|
return self._options[const.CONF_BETA] # pragma: no cover
|
|
|
|
@property
|
|
def notifier(self) -> list[ConfigType]:
|
|
return self._data.get(const.CONF_NOTIFIER, [])
|
|
|
|
@property
|
|
def color_profiles(self) -> dict[str, dict[str, int]]:
|
|
return self._options.get(const.CONF_COLOR_PROFILE, {})
|
|
|
|
@property
|
|
def devices_discovered(self) -> bool:
|
|
return self._data[const.CONF_DEVICES_DISCOVERED]
|
|
|
|
def get_entity_config(self, entity_id: str) -> dict[str, Any]:
|
|
return self.entity_config.get(entity_id, {})
|
|
|
|
def should_expose(self, entity_id: str) -> bool:
|
|
if self._entity_filter and not self._entity_filter.empty_filter:
|
|
return self._entity_filter(entity_id)
|
|
|
|
return False
|
|
|
|
|
|
class CacheStore:
|
|
_STORAGE_VERSION = 1
|
|
_STORAGE_KEY = f'{DOMAIN}.cache'
|
|
|
|
def __init__(self, hass):
|
|
self._hass = hass
|
|
self._store = Store(hass, self._STORAGE_VERSION, self._STORAGE_KEY)
|
|
self._data = {STORE_CACHE_ATTRS: {}}
|
|
|
|
def get_attr_value(self, entity_id: str, attr: str) -> Any | None:
|
|
"""Return a cached value of attribute for entity."""
|
|
if entity_id not in self._data[STORE_CACHE_ATTRS]:
|
|
return None
|
|
|
|
return self._data[STORE_CACHE_ATTRS][entity_id].get(attr)
|
|
|
|
@callback
|
|
def save_attr_value(self, entity_id: str, attr: str, value: Any):
|
|
"""Cache entity's attribute value to disk."""
|
|
if entity_id not in self._data[STORE_CACHE_ATTRS]:
|
|
self._data[STORE_CACHE_ATTRS][entity_id] = {}
|
|
has_changed = True
|
|
else:
|
|
has_changed = self._data[STORE_CACHE_ATTRS][entity_id][attr] != value
|
|
|
|
self._data[STORE_CACHE_ATTRS][entity_id][attr] = value
|
|
|
|
if has_changed:
|
|
self._store.async_delay_save(lambda: self._data, 5.0)
|
|
|
|
async def async_load(self):
|
|
data = await self._store.async_load()
|
|
if data:
|
|
self._data = data
|
|
|
|
|
|
class RequestData:
|
|
"""Hold data associated with a particular request."""
|
|
|
|
def __init__(self,
|
|
config: Config,
|
|
request_user_id: str | None,
|
|
request_id: str | None = None,
|
|
user_id: str | None = None):
|
|
"""Initialize the request data."""
|
|
self.config = config
|
|
self.context = Context(user_id=user_id)
|
|
self.request_user_id = request_user_id
|
|
self.request_id = request_id
|