diff --git a/.coveragerc b/.coveragerc index d6fe547ac83441..35cdb0002f1f90 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1120,6 +1120,7 @@ omit = homeassistant/components/tuya/scene.py homeassistant/components/tuya/select.py homeassistant/components/tuya/sensor.py + homeassistant/components/tuya/siren.py homeassistant/components/tuya/switch.py homeassistant/components/twentemilieu/const.py homeassistant/components/twentemilieu/sensor.py diff --git a/homeassistant/components/tuya/const.py b/homeassistant/components/tuya/const.py index 43ecefec13b8b5..48524f6b1f213b 100644 --- a/homeassistant/components/tuya/const.py +++ b/homeassistant/components/tuya/const.py @@ -46,6 +46,7 @@ "pir", # PIR Detector "qn", # Heater "sos", # SOS Button + "sgbj", # Siren Alarm "wk", # Thermostat "xdd", # Ceiling Light "xxj", # Diffuser @@ -63,6 +64,7 @@ "scene", "select", "sensor", + "siren", "switch", ] @@ -73,9 +75,13 @@ class DPCode(str, Enum): https://developer.tuya.com/en/docs/iot/standarddescription?id=K9i5ql6waswzq """ + ALARM_SWITCH = "alarm_switch" # Alarm switch + ALARM_TIME = "alarm_time" # Alarm time + ALARM_VOLUME = "alarm_volume" # Alarm volume ANION = "anion" # Ionizer unit BATTERY_PERCENTAGE = "battery_percentage" # Battery percentage BATTERY_STATE = "battery_state" # Battery state + BRIGHT_STATE = "Brightness" # Brightness BRIGHT_VALUE = "bright_value" # Brightness C_F = "c_f" # Temperature unit switching CHILD_LOCK = "child_lock" # Child lock @@ -98,6 +104,7 @@ class DPCode(str, Enum): MATERIAL = "material" # Material MODE = "mode" # Working mode / Mode PIR = "pir" # Motion sensor + MUFFLING = "muffling" # Muffling POWDER_SET = "powder_set" # Powder PUMP_RESET = "pump_reset" # Water pump reset SHAKE = "shake" # Oscillating diff --git a/homeassistant/components/tuya/number.py b/homeassistant/components/tuya/number.py index 91ad3f0e6ba52a..15c7bf3150d3f0 100644 --- a/homeassistant/components/tuya/number.py +++ b/homeassistant/components/tuya/number.py @@ -8,6 +8,7 @@ from homeassistant.components.number import NumberEntity, NumberEntityDescription from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ENTITY_CATEGORY_CONFIG from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -47,6 +48,15 @@ entity_registry_enabled_default=False, ), ), + # Siren Alarm + # https://developer.tuya.com/en/docs/iot/categorysgbj?id=Kaiuz37tlpbnu + "sgbj": ( + NumberEntityDescription( + key=DPCode.ALARM_TIME, + name="Time", + entity_category=ENTITY_CATEGORY_CONFIG, + ), + ), } diff --git a/homeassistant/components/tuya/select.py b/homeassistant/components/tuya/select.py index 2b033757bc957a..3c99e131284414 100644 --- a/homeassistant/components/tuya/select.py +++ b/homeassistant/components/tuya/select.py @@ -8,6 +8,7 @@ from homeassistant.components.select import SelectEntity, SelectEntityDescription from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ENTITY_CATEGORY_CONFIG from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -42,6 +43,20 @@ name="Mode", ), ), + # Siren Alarm + # https://developer.tuya.com/en/docs/iot/categorysgbj?id=Kaiuz37tlpbnu + "sgbj": ( + SelectEntityDescription( + key=DPCode.ALARM_VOLUME, + name="Volume", + entity_category=ENTITY_CATEGORY_CONFIG, + ), + SelectEntityDescription( + key=DPCode.BRIGHT_STATE, + name="Brightness", + entity_category=ENTITY_CATEGORY_CONFIG, + ), + ), } diff --git a/homeassistant/components/tuya/siren.py b/homeassistant/components/tuya/siren.py new file mode 100644 index 00000000000000..42b1f6839f57a2 --- /dev/null +++ b/homeassistant/components/tuya/siren.py @@ -0,0 +1,92 @@ +"""Support for Tuya siren.""" +from __future__ import annotations + +from typing import Any + +from tuya_iot import TuyaDevice, TuyaDeviceManager + +from homeassistant.components.siren import SirenEntity, SirenEntityDescription +from homeassistant.components.siren.const import SUPPORT_TURN_OFF, SUPPORT_TURN_ON +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.helpers.entity_platform import AddEntitiesCallback + +from . import HomeAssistantTuyaData +from .base import TuyaEntity +from .const import DOMAIN, TUYA_DISCOVERY_NEW, DPCode + +# All descriptions can be found here: +# https://developer.tuya.com/en/docs/iot/standarddescription?id=K9i5ql6waswzq +SIRENS: dict[str, tuple[SirenEntityDescription, ...]] = { + # Siren Alarm + # https://developer.tuya.com/en/docs/iot/categorysgbj?id=Kaiuz37tlpbnu + "sgbj": ( + SirenEntityDescription( + key=DPCode.ALARM_SWITCH, + name="Siren", + ), + ), +} + + +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback +) -> None: + """Set up Tuya siren dynamically through Tuya discovery.""" + hass_data: HomeAssistantTuyaData = hass.data[DOMAIN][entry.entry_id] + + @callback + def async_discover_device(device_ids: list[str]) -> None: + """Discover and add a discovered Tuya siren.""" + entities: list[TuyaSirenEntity] = [] + for device_id in device_ids: + device = hass_data.device_manager.device_map[device_id] + if descriptions := SIRENS.get(device.category): + for description in descriptions: + if ( + description.key in device.function + or description.key in device.status + ): + entities.append( + TuyaSirenEntity( + device, hass_data.device_manager, description + ) + ) + + async_add_entities(entities) + + async_discover_device([*hass_data.device_manager.device_map]) + + entry.async_on_unload( + async_dispatcher_connect(hass, TUYA_DISCOVERY_NEW, async_discover_device) + ) + + +class TuyaSirenEntity(TuyaEntity, SirenEntity): + """Tuya Siren Entity.""" + + def __init__( + self, + device: TuyaDevice, + device_manager: TuyaDeviceManager, + description: SirenEntityDescription, + ) -> None: + """Init Tuya Siren.""" + super().__init__(device, device_manager) + self.entity_description = description + self._attr_unique_id = f"{super().unique_id}{description.key}" + self._attr_supported_features = SUPPORT_TURN_ON | SUPPORT_TURN_OFF + + @property + def is_on(self) -> bool: + """Return true if siren is on.""" + return self.device.status.get(self.entity_description.key, False) + + def turn_on(self, **kwargs: Any) -> None: + """Turn the siren on.""" + self._send_command([{"code": self.entity_description.key, "value": True}]) + + def turn_off(self, **kwargs: Any) -> None: + """Turn the siren off.""" + self._send_command([{"code": self.entity_description.key, "value": False}]) diff --git a/homeassistant/components/tuya/switch.py b/homeassistant/components/tuya/switch.py index e00fea62c7a79b..a828b6c6936358 100644 --- a/homeassistant/components/tuya/switch.py +++ b/homeassistant/components/tuya/switch.py @@ -11,6 +11,7 @@ SwitchEntityDescription, ) from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ENTITY_CATEGORY_CONFIG from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -237,6 +238,15 @@ device_class=DEVICE_CLASS_OUTLET, ), ), + # Siren Alarm + # https://developer.tuya.com/en/docs/iot/categorysgbj?id=Kaiuz37tlpbnu + "sgbj": ( + SwitchEntityDescription( + key=DPCode.MUFFLING, + name="Muffling", + entity_category=ENTITY_CATEGORY_CONFIG, + ), + ), # Diffuser "xxj": ( SwitchEntityDescription(