1 """Class to hold all alarm control panel accessories."""
6 from pyhap.const
import CATEGORY_ALARM_SYSTEM
9 DOMAIN
as ALARM_CONTROL_PANEL_DOMAIN,
10 AlarmControlPanelEntityFeature,
11 AlarmControlPanelState,
16 ATTR_SUPPORTED_FEATURES,
17 SERVICE_ALARM_ARM_AWAY,
18 SERVICE_ALARM_ARM_HOME,
19 SERVICE_ALARM_ARM_NIGHT,
26 from .accessories
import TYPES, HomeAccessory
28 CHAR_CURRENT_SECURITY_STATE,
29 CHAR_TARGET_SECURITY_STATE,
33 _LOGGER = logging.getLogger(__name__)
35 HK_ALARM_STAY_ARMED = 0
36 HK_ALARM_AWAY_ARMED = 1
37 HK_ALARM_NIGHT_ARMED = 2
39 HK_ALARM_TRIGGERED = 4
41 HASS_TO_HOMEKIT_CURRENT = {
42 AlarmControlPanelState.ARMED_HOME: HK_ALARM_STAY_ARMED,
43 AlarmControlPanelState.ARMED_VACATION: HK_ALARM_AWAY_ARMED,
44 AlarmControlPanelState.ARMED_AWAY: HK_ALARM_AWAY_ARMED,
45 AlarmControlPanelState.ARMED_NIGHT: HK_ALARM_NIGHT_ARMED,
46 AlarmControlPanelState.ARMING: HK_ALARM_DISARMED,
47 AlarmControlPanelState.DISARMED: HK_ALARM_DISARMED,
48 AlarmControlPanelState.TRIGGERED: HK_ALARM_TRIGGERED,
51 HASS_TO_HOMEKIT_TARGET = {
52 AlarmControlPanelState.ARMED_HOME: HK_ALARM_STAY_ARMED,
53 AlarmControlPanelState.ARMED_VACATION: HK_ALARM_AWAY_ARMED,
54 AlarmControlPanelState.ARMED_AWAY: HK_ALARM_AWAY_ARMED,
55 AlarmControlPanelState.ARMED_NIGHT: HK_ALARM_NIGHT_ARMED,
56 AlarmControlPanelState.ARMING: HK_ALARM_AWAY_ARMED,
57 AlarmControlPanelState.DISARMED: HK_ALARM_DISARMED,
60 HASS_TO_HOMEKIT_SERVICES = {
61 SERVICE_ALARM_ARM_HOME: HK_ALARM_STAY_ARMED,
62 SERVICE_ALARM_ARM_AWAY: HK_ALARM_AWAY_ARMED,
63 SERVICE_ALARM_ARM_NIGHT: HK_ALARM_NIGHT_ARMED,
64 SERVICE_ALARM_DISARM: HK_ALARM_DISARMED,
68 HK_ALARM_AWAY_ARMED: SERVICE_ALARM_ARM_AWAY,
69 HK_ALARM_STAY_ARMED: SERVICE_ALARM_ARM_HOME,
70 HK_ALARM_NIGHT_ARMED: SERVICE_ALARM_ARM_NIGHT,
71 HK_ALARM_DISARMED: SERVICE_ALARM_DISARM,
75 @TYPES.register("SecuritySystem")
77 """Generate an SecuritySystem accessory for an alarm control panel."""
80 """Initialize a SecuritySystem accessory object."""
81 super().
__init__(*args, category=CATEGORY_ALARM_SYSTEM)
86 supported_states = state.attributes.get(
87 ATTR_SUPPORTED_FEATURES,
89 AlarmControlPanelEntityFeature.ARM_HOME
90 | AlarmControlPanelEntityFeature.ARM_VACATION
91 | AlarmControlPanelEntityFeature.ARM_AWAY
92 | AlarmControlPanelEntityFeature.ARM_NIGHT
93 | AlarmControlPanelEntityFeature.TRIGGER
97 serv_alarm = self.add_preload_service(SERV_SECURITY_SYSTEM)
98 current_char = serv_alarm.get_characteristic(CHAR_CURRENT_SECURITY_STATE)
99 target_char = serv_alarm.get_characteristic(CHAR_TARGET_SECURITY_STATE)
100 default_current_states = current_char.properties.get(
"ValidValues")
101 default_target_services = target_char.properties.get(
"ValidValues")
103 current_supported_states = [HK_ALARM_DISARMED, HK_ALARM_TRIGGERED]
104 target_supported_services = [HK_ALARM_DISARMED]
106 if supported_states & AlarmControlPanelEntityFeature.ARM_HOME:
107 current_supported_states.append(HK_ALARM_STAY_ARMED)
108 target_supported_services.append(HK_ALARM_STAY_ARMED)
110 if supported_states & (
111 AlarmControlPanelEntityFeature.ARM_AWAY
112 | AlarmControlPanelEntityFeature.ARM_VACATION
114 current_supported_states.append(HK_ALARM_AWAY_ARMED)
115 target_supported_services.append(HK_ALARM_AWAY_ARMED)
117 if supported_states & AlarmControlPanelEntityFeature.ARM_NIGHT:
118 current_supported_states.append(HK_ALARM_NIGHT_ARMED)
119 target_supported_services.append(HK_ALARM_NIGHT_ARMED)
122 CHAR_CURRENT_SECURITY_STATE,
123 value=HASS_TO_HOMEKIT_CURRENT[AlarmControlPanelState.DISARMED],
126 for key, val
in default_current_states.items()
127 if val
in current_supported_states
131 CHAR_TARGET_SECURITY_STATE,
132 value=HASS_TO_HOMEKIT_SERVICES[SERVICE_ALARM_DISARM],
135 for key, val
in default_target_services.items()
136 if val
in target_supported_services
146 """Move security state to value if call came from HomeKit."""
147 _LOGGER.debug(
"%s: Set security state to %d", self.
entity_identity_id, value)
148 service = HK_TO_SERVICE[value]
149 params = {ATTR_ENTITY_ID: self.
entity_identity_id}
152 self.
async_call_serviceasync_call_service(ALARM_CONTROL_PANEL_DOMAIN, service, params)
156 """Update security state after state changed."""
157 hass_state: str | AlarmControlPanelState = new_state.state
158 if hass_state
in {
"None", STATE_UNKNOWN, STATE_UNAVAILABLE}:
161 if hass_state
is not None:
162 hass_state = AlarmControlPanelState(hass_state)
165 and (current_state := HASS_TO_HOMEKIT_CURRENT.get(hass_state))
is not None
169 "%s: Updated current state to %s (%d)",
176 and (target_state := HASS_TO_HOMEKIT_TARGET.get(hass_state))
is not None
None async_call_service(self, str domain, str service, dict[str, Any]|None service_data, Any|None value=None)
None async_update_state(self, State new_state)
None async_update_state(self, State new_state)
None __init__(self, *Any args)
None set_security_state(self, int value)
web.Response get(self, web.Request request, str config_key)