From 553d420db91690d99847418ab16a23cc77843e27 Mon Sep 17 00:00:00 2001 From: Markus Lanthaler Date: Fri, 23 May 2025 08:42:09 +0200 Subject: [PATCH] Add support for Tuya Wireless Switch entity (#123284) Add support for Tuya Wireless Switch entity --- homeassistant/components/tuya/const.py | 10 ++ homeassistant/components/tuya/event.py | 147 +++++++++++++++++++++ homeassistant/components/tuya/sensor.py | 3 + homeassistant/components/tuya/strings.json | 14 ++ 4 files changed, 174 insertions(+) create mode 100644 homeassistant/components/tuya/event.py diff --git a/homeassistant/components/tuya/const.py b/homeassistant/components/tuya/const.py index a40260ed787..518e49f2636 100644 --- a/homeassistant/components/tuya/const.py +++ b/homeassistant/components/tuya/const.py @@ -56,6 +56,7 @@ PLATFORMS = [ Platform.CAMERA, Platform.CLIMATE, Platform.COVER, + Platform.EVENT, Platform.FAN, Platform.HUMIDIFIER, Platform.LIGHT, @@ -314,6 +315,15 @@ class DPCode(StrEnum): SWITCH_LED_1 = "switch_led_1" SWITCH_LED_2 = "switch_led_2" SWITCH_LED_3 = "switch_led_3" + SWITCH_MODE1 = "switch_mode1" + SWITCH_MODE2 = "switch_mode2" + SWITCH_MODE3 = "switch_mode3" + SWITCH_MODE4 = "switch_mode4" + SWITCH_MODE5 = "switch_mode5" + SWITCH_MODE6 = "switch_mode6" + SWITCH_MODE7 = "switch_mode7" + SWITCH_MODE8 = "switch_mode8" + SWITCH_MODE9 = "switch_mode9" SWITCH_NIGHT_LIGHT = "switch_night_light" SWITCH_SAVE_ENERGY = "switch_save_energy" SWITCH_SOUND = "switch_sound" # Voice switch diff --git a/homeassistant/components/tuya/event.py b/homeassistant/components/tuya/event.py new file mode 100644 index 00000000000..09ab8e8f544 --- /dev/null +++ b/homeassistant/components/tuya/event.py @@ -0,0 +1,147 @@ +"""Support for Tuya event entities.""" + +from __future__ import annotations + +from tuya_sharing import CustomerDevice, Manager + +from homeassistant.components.event import ( + EventDeviceClass, + EventEntity, + EventEntityDescription, +) +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback + +from . import TuyaConfigEntry +from .const import TUYA_DISCOVERY_NEW, DPCode, DPType +from .entity import TuyaEntity + +# All descriptions can be found here. Mostly the Enum data types in the +# default status set of each category (that don't have a set instruction) +# end up being events. +# https://developer.tuya.com/en/docs/iot/standarddescription?id=K9i5ql6waswzq +EVENTS: dict[str, tuple[EventEntityDescription, ...]] = { + # Wireless Switch + # https://developer.tuya.com/en/docs/iot/s?id=Kbeoa9fkv6brp + "wxkg": ( + EventEntityDescription( + key=DPCode.SWITCH_MODE1, + device_class=EventDeviceClass.BUTTON, + translation_key="numbered_button", + translation_placeholders={"button_number": "1"}, + ), + EventEntityDescription( + key=DPCode.SWITCH_MODE2, + device_class=EventDeviceClass.BUTTON, + translation_key="numbered_button", + translation_placeholders={"button_number": "2"}, + ), + EventEntityDescription( + key=DPCode.SWITCH_MODE3, + device_class=EventDeviceClass.BUTTON, + translation_key="numbered_button", + translation_placeholders={"button_number": "3"}, + ), + EventEntityDescription( + key=DPCode.SWITCH_MODE4, + device_class=EventDeviceClass.BUTTON, + translation_key="numbered_button", + translation_placeholders={"button_number": "4"}, + ), + EventEntityDescription( + key=DPCode.SWITCH_MODE5, + device_class=EventDeviceClass.BUTTON, + translation_key="numbered_button", + translation_placeholders={"button_number": "5"}, + ), + EventEntityDescription( + key=DPCode.SWITCH_MODE6, + device_class=EventDeviceClass.BUTTON, + translation_key="numbered_button", + translation_placeholders={"button_number": "6"}, + ), + EventEntityDescription( + key=DPCode.SWITCH_MODE7, + device_class=EventDeviceClass.BUTTON, + translation_key="numbered_button", + translation_placeholders={"button_number": "7"}, + ), + EventEntityDescription( + key=DPCode.SWITCH_MODE8, + device_class=EventDeviceClass.BUTTON, + translation_key="numbered_button", + translation_placeholders={"button_number": "8"}, + ), + EventEntityDescription( + key=DPCode.SWITCH_MODE9, + device_class=EventDeviceClass.BUTTON, + translation_key="numbered_button", + translation_placeholders={"button_number": "9"}, + ), + ) +} + + +async def async_setup_entry( + hass: HomeAssistant, + entry: TuyaConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up Tuya events dynamically through Tuya discovery.""" + hass_data = entry.runtime_data + + @callback + def async_discover_device(device_ids: list[str]) -> None: + """Discover and add a discovered Tuya binary sensor.""" + entities: list[TuyaEventEntity] = [] + for device_id in device_ids: + device = hass_data.manager.device_map[device_id] + if descriptions := EVENTS.get(device.category): + for description in descriptions: + dpcode = description.key + if dpcode in device.status: + entities.append( + TuyaEventEntity(device, hass_data.manager, description) + ) + + async_add_entities(entities) + + async_discover_device([*hass_data.manager.device_map]) + + entry.async_on_unload( + async_dispatcher_connect(hass, TUYA_DISCOVERY_NEW, async_discover_device) + ) + + +class TuyaEventEntity(TuyaEntity, EventEntity): + """Tuya Event Entity.""" + + entity_description: EventEntityDescription + + def __init__( + self, + device: CustomerDevice, + device_manager: Manager, + description: EventEntityDescription, + ) -> None: + """Init Tuya event entity.""" + super().__init__(device, device_manager) + self.entity_description = description + self._attr_unique_id = f"{super().unique_id}{description.key}" + + if dpcode := self.find_dpcode(description.key, dptype=DPType.ENUM): + self._attr_event_types: list[str] = dpcode.range + + async def _handle_state_update( + self, updated_status_properties: list[str] | None + ) -> None: + if ( + updated_status_properties is None + or self.entity_description.key not in updated_status_properties + ): + return + + value = self.device.status.get(self.entity_description.key) + self._trigger_event(value) + self.async_write_ha_state() diff --git a/homeassistant/components/tuya/sensor.py b/homeassistant/components/tuya/sensor.py index 9e40bda5d4d..d9be940bddd 100644 --- a/homeassistant/components/tuya/sensor.py +++ b/homeassistant/components/tuya/sensor.py @@ -1281,6 +1281,9 @@ SENSORS: dict[str, tuple[TuyaSensorEntityDescription, ...]] = { state_class=SensorStateClass.MEASUREMENT, ), ), + # Wireless Switch + # https://developer.tuya.com/en/docs/iot/s?id=Kbeoa9fkv6brp + "wxkg": BATTERY_SENSORS, } # Socket (duplicate of `kg`) diff --git a/homeassistant/components/tuya/strings.json b/homeassistant/components/tuya/strings.json index c6f6bfe9776..fc27aa65ce5 100644 --- a/homeassistant/components/tuya/strings.json +++ b/homeassistant/components/tuya/strings.json @@ -101,6 +101,20 @@ "name": "Door 3" } }, + "event": { + "numbered_button": { + "name": "Button {button_number}", + "state_attributes": { + "event_type": { + "state": { + "click": "Clicked", + "double_click": "Double-clicked", + "press": "Long-pressed" + } + } + } + } + }, "light": { "backlight": { "name": "Backlight"