"""YoLink home manager.""" from __future__ import annotations import logging from typing import Any from .auth_mgr import YoLinkAuthMgr from .client import YoLinkClient from .const import ATTR_DEVICE_WATER_DEPTH_SENSOR from .device import YoLinkDevice, YoLinkDeviceMode from .exception import YoLinkClientError, YoLinkUnSupportedMethodError from .message_listener import MessageListener from .model import BRDP from .mqtt_client import YoLinkMqttClient from .endpoint import Endpoint, Endpoints _LOGGER = logging.getLogger(__name__) has_external_data_devices = [ATTR_DEVICE_WATER_DEPTH_SENSOR] class YoLinkHome: """YoLink home manager.""" def __init__(self) -> None: """Init YoLink Home Manager.""" self._home_devices: dict[str, YoLinkDevice] = {} self._http_client: YoLinkClient self._endpoints: dict[str, Endpoint] = {} self._mqtt_clients: dict[str, YoLinkMqttClient] = {} self._message_listener: MessageListener async def async_setup( self, auth_mgr: YoLinkAuthMgr, listener: MessageListener ) -> None: """Init YoLink home.""" if not auth_mgr: raise YoLinkClientError("-1001", "setup failed, auth_mgr is required!") if not listener: raise YoLinkClientError( "-1002", "setup failed, message listener is required!" ) self._http_client = YoLinkClient(auth_mgr) home_info: BRDP = await self.async_get_home_info() # load home devices await self.async_load_home_devices() # setup yolink mqtt connection self._message_listener = listener # setup yolink mqtt clients for endpoint in self._endpoints.values(): endpoint_mqtt_client = YoLinkMqttClient( auth_manager=auth_mgr, endpoint=endpoint, broker_host=endpoint.mqtt_broker_host, broker_port=endpoint.mqtt_broker_port, devices=self._home_devices, ) await endpoint_mqtt_client.connect( f"yl-home/{home_info.data['id']}/+/report", self._message_listener ) self._mqtt_clients[endpoint.name] = endpoint_mqtt_client async def async_unload(self) -> None: """Unload YoLink home.""" self._home_devices = {} self._http_client = None # type: ignore for endpoint, client in self._mqtt_clients.items(): _LOGGER.info( "[%s] shutting down yolink mqtt client.", endpoint, ) await client.disconnect() _LOGGER.info( "[%s] yolink mqtt client disconnected.", endpoint, ) self._message_listener = None # type: ignore self._mqtt_clients = {} async def async_get_home_info(self, **kwargs: Any) -> BRDP: """Get home general information.""" return await self._http_client.execute( url=Endpoints.US.value.url, # type: ignore bsdp={"method": "Home.getGeneralInfo"}, **kwargs, ) async def async_load_home_devices(self, **kwargs: Any) -> dict[str, YoLinkDevice]: """Get home devices.""" # sync eu devices, will remove in future eu_response: BRDP = await self._http_client.execute( url=Endpoints.EU.value.url, # type: ignore bsdp={"method": "Home.getDeviceList"}, **kwargs, ) response: BRDP = await self._http_client.execute( url=Endpoints.US.value.url, # type: ignore bsdp={"method": "Home.getDeviceList"}, **kwargs, ) eu_dev_tokens = {} for eu_device in eu_response.data["devices"]: eu_dev_tokens[eu_device["deviceId"]] = eu_device["token"] for _device in response.data["devices"]: _yl_device = YoLinkDevice(YoLinkDeviceMode(**_device), self._http_client) if _yl_device.device_endpoint == Endpoints.EU.value: # type: ignore # sync eu device token _yl_device.device_token = eu_dev_tokens.get(_yl_device.device_id) # type: ignore self._endpoints[_yl_device.device_endpoint.name] = ( _yl_device.device_endpoint ) if _yl_device.device_type in has_external_data_devices: try: dev_external_data_resp = await _yl_device.get_external_data() _yl_device.device_attrs = dev_external_data_resp.data.get("extData") except YoLinkUnSupportedMethodError: _LOGGER.debug( "getExternalData is not supported for: %s", _yl_device.device_type, ) self._home_devices[_device["deviceId"]] = _yl_device return self._home_devices def get_devices(self) -> list[YoLinkDevice]: """Get home devices.""" return list(self._home_devices.values()) def get_device(self, device_id: str) -> YoLinkDevice | None: """Get home device via device id.""" return self._home_devices.get(device_id)