Home Assistant Unofficial Reference 2024.12.1
alarm_control_panel.py
Go to the documentation of this file.
1 """Support for Satel Integra alarm, using ETHM module."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from collections import OrderedDict
7 import logging
8 
9 from satel_integra.satel_integra import AlarmState
10 
12  AlarmControlPanelEntity,
13  AlarmControlPanelEntityFeature,
14  AlarmControlPanelState,
15  CodeFormat,
16 )
17 from homeassistant.core import HomeAssistant, callback
18 from homeassistant.helpers.dispatcher import async_dispatcher_connect
19 from homeassistant.helpers.entity_platform import AddEntitiesCallback
20 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
21 
22 from . import (
23  CONF_ARM_HOME_MODE,
24  CONF_DEVICE_PARTITIONS,
25  CONF_ZONE_NAME,
26  DATA_SATEL,
27  SIGNAL_PANEL_MESSAGE,
28 )
29 
30 _LOGGER = logging.getLogger(__name__)
31 
32 
34  hass: HomeAssistant,
35  config: ConfigType,
36  async_add_entities: AddEntitiesCallback,
37  discovery_info: DiscoveryInfoType | None = None,
38 ) -> None:
39  """Set up for Satel Integra alarm panels."""
40  if not discovery_info:
41  return
42 
43  configured_partitions = discovery_info[CONF_DEVICE_PARTITIONS]
44  controller = hass.data[DATA_SATEL]
45 
46  devices = []
47 
48  for partition_num, device_config_data in configured_partitions.items():
49  zone_name = device_config_data[CONF_ZONE_NAME]
50  arm_home_mode = device_config_data.get(CONF_ARM_HOME_MODE)
51  device = SatelIntegraAlarmPanel(
52  controller, zone_name, arm_home_mode, partition_num
53  )
54  devices.append(device)
55 
56  async_add_entities(devices)
57 
58 
60  """Representation of an AlarmDecoder-based alarm panel."""
61 
62  _attr_code_format = CodeFormat.NUMBER
63  _attr_should_poll = False
64  _attr_supported_features = (
65  AlarmControlPanelEntityFeature.ARM_HOME
66  | AlarmControlPanelEntityFeature.ARM_AWAY
67  )
68 
69  def __init__(self, controller, name, arm_home_mode, partition_id):
70  """Initialize the alarm panel."""
71  self._attr_name_attr_name = name
72  self._arm_home_mode_arm_home_mode = arm_home_mode
73  self._partition_id_partition_id = partition_id
74  self._satel_satel = controller
75 
76  async def async_added_to_hass(self) -> None:
77  """Update alarm status and register callbacks for future updates."""
78  _LOGGER.debug("Starts listening for panel messages")
79  self._update_alarm_status_update_alarm_status()
80  self.async_on_removeasync_on_remove(
82  self.hasshass, SIGNAL_PANEL_MESSAGE, self._update_alarm_status_update_alarm_status
83  )
84  )
85 
86  @callback
88  """Handle alarm status update."""
89  state = self._read_alarm_state_read_alarm_state()
90  _LOGGER.debug("Got status update, current status: %s", state)
91  if state != self._attr_alarm_state_attr_alarm_state:
92  self._attr_alarm_state_attr_alarm_state = state
93  self.async_write_ha_stateasync_write_ha_state()
94  else:
95  _LOGGER.debug("Ignoring alarm status message, same state")
96 
97  def _read_alarm_state(self):
98  """Read current status of the alarm and translate it into HA status."""
99 
100  # Default - disarmed:
101  hass_alarm_status = AlarmControlPanelState.DISARMED
102 
103  if not self._satel_satel.connected:
104  return None
105 
106  state_map = OrderedDict(
107  [
108  (AlarmState.TRIGGERED, AlarmControlPanelState.TRIGGERED),
109  (AlarmState.TRIGGERED_FIRE, AlarmControlPanelState.TRIGGERED),
110  (AlarmState.ENTRY_TIME, AlarmControlPanelState.PENDING),
111  (AlarmState.ARMED_MODE3, AlarmControlPanelState.ARMED_HOME),
112  (AlarmState.ARMED_MODE2, AlarmControlPanelState.ARMED_HOME),
113  (AlarmState.ARMED_MODE1, AlarmControlPanelState.ARMED_HOME),
114  (AlarmState.ARMED_MODE0, AlarmControlPanelState.ARMED_AWAY),
115  (
116  AlarmState.EXIT_COUNTDOWN_OVER_10,
117  AlarmControlPanelState.PENDING,
118  ),
119  (
120  AlarmState.EXIT_COUNTDOWN_UNDER_10,
121  AlarmControlPanelState.PENDING,
122  ),
123  ]
124  )
125  _LOGGER.debug("State map of Satel: %s", self._satel_satel.partition_states)
126 
127  for satel_state, ha_state in state_map.items():
128  if (
129  satel_state in self._satel_satel.partition_states
130  and self._partition_id_partition_id in self._satel_satel.partition_states[satel_state]
131  ):
132  hass_alarm_status = ha_state
133  break
134 
135  return hass_alarm_status
136 
137  async def async_alarm_disarm(self, code: str | None = None) -> None:
138  """Send disarm command."""
139  if not code:
140  _LOGGER.debug("Code was empty or None")
141  return
142 
143  clear_alarm_necessary = (
144  self._attr_alarm_state_attr_alarm_state == AlarmControlPanelState.TRIGGERED
145  )
146 
147  _LOGGER.debug("Disarming, self._attr_alarm_state: %s", self._attr_alarm_state_attr_alarm_state)
148 
149  await self._satel_satel.disarm(code, [self._partition_id_partition_id])
150 
151  if clear_alarm_necessary:
152  # Wait 1s before clearing the alarm
153  await asyncio.sleep(1)
154  await self._satel_satel.clear_alarm(code, [self._partition_id_partition_id])
155 
156  async def async_alarm_arm_away(self, code: str | None = None) -> None:
157  """Send arm away command."""
158  _LOGGER.debug("Arming away")
159 
160  if code:
161  await self._satel_satel.arm(code, [self._partition_id_partition_id])
162 
163  async def async_alarm_arm_home(self, code: str | None = None) -> None:
164  """Send arm home command."""
165  _LOGGER.debug("Arming home")
166 
167  if code:
168  await self._satel_satel.arm(code, [self._partition_id_partition_id], self._arm_home_mode_arm_home_mode)
def __init__(self, controller, name, arm_home_mode, partition_id)
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103