Home Assistant Unofficial Reference 2024.12.1
alarm_control_panel.py
Go to the documentation of this file.
1 """Support for SimpliSafe alarm control panels."""
2 
3 from __future__ import annotations
4 
5 from simplipy.errors import SimplipyError
6 from simplipy.system import SystemStates
7 from simplipy.system.v3 import SystemV3
8 from simplipy.websocket import (
9  EVENT_ALARM_CANCELED,
10  EVENT_ALARM_TRIGGERED,
11  EVENT_ARMED_AWAY,
12  EVENT_ARMED_AWAY_BY_KEYPAD,
13  EVENT_ARMED_AWAY_BY_REMOTE,
14  EVENT_ARMED_HOME,
15  EVENT_AWAY_EXIT_DELAY_BY_KEYPAD,
16  EVENT_AWAY_EXIT_DELAY_BY_REMOTE,
17  EVENT_DISARMED_BY_KEYPAD,
18  EVENT_DISARMED_BY_REMOTE,
19  EVENT_ENTRY_DELAY,
20  EVENT_HOME_EXIT_DELAY,
21  EVENT_SECRET_ALERT_TRIGGERED,
22  EVENT_USER_INITIATED_TEST,
23  WebsocketEvent,
24 )
25 
27  AlarmControlPanelEntity,
28  AlarmControlPanelEntityFeature,
29  AlarmControlPanelState,
30 )
31 from homeassistant.config_entries import ConfigEntry
32 from homeassistant.core import HomeAssistant, callback
33 from homeassistant.exceptions import HomeAssistantError
34 from homeassistant.helpers.entity_platform import AddEntitiesCallback
35 
36 from . import SimpliSafe
37 from .const import (
38  ATTR_ALARM_DURATION,
39  ATTR_ALARM_VOLUME,
40  ATTR_CHIME_VOLUME,
41  ATTR_ENTRY_DELAY_AWAY,
42  ATTR_ENTRY_DELAY_HOME,
43  ATTR_EXIT_DELAY_AWAY,
44  ATTR_EXIT_DELAY_HOME,
45  ATTR_LIGHT,
46  ATTR_VOICE_PROMPT_VOLUME,
47  DOMAIN,
48  LOGGER,
49 )
50 from .entity import SimpliSafeEntity
51 from .typing import SystemType
52 
53 ATTR_BATTERY_BACKUP_POWER_LEVEL = "battery_backup_power_level"
54 ATTR_GSM_STRENGTH = "gsm_strength"
55 ATTR_PIN_NAME = "pin_name"
56 ATTR_RF_JAMMING = "rf_jamming"
57 ATTR_WALL_POWER_LEVEL = "wall_power_level"
58 ATTR_WIFI_STRENGTH = "wifi_strength"
59 
60 STATE_MAP_FROM_REST_API = {
61  SystemStates.ALARM: AlarmControlPanelState.TRIGGERED,
62  SystemStates.ALARM_COUNT: AlarmControlPanelState.PENDING,
63  SystemStates.AWAY: AlarmControlPanelState.ARMED_AWAY,
64  SystemStates.AWAY_COUNT: AlarmControlPanelState.ARMING,
65  SystemStates.ENTRY_DELAY: AlarmControlPanelState.PENDING,
66  SystemStates.EXIT_DELAY: AlarmControlPanelState.ARMING,
67  SystemStates.HOME: AlarmControlPanelState.ARMED_HOME,
68  SystemStates.HOME_COUNT: AlarmControlPanelState.ARMING,
69  SystemStates.OFF: AlarmControlPanelState.DISARMED,
70  SystemStates.TEST: AlarmControlPanelState.DISARMED,
71 }
72 
73 STATE_MAP_FROM_WEBSOCKET_EVENT = {
74  EVENT_ALARM_CANCELED: AlarmControlPanelState.DISARMED,
75  EVENT_ALARM_TRIGGERED: AlarmControlPanelState.TRIGGERED,
76  EVENT_ARMED_AWAY: AlarmControlPanelState.ARMED_AWAY,
77  EVENT_ARMED_AWAY_BY_KEYPAD: AlarmControlPanelState.ARMED_AWAY,
78  EVENT_ARMED_AWAY_BY_REMOTE: AlarmControlPanelState.ARMED_AWAY,
79  EVENT_ARMED_HOME: AlarmControlPanelState.ARMED_HOME,
80  EVENT_AWAY_EXIT_DELAY_BY_KEYPAD: AlarmControlPanelState.ARMING,
81  EVENT_AWAY_EXIT_DELAY_BY_REMOTE: AlarmControlPanelState.ARMING,
82  EVENT_DISARMED_BY_KEYPAD: AlarmControlPanelState.DISARMED,
83  EVENT_DISARMED_BY_REMOTE: AlarmControlPanelState.DISARMED,
84  EVENT_ENTRY_DELAY: AlarmControlPanelState.PENDING,
85  EVENT_HOME_EXIT_DELAY: AlarmControlPanelState.ARMING,
86  EVENT_SECRET_ALERT_TRIGGERED: AlarmControlPanelState.TRIGGERED,
87  EVENT_USER_INITIATED_TEST: AlarmControlPanelState.DISARMED,
88 }
89 
90 WEBSOCKET_EVENTS_TO_LISTEN_FOR = (
91  EVENT_ALARM_CANCELED,
92  EVENT_ALARM_TRIGGERED,
93  EVENT_ARMED_AWAY,
94  EVENT_ARMED_AWAY_BY_KEYPAD,
95  EVENT_ARMED_AWAY_BY_REMOTE,
96  EVENT_ARMED_HOME,
97  EVENT_AWAY_EXIT_DELAY_BY_KEYPAD,
98  EVENT_AWAY_EXIT_DELAY_BY_REMOTE,
99  EVENT_DISARMED_BY_KEYPAD,
100  EVENT_DISARMED_BY_REMOTE,
101  EVENT_HOME_EXIT_DELAY,
102 )
103 
104 
106  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
107 ) -> None:
108  """Set up a SimpliSafe alarm control panel based on a config entry."""
109  simplisafe = hass.data[DOMAIN][entry.entry_id]
111  [SimpliSafeAlarm(simplisafe, system) for system in simplisafe.systems.values()],
112  True,
113  )
114 
115 
117  """Representation of a SimpliSafe alarm."""
118 
119  _attr_code_arm_required = False
120  _attr_name = None
121  _attr_supported_features = (
122  AlarmControlPanelEntityFeature.ARM_HOME
123  | AlarmControlPanelEntityFeature.ARM_AWAY
124  )
125 
126  def __init__(self, simplisafe: SimpliSafe, system: SystemType) -> None:
127  """Initialize the SimpliSafe alarm."""
128  super().__init__(
129  simplisafe,
130  system,
131  additional_websocket_events=WEBSOCKET_EVENTS_TO_LISTEN_FOR,
132  )
133 
134  self._last_event_last_event = None
135  self._set_state_from_system_data_set_state_from_system_data()
136 
137  @callback
138  def _set_state_from_system_data(self) -> None:
139  """Set the state based on the latest REST API data."""
140  if self._system_system.alarm_going_off:
141  self._attr_alarm_state_attr_alarm_state = AlarmControlPanelState.TRIGGERED
142  elif state := STATE_MAP_FROM_REST_API.get(self._system_system.state):
143  self._attr_alarm_state_attr_alarm_state = state
144  self.async_reset_error_countasync_reset_error_count()
145  else:
146  LOGGER.warning("Unexpected system state (REST API): %s", self._system_system.state)
147  self.async_increment_error_countasync_increment_error_count()
148 
149  async def async_alarm_disarm(self, code: str | None = None) -> None:
150  """Send disarm command."""
151  try:
152  await self._system_system.async_set_off()
153  except SimplipyError as err:
154  raise HomeAssistantError(
155  f'Error while disarming "{self._system.system_id}": {err}'
156  ) from err
157 
158  self._attr_alarm_state_attr_alarm_state = AlarmControlPanelState.DISARMED
159  self.async_write_ha_stateasync_write_ha_state()
160 
161  async def async_alarm_arm_home(self, code: str | None = None) -> None:
162  """Send arm home command."""
163  try:
164  await self._system_system.async_set_home()
165  except SimplipyError as err:
166  raise HomeAssistantError(
167  f'Error while arming (home) "{self._system.system_id}": {err}'
168  ) from err
169 
170  self._attr_alarm_state_attr_alarm_state = AlarmControlPanelState.ARMED_HOME
171  self.async_write_ha_stateasync_write_ha_state()
172 
173  async def async_alarm_arm_away(self, code: str | None = None) -> None:
174  """Send arm away command."""
175  try:
176  await self._system_system.async_set_away()
177  except SimplipyError as err:
178  raise HomeAssistantError(
179  f'Error while arming (away) "{self._system.system_id}": {err}'
180  ) from err
181 
182  self._attr_alarm_state_attr_alarm_state = AlarmControlPanelState.ARMING
183  self.async_write_ha_stateasync_write_ha_state()
184 
185  @callback
186  def async_update_from_rest_api(self) -> None:
187  """Update the entity with the provided REST API data."""
188  if isinstance(self._system_system, SystemV3):
189  self._attr_extra_state_attributes_attr_extra_state_attributes.update(
190  {
191  ATTR_ALARM_DURATION: self._system_system.alarm_duration,
192  ATTR_BATTERY_BACKUP_POWER_LEVEL: (
193  self._system_system.battery_backup_power_level
194  ),
195  ATTR_ENTRY_DELAY_AWAY: self._system_system.entry_delay_away,
196  ATTR_ENTRY_DELAY_HOME: self._system_system.entry_delay_home,
197  ATTR_EXIT_DELAY_AWAY: self._system_system.exit_delay_away,
198  ATTR_EXIT_DELAY_HOME: self._system_system.exit_delay_home,
199  ATTR_GSM_STRENGTH: self._system_system.gsm_strength,
200  ATTR_LIGHT: self._system_system.light,
201  ATTR_RF_JAMMING: self._system_system.rf_jamming,
202  ATTR_WALL_POWER_LEVEL: self._system_system.wall_power_level,
203  ATTR_WIFI_STRENGTH: self._system_system.wifi_strength,
204  }
205  )
206 
207  for key, volume_prop in (
208  (ATTR_ALARM_VOLUME, self._system_system.alarm_volume),
209  (ATTR_CHIME_VOLUME, self._system_system.chime_volume),
210  (ATTR_VOICE_PROMPT_VOLUME, self._system_system.voice_prompt_volume),
211  ):
212  if not volume_prop:
213  continue
214  self._attr_extra_state_attributes_attr_extra_state_attributes[key] = volume_prop.name.lower()
215 
216  self._set_state_from_system_data_set_state_from_system_data()
217 
218  @callback
219  def async_update_from_websocket_event(self, event: WebsocketEvent) -> None:
220  """Update the entity when new data comes from the websocket."""
221  self._attr_changed_by_attr_changed_by = event.changed_by
222 
223  assert event.event_type
224 
225  if state := STATE_MAP_FROM_WEBSOCKET_EVENT.get(event.event_type):
226  self._attr_alarm_state_attr_alarm_state = state
227  self.async_reset_error_countasync_reset_error_count()
228  else:
229  LOGGER.error("Unknown alarm websocket event: %s", event.event_type)
230  self.async_increment_error_countasync_increment_error_count()
None __init__(self, SimpliSafe simplisafe, SystemType system)
IssData update(pyiss.ISS iss)
Definition: __init__.py:33
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)