"""YoLink Siren.""" from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass from typing import Any from yolink.device import YoLinkDevice from yolink.exception import YoLinkAuthFailError, YoLinkClientError from homeassistant.components.siren import ( SirenEntity, SirenEntityDescription, SirenEntityFeature, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import ATTR_COORDINATOR, ATTR_DEVICE_SIREN, DOMAIN from .coordinator import YoLinkCoordinator from .entity import YoLinkEntity @dataclass class YoLinkSirenEntityDescription(SirenEntityDescription): """YoLink SirenEntityDescription.""" exists_fn: Callable[[YoLinkDevice], bool] = lambda _: True value: Callable[[str], bool | None] = lambda _: None DEVICE_TYPES: tuple[YoLinkSirenEntityDescription, ...] = ( YoLinkSirenEntityDescription( key="state", name="State", value=lambda value: value == "alert", exists_fn=lambda device: device.device_type in [ATTR_DEVICE_SIREN], ), ) DEVICE_TYPE = [ATTR_DEVICE_SIREN] async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up YoLink siren from a config entry.""" coordinator = hass.data[DOMAIN][config_entry.entry_id][ATTR_COORDINATOR] devices = [ device for device in coordinator.yl_devices if device.device_type in DEVICE_TYPE ] entities = [] for device in devices: for description in DEVICE_TYPES: if description.exists_fn(device): entities.append( YoLinkSirenEntity(config_entry, coordinator, description, device) ) async_add_entities(entities) class YoLinkSirenEntity(YoLinkEntity, SirenEntity): """YoLink Siren Entity.""" entity_description: YoLinkSirenEntityDescription def __init__( self, config_entry: ConfigEntry, coordinator: YoLinkCoordinator, description: YoLinkSirenEntityDescription, device: YoLinkDevice, ) -> None: """Init YoLink Siren.""" super().__init__(coordinator, device) self.config_entry = config_entry self.entity_description = description self._attr_unique_id = f"{device.device_id} {self.entity_description.key}" self._attr_name = f"{device.device_name} ({self.entity_description.name})" self._attr_supported_features = ( SirenEntityFeature.TURN_ON | SirenEntityFeature.TURN_OFF ) @callback def update_entity_state(self, state: dict) -> None: """Update HA Entity State.""" self._attr_is_on = self.entity_description.value( state[self.entity_description.key] ) self.async_write_ha_state() async def call_state_change(self, state: bool) -> None: """Call setState api to change siren state.""" try: # call_device_http_api will check result, fail by raise YoLinkClientError await self.device.call_device_http_api( "setState", {"state": {"alarm": state}} ) except YoLinkAuthFailError as yl_auth_err: self.config_entry.async_start_reauth(self.hass) raise HomeAssistantError(yl_auth_err) from yl_auth_err except YoLinkClientError as yl_client_err: self.coordinator.last_update_success = False raise HomeAssistantError(yl_client_err) from yl_client_err self._attr_is_on = self.entity_description.value("alert" if state else "normal") self.async_write_ha_state() async def async_turn_on(self, **kwargs: Any) -> None: """Turn the entity on.""" await self.call_state_change(True) async def async_turn_off(self, **kwargs: Any) -> None: """Turn the entity off.""" await self.call_state_change(False)