Home Assistant Unofficial Reference 2024.12.1
alarm_control_panel.py
Go to the documentation of this file.
1 """Support for Tuya Alarm."""
2 
3 from __future__ import annotations
4 
5 from enum import StrEnum
6 
7 from tuya_sharing import CustomerDevice, Manager
8 
10  AlarmControlPanelEntity,
11  AlarmControlPanelEntityDescription,
12  AlarmControlPanelEntityFeature,
13  AlarmControlPanelState,
14 )
15 from homeassistant.core import HomeAssistant, callback
16 from homeassistant.helpers.dispatcher import async_dispatcher_connect
17 from homeassistant.helpers.entity_platform import AddEntitiesCallback
18 
19 from . import TuyaConfigEntry
20 from .const import TUYA_DISCOVERY_NEW, DPCode, DPType
21 from .entity import TuyaEntity
22 
23 
24 class Mode(StrEnum):
25  """Alarm modes."""
26 
27  ARM = "arm"
28  DISARMED = "disarmed"
29  HOME = "home"
30  SOS = "sos"
31 
32 
33 STATE_MAPPING: dict[str, AlarmControlPanelState] = {
34  Mode.DISARMED: AlarmControlPanelState.DISARMED,
35  Mode.ARM: AlarmControlPanelState.ARMED_AWAY,
36  Mode.HOME: AlarmControlPanelState.ARMED_HOME,
37  Mode.SOS: AlarmControlPanelState.TRIGGERED,
38 }
39 
40 
41 # All descriptions can be found here:
42 # https://developer.tuya.com/en/docs/iot/standarddescription?id=K9i5ql6waswzq
43 ALARM: dict[str, tuple[AlarmControlPanelEntityDescription, ...]] = {
44  # Alarm Host
45  # https://developer.tuya.com/en/docs/iot/categorymal?id=Kaiuz33clqxaf
46  "mal": (
48  key=DPCode.MASTER_MODE,
49  name="Alarm",
50  ),
51  )
52 }
53 
54 
56  hass: HomeAssistant, entry: TuyaConfigEntry, async_add_entities: AddEntitiesCallback
57 ) -> None:
58  """Set up Tuya alarm dynamically through Tuya discovery."""
59  hass_data = entry.runtime_data
60 
61  @callback
62  def async_discover_device(device_ids: list[str]) -> None:
63  """Discover and add a discovered Tuya siren."""
64  entities: list[TuyaAlarmEntity] = []
65  for device_id in device_ids:
66  device = hass_data.manager.device_map[device_id]
67  if descriptions := ALARM.get(device.category):
68  entities.extend(
69  TuyaAlarmEntity(device, hass_data.manager, description)
70  for description in descriptions
71  if description.key in device.status
72  )
73  async_add_entities(entities)
74 
75  async_discover_device([*hass_data.manager.device_map])
76 
77  entry.async_on_unload(
78  async_dispatcher_connect(hass, TUYA_DISCOVERY_NEW, async_discover_device)
79  )
80 
81 
83  """Tuya Alarm Entity."""
84 
85  _attr_name = None
86  _attr_code_arm_required = False
87 
88  def __init__(
89  self,
90  device: CustomerDevice,
91  device_manager: Manager,
92  description: AlarmControlPanelEntityDescription,
93  ) -> None:
94  """Init Tuya Alarm."""
95  super().__init__(device, device_manager)
96  self.entity_descriptionentity_description = description
97  self._attr_unique_id_attr_unique_id_attr_unique_id = f"{super().unique_id}{description.key}"
98 
99  # Determine supported modes
100  if supported_modes := self.find_dpcodefind_dpcodefind_dpcodefind_dpcodefind_dpcode(
101  description.key, dptype=DPType.ENUM, prefer_function=True
102  ):
103  if Mode.HOME in supported_modes.range:
104  self._attr_supported_features |= AlarmControlPanelEntityFeature.ARM_HOME
105 
106  if Mode.ARM in supported_modes.range:
107  self._attr_supported_features |= AlarmControlPanelEntityFeature.ARM_AWAY
108 
109  if Mode.SOS in supported_modes.range:
110  self._attr_supported_features |= AlarmControlPanelEntityFeature.TRIGGER
111 
112  @property
113  def alarm_state(self) -> AlarmControlPanelState | None:
114  """Return the state of the device."""
115  if not (status := self.devicedevice.status.get(self.entity_descriptionentity_description.key)):
116  return None
117  return STATE_MAPPING.get(status)
118 
119  def alarm_disarm(self, code: str | None = None) -> None:
120  """Send Disarm command."""
121  self._send_command_send_command(
122  [{"code": self.entity_descriptionentity_description.key, "value": Mode.DISARMED}]
123  )
124 
125  def alarm_arm_home(self, code: str | None = None) -> None:
126  """Send Home command."""
127  self._send_command_send_command([{"code": self.entity_descriptionentity_description.key, "value": Mode.HOME}])
128 
129  def alarm_arm_away(self, code: str | None = None) -> None:
130  """Send Arm command."""
131  self._send_command_send_command([{"code": self.entity_descriptionentity_description.key, "value": Mode.ARM}])
132 
133  def alarm_trigger(self, code: str | None = None) -> None:
134  """Send SOS command."""
135  self._send_command_send_command([{"code": self.entity_descriptionentity_description.key, "value": Mode.SOS}])
None __init__(self, CustomerDevice device, Manager device_manager, AlarmControlPanelEntityDescription description)
None _send_command(self, list[dict[str, Any]] commands)
Definition: entity.py:295
DPCode|EnumTypeData|IntegerTypeData|None find_dpcode(self, str|DPCode|tuple[DPCode,...]|None dpcodes, *bool prefer_function=False, DPType|None dptype=None)
Definition: entity.py:206
IntegerTypeData|None find_dpcode(self, str|DPCode|tuple[DPCode,...]|None dpcodes, *bool prefer_function=False, Literal[DPType.INTEGER] dptype)
Definition: entity.py:190
DPCode|None find_dpcode(self, str|DPCode|tuple[DPCode,...]|None dpcodes, *bool prefer_function=False)
Definition: entity.py:198
EnumTypeData|None find_dpcode(self, str|DPCode|tuple[DPCode,...]|None dpcodes, *bool prefer_function=False, Literal[DPType.ENUM] dptype)
Definition: entity.py:181
ElkSystem|None async_discover_device(HomeAssistant hass, str host)
Definition: discovery.py:78
None async_setup_entry(HomeAssistant hass, TuyaConfigEntry entry, AddEntitiesCallback async_add_entities)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103