mirror of
https://github.com/home-assistant/core.git
synced 2025-12-22 11:59:34 +00:00
1050 lines
33 KiB
Python
1050 lines
33 KiB
Python
"""Support for Tuya switches."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Any
|
|
|
|
from tuya_sharing import CustomerDevice, Manager
|
|
|
|
from homeassistant.components.switch import (
|
|
DOMAIN as SWITCH_DOMAIN,
|
|
SwitchDeviceClass,
|
|
SwitchEntity,
|
|
SwitchEntityDescription,
|
|
)
|
|
from homeassistant.const import EntityCategory
|
|
from homeassistant.core import HomeAssistant, callback
|
|
from homeassistant.helpers import entity_registry as er
|
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|
from homeassistant.helpers.issue_registry import (
|
|
IssueSeverity,
|
|
async_create_issue,
|
|
async_delete_issue,
|
|
)
|
|
|
|
from . import TuyaConfigEntry
|
|
from .const import DOMAIN, TUYA_DISCOVERY_NEW, DeviceCategory, DPCode
|
|
from .entity import TuyaEntity
|
|
from .models import DPCodeBooleanWrapper
|
|
|
|
|
|
@dataclass(frozen=True, kw_only=True)
|
|
class TuyaDeprecatedSwitchEntityDescription(SwitchEntityDescription):
|
|
"""Describes Tuya deprecated switch entity."""
|
|
|
|
deprecated: str
|
|
breaks_in_ha_version: str
|
|
|
|
|
|
# All descriptions can be found here. Mostly the Boolean data types in the
|
|
# default instruction set of each category end up being a Switch.
|
|
# https://developer.tuya.com/en/docs/iot/standarddescription?id=K9i5ql6waswzq
|
|
SWITCHES: dict[DeviceCategory, tuple[SwitchEntityDescription, ...]] = {
|
|
DeviceCategory.BH: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.START,
|
|
translation_key="start",
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.WARM,
|
|
translation_key="heat_preservation",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.BZYD: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
name=None,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.CHILD_LOCK,
|
|
translation_key="child_lock",
|
|
icon="mdi:account-lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_MUSIC,
|
|
translation_key="music",
|
|
icon="mdi:music",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SNOOZE,
|
|
translation_key="snooze",
|
|
icon="mdi:alarm-snooze",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.CJKG: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_1,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "1"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_2,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "2"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_3,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "3"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_4,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "4"},
|
|
),
|
|
),
|
|
DeviceCategory.CL: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.CONTROL_BACK,
|
|
translation_key="reverse",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.OPPOSITE,
|
|
translation_key="reverse",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.CN: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.DISINFECTION,
|
|
translation_key="disinfection",
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.WATER,
|
|
translation_key="water",
|
|
),
|
|
),
|
|
DeviceCategory.CS: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.ANION,
|
|
translation_key="ionizer",
|
|
icon="mdi:atom",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.CHILD_LOCK,
|
|
translation_key="child_lock",
|
|
icon="mdi:account-lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.FILTER_RESET,
|
|
translation_key="filter_reset",
|
|
icon="mdi:filter",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.CWJWQ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="switch",
|
|
),
|
|
),
|
|
DeviceCategory.CWWSQ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SLOW_FEED,
|
|
translation_key="slow_feed",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.CWYSJ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.FILTER_RESET,
|
|
translation_key="filter_reset",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.PUMP_RESET,
|
|
translation_key="water_pump_reset",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="power",
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.WATER_RESET,
|
|
translation_key="reset_of_water_usage_days",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.UV,
|
|
translation_key="uv_sterilization",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.DJ: (
|
|
# There are sockets available with an RGB light
|
|
# that advertise as `dj`, but provide an additional
|
|
# switch to control the plug.
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="plug",
|
|
),
|
|
),
|
|
DeviceCategory.DLQ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.CHILD_LOCK,
|
|
translation_key="child_lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="switch",
|
|
),
|
|
),
|
|
DeviceCategory.DR: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
name="Power",
|
|
icon="mdi:power",
|
|
device_class=SwitchDeviceClass.SWITCH,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_1,
|
|
name="Side A Power",
|
|
icon="mdi:alpha-a",
|
|
device_class=SwitchDeviceClass.SWITCH,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_2,
|
|
name="Side B Power",
|
|
icon="mdi:alpha-b",
|
|
device_class=SwitchDeviceClass.SWITCH,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.PREHEAT,
|
|
name="Preheat",
|
|
icon="mdi:radiator",
|
|
device_class=SwitchDeviceClass.SWITCH,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.PREHEAT_1,
|
|
name="Side A Preheat",
|
|
icon="mdi:radiator",
|
|
device_class=SwitchDeviceClass.SWITCH,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.PREHEAT_2,
|
|
name="Side B Preheat",
|
|
icon="mdi:radiator",
|
|
device_class=SwitchDeviceClass.SWITCH,
|
|
),
|
|
),
|
|
DeviceCategory.FS: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.ANION,
|
|
translation_key="anion",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.HUMIDIFIER,
|
|
translation_key="humidification",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.OXYGEN,
|
|
translation_key="oxygen_bar",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.FAN_COOL,
|
|
translation_key="natural_wind",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.FAN_BEEP,
|
|
translation_key="sound",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.CHILD_LOCK,
|
|
translation_key="child_lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.FSD: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.FAN_BEEP,
|
|
translation_key="sound",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.GGQ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_1,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "1"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_2,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "2"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_3,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "3"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_4,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "4"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_5,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "5"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_6,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "6"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_7,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "7"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_8,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "8"},
|
|
),
|
|
),
|
|
DeviceCategory.HXD: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_1,
|
|
translation_key="radio",
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_2,
|
|
translation_key="indexed_alarm",
|
|
translation_placeholders={"index": "1"},
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_3,
|
|
translation_key="indexed_alarm",
|
|
translation_placeholders={"index": "2"},
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_4,
|
|
translation_key="indexed_alarm",
|
|
translation_placeholders={"index": "3"},
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_5,
|
|
translation_key="indexed_alarm",
|
|
translation_placeholders={"index": "4"},
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_6,
|
|
translation_key="sleep_aid",
|
|
),
|
|
),
|
|
DeviceCategory.JSQ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_SOUND,
|
|
translation_key="voice",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SLEEP,
|
|
translation_key="sleep",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.STERILIZATION,
|
|
translation_key="sterilization",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.KG: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.CHILD_LOCK,
|
|
translation_key="child_lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_1,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "1"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_2,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "2"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_3,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "3"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_4,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "4"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_5,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "5"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_6,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "6"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_7,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "7"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_8,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "8"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_USB1,
|
|
translation_key="indexed_usb",
|
|
translation_placeholders={"index": "1"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_USB2,
|
|
translation_key="indexed_usb",
|
|
translation_placeholders={"index": "2"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_USB3,
|
|
translation_key="indexed_usb",
|
|
translation_placeholders={"index": "3"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_USB4,
|
|
translation_key="indexed_usb",
|
|
translation_placeholders={"index": "4"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_USB5,
|
|
translation_key="indexed_usb",
|
|
translation_placeholders={"index": "5"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_USB6,
|
|
translation_key="indexed_usb",
|
|
translation_placeholders={"index": "6"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="switch",
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
),
|
|
DeviceCategory.KJ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.ANION,
|
|
translation_key="ionizer",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.FILTER_RESET,
|
|
translation_key="filter_cartridge_reset",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.LOCK,
|
|
translation_key="child_lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="power",
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.WET,
|
|
translation_key="humidification",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.UV,
|
|
translation_key="uv_sterilization",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.KT: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.ANION,
|
|
translation_key="ionizer",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.LOCK,
|
|
translation_key="child_lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.KS: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.ANION,
|
|
translation_key="ionizer",
|
|
),
|
|
),
|
|
DeviceCategory.MAL: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_ALARM_SOUND,
|
|
# This switch is called "Arm Beep" in the official Tuya app
|
|
translation_key="arm_beep",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_ALARM_LIGHT,
|
|
# This switch is called "Siren" in the official Tuya app
|
|
translation_key="siren",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.MSP: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.AUTO_CLEAN,
|
|
translation_key="auto_clean",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.MZJ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="switch",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.START,
|
|
translation_key="start",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.PC: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.CHILD_LOCK,
|
|
translation_key="child_lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_1,
|
|
translation_key="indexed_socket",
|
|
translation_placeholders={"index": "1"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_2,
|
|
translation_key="indexed_socket",
|
|
translation_placeholders={"index": "2"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_3,
|
|
translation_key="indexed_socket",
|
|
translation_placeholders={"index": "3"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_4,
|
|
translation_key="indexed_socket",
|
|
translation_placeholders={"index": "4"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_5,
|
|
translation_key="indexed_socket",
|
|
translation_placeholders={"index": "5"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_6,
|
|
translation_key="indexed_socket",
|
|
translation_placeholders={"index": "6"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_USB1,
|
|
translation_key="indexed_usb",
|
|
translation_placeholders={"index": "1"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_USB2,
|
|
translation_key="indexed_usb",
|
|
translation_placeholders={"index": "2"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_USB3,
|
|
translation_key="indexed_usb",
|
|
translation_placeholders={"index": "3"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_USB4,
|
|
translation_key="indexed_usb",
|
|
translation_placeholders={"index": "4"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_USB5,
|
|
translation_key="indexed_usb",
|
|
translation_placeholders={"index": "5"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_USB6,
|
|
translation_key="indexed_usb",
|
|
translation_placeholders={"index": "6"},
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="socket",
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
),
|
|
DeviceCategory.QCCDZ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="switch",
|
|
),
|
|
),
|
|
DeviceCategory.QJDCZ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_1,
|
|
translation_key="switch",
|
|
),
|
|
),
|
|
DeviceCategory.QN: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.ANION,
|
|
translation_key="ionizer",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.LOCK,
|
|
translation_key="child_lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.QXJ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="switch",
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
),
|
|
DeviceCategory.SD: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_DISTURB,
|
|
translation_key="do_not_disturb",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.VOICE_SWITCH,
|
|
translation_key="mute_voice",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.SFKZQ: (
|
|
TuyaDeprecatedSwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="switch",
|
|
deprecated="deprecated_entity_new_valve",
|
|
breaks_in_ha_version="2026.4.0",
|
|
),
|
|
),
|
|
DeviceCategory.SGBJ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.MUFFLING,
|
|
translation_key="mute",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.SJZ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.CHILD_LOCK,
|
|
translation_key="child_lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.SP: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.WIRELESS_BATTERYLOCK,
|
|
translation_key="battery_lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.CRY_DETECTION_SWITCH,
|
|
translation_key="cry_detection",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.DECIBEL_SWITCH,
|
|
translation_key="sound_detection",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.RECORD_SWITCH,
|
|
translation_key="video_recording",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.MOTION_RECORD,
|
|
translation_key="motion_recording",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.BASIC_PRIVATE,
|
|
translation_key="privacy_mode",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.BASIC_FLIP,
|
|
translation_key="flip",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.BASIC_OSD,
|
|
translation_key="time_watermark",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.BASIC_WDR,
|
|
translation_key="wide_dynamic_range",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.MOTION_TRACKING,
|
|
translation_key="motion_tracking",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.MOTION_SWITCH,
|
|
translation_key="motion_alarm",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.SZ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="power",
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.PUMP,
|
|
translation_key="pump",
|
|
),
|
|
),
|
|
DeviceCategory.SZJQR: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="switch",
|
|
),
|
|
),
|
|
DeviceCategory.TDQ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_1,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "1"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_2,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "2"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_3,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "3"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_4,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "4"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_5,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "5"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_6,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "6"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.CHILD_LOCK,
|
|
translation_key="child_lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.TYNDJ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_SAVE_ENERGY,
|
|
translation_key="energy_saving",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.WG2: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.MUFFLING,
|
|
translation_key="mute",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.WK: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.CHILD_LOCK,
|
|
translation_key="child_lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.FROST,
|
|
translation_key="frost_protection",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.WKCZ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_1,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "1"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_2,
|
|
translation_key="indexed_switch",
|
|
translation_placeholders={"index": "2"},
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
),
|
|
DeviceCategory.WKF: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.CHILD_LOCK,
|
|
translation_key="child_lock",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.WINDOW_CHECK,
|
|
translation_key="open_window_detection",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.WNYKQ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
name=None,
|
|
),
|
|
),
|
|
DeviceCategory.WSDCG: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="switch",
|
|
device_class=SwitchDeviceClass.OUTLET,
|
|
),
|
|
),
|
|
DeviceCategory.XDD: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.DO_NOT_DISTURB,
|
|
translation_key="do_not_disturb",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.XNYJCN: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.FEEDIN_POWER_LIMIT_ENABLE,
|
|
translation_key="output_power_limit",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.XXJ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="power",
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_SPRAY,
|
|
translation_key="spray",
|
|
),
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH_VOICE,
|
|
translation_key="voice",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.YWBJ: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.MUFFLING,
|
|
translation_key="mute",
|
|
entity_category=EntityCategory.CONFIG,
|
|
),
|
|
),
|
|
DeviceCategory.ZNDB: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="switch",
|
|
),
|
|
),
|
|
DeviceCategory.ZNJXS: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="switch",
|
|
),
|
|
),
|
|
DeviceCategory.ZNRB: (
|
|
SwitchEntityDescription(
|
|
key=DPCode.SWITCH,
|
|
translation_key="switch",
|
|
),
|
|
),
|
|
}
|
|
|
|
# Socket (duplicate of `pc`)
|
|
SWITCHES[DeviceCategory.CZ] = SWITCHES[DeviceCategory.PC]
|
|
|
|
# Smart Camera - Low power consumption camera (duplicate of `sp`)
|
|
SWITCHES[DeviceCategory.DGHSXJ] = SWITCHES[DeviceCategory.SP]
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
entry: TuyaConfigEntry,
|
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
) -> None:
|
|
"""Set up tuya sensors dynamically through tuya discovery."""
|
|
manager = entry.runtime_data.manager
|
|
entity_registry = er.async_get(hass)
|
|
|
|
@callback
|
|
def async_discover_device(device_ids: list[str]) -> None:
|
|
"""Discover and add a discovered tuya sensor."""
|
|
entities: list[TuyaSwitchEntity] = []
|
|
for device_id in device_ids:
|
|
device = manager.device_map[device_id]
|
|
if descriptions := SWITCHES.get(device.category):
|
|
entities.extend(
|
|
TuyaSwitchEntity(device, manager, description, dpcode_wrapper)
|
|
for description in descriptions
|
|
if (
|
|
dpcode_wrapper := DPCodeBooleanWrapper.find_dpcode(
|
|
device, description.key, prefer_function=True
|
|
)
|
|
)
|
|
and _check_deprecation(
|
|
hass,
|
|
device,
|
|
description,
|
|
entity_registry,
|
|
)
|
|
)
|
|
|
|
async_add_entities(entities)
|
|
|
|
async_discover_device([*manager.device_map])
|
|
|
|
entry.async_on_unload(
|
|
async_dispatcher_connect(hass, TUYA_DISCOVERY_NEW, async_discover_device)
|
|
)
|
|
|
|
|
|
def _check_deprecation(
|
|
hass: HomeAssistant,
|
|
device: CustomerDevice,
|
|
description: SwitchEntityDescription,
|
|
entity_registry: er.EntityRegistry,
|
|
) -> bool:
|
|
"""Check entity deprecation.
|
|
|
|
Returns:
|
|
`True` if the entity should be created, `False` otherwise.
|
|
"""
|
|
# Not deprecated, just create it
|
|
if not isinstance(description, TuyaDeprecatedSwitchEntityDescription):
|
|
return True
|
|
|
|
unique_id = f"tuya.{device.id}{description.key}"
|
|
entity_id = entity_registry.async_get_entity_id(SWITCH_DOMAIN, DOMAIN, unique_id)
|
|
|
|
# Deprecated and not present in registry, skip creation
|
|
if not entity_id or not (entity_entry := entity_registry.async_get(entity_id)):
|
|
return False
|
|
|
|
# Deprecated and present in registry but disabled, remove it and skip creation
|
|
if entity_entry.disabled:
|
|
entity_registry.async_remove(entity_id)
|
|
async_delete_issue(
|
|
hass,
|
|
DOMAIN,
|
|
f"deprecated_entity_{unique_id}",
|
|
)
|
|
return False
|
|
|
|
# Deprecated and present in registry and enabled, raise issue and create it
|
|
async_create_issue(
|
|
hass,
|
|
DOMAIN,
|
|
f"deprecated_entity_{unique_id}",
|
|
breaks_in_ha_version=description.breaks_in_ha_version,
|
|
is_fixable=False,
|
|
severity=IssueSeverity.WARNING,
|
|
translation_key=description.deprecated,
|
|
translation_placeholders={
|
|
"name": f"{device.name} {entity_entry.name or entity_entry.original_name}",
|
|
"entity": entity_id,
|
|
},
|
|
)
|
|
return True
|
|
|
|
|
|
class TuyaSwitchEntity(TuyaEntity, SwitchEntity):
|
|
"""Tuya Switch Device."""
|
|
|
|
def __init__(
|
|
self,
|
|
device: CustomerDevice,
|
|
device_manager: Manager,
|
|
description: SwitchEntityDescription,
|
|
dpcode_wrapper: DPCodeBooleanWrapper,
|
|
) -> None:
|
|
"""Init TuyaHaSwitch."""
|
|
super().__init__(device, device_manager)
|
|
self.entity_description = description
|
|
self._attr_unique_id = f"{super().unique_id}{description.key}"
|
|
self._dpcode_wrapper = dpcode_wrapper
|
|
|
|
@property
|
|
def is_on(self) -> bool | None:
|
|
"""Return true if switch is on."""
|
|
return self._read_wrapper(self._dpcode_wrapper)
|
|
|
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
|
"""Turn the switch on."""
|
|
await self._async_send_wrapper_updates(self._dpcode_wrapper, True)
|
|
|
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
|
"""Turn the switch off."""
|
|
await self._async_send_wrapper_updates(self._dpcode_wrapper, False)
|