1 """Interfaces with TotalConnect alarm control panels."""
3 from __future__
import annotations
5 from total_connect_client
import ArmingHelper
6 from total_connect_client.exceptions
import BadResultCodeError, UsercodeInvalid
7 from total_connect_client.location
import TotalConnectLocation
10 AlarmControlPanelEntity,
11 AlarmControlPanelEntityFeature,
12 AlarmControlPanelState,
21 from .const
import CODE_REQUIRED, DOMAIN
22 from .coordinator
import TotalConnectDataUpdateCoordinator
23 from .entity
import TotalConnectLocationEntity
25 SERVICE_ALARM_ARM_AWAY_INSTANT =
"arm_away_instant"
26 SERVICE_ALARM_ARM_HOME_INSTANT =
"arm_home_instant"
30 hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
32 """Set up TotalConnect alarm panels based on a config entry."""
33 coordinator: TotalConnectDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
34 code_required = entry.options.get(CODE_REQUIRED,
False)
38 for location
in coordinator.client.locations.values()
39 for partition_id
in location.partitions
43 platform = entity_platform.async_get_current_platform()
45 platform.async_register_entity_service(
46 SERVICE_ALARM_ARM_AWAY_INSTANT,
48 "async_alarm_arm_away_instant",
51 platform.async_register_entity_service(
52 SERVICE_ALARM_ARM_HOME_INSTANT,
54 "async_alarm_arm_home_instant",
59 """Represent a TotalConnect alarm panel."""
61 _attr_supported_features = (
62 AlarmControlPanelEntityFeature.ARM_HOME
63 | AlarmControlPanelEntityFeature.ARM_AWAY
64 | AlarmControlPanelEntityFeature.ARM_NIGHT
69 coordinator: TotalConnectDataUpdateCoordinator,
70 location: TotalConnectLocation,
74 """Initialize the TotalConnect status."""
75 super().
__init__(coordinator, location)
80 Set unique_id to location_id for partition 1 to avoid breaking change
81 for most users with new support for partitions.
82 Add _# for partition 2 and beyond.
90 self.
_attr_unique_id_attr_unique_id = f
"{location.location_id}_{partition_id}"
98 """Return the state of the device."""
101 "location_id": self.
_location_location.location_id,
103 "ac_loss": self.
_location_location.ac_loss,
104 "low_battery": self.
_location_location.low_battery,
105 "cover_tampered": self.
_location_location.is_cover_tampered(),
106 "triggered_source":
None,
107 "triggered_zone":
None,
111 attr[
"location_name"] = self.
devicedevice.name
113 attr[
"location_name"] = f
"{self.device.name} partition {self._partition_id}"
115 state: AlarmControlPanelState |
None =
None
116 if self.
_partition_partition.arming_state.is_disarmed():
117 state = AlarmControlPanelState.DISARMED
118 elif self.
_partition_partition.arming_state.is_armed_night():
119 state = AlarmControlPanelState.ARMED_NIGHT
120 elif self.
_partition_partition.arming_state.is_armed_home():
121 state = AlarmControlPanelState.ARMED_HOME
122 elif self.
_partition_partition.arming_state.is_armed_away():
123 state = AlarmControlPanelState.ARMED_AWAY
124 elif self.
_partition_partition.arming_state.is_armed_custom_bypass():
125 state = AlarmControlPanelState.ARMED_CUSTOM_BYPASS
126 elif self.
_partition_partition.arming_state.is_arming():
127 state = AlarmControlPanelState.ARMING
128 elif self.
_partition_partition.arming_state.is_disarming():
129 state = AlarmControlPanelState.DISARMING
130 elif self.
_partition_partition.arming_state.is_triggered_police():
131 state = AlarmControlPanelState.TRIGGERED
132 attr[
"triggered_source"] =
"Police/Medical"
133 elif self.
_partition_partition.arming_state.is_triggered_fire():
134 state = AlarmControlPanelState.TRIGGERED
135 attr[
"triggered_source"] =
"Fire/Smoke"
136 elif self.
_partition_partition.arming_state.is_triggered_gas():
137 state = AlarmControlPanelState.TRIGGERED
138 attr[
"triggered_source"] =
"Carbon Monoxide"
145 """Send disarm command."""
149 except UsercodeInvalid
as error:
150 self.coordinator.config_entry.async_start_reauth(self.
hasshasshass)
152 translation_domain=DOMAIN,
153 translation_key=
"disarm_invalid_code",
155 except BadResultCodeError
as error:
157 translation_domain=DOMAIN,
158 translation_key=
"disarm_failed",
159 translation_placeholders={
"device": self.
devicedevice.name},
164 """Disarm synchronous."""
165 ArmingHelper(self.
_partition_partition).disarm()
168 """Send arm home command."""
172 except UsercodeInvalid
as error:
173 self.coordinator.config_entry.async_start_reauth(self.
hasshasshass)
175 translation_domain=DOMAIN,
176 translation_key=
"arm_home_invalid_code",
178 except BadResultCodeError
as error:
180 translation_domain=DOMAIN,
181 translation_key=
"arm_home_failed",
182 translation_placeholders={
"device": self.
devicedevice.name},
187 """Arm home synchronous."""
188 ArmingHelper(self.
_partition_partition).arm_stay()
191 """Send arm away command."""
195 except UsercodeInvalid
as error:
196 self.coordinator.config_entry.async_start_reauth(self.
hasshasshass)
198 translation_domain=DOMAIN,
199 translation_key=
"arm_away_invalid_code",
201 except BadResultCodeError
as error:
203 translation_domain=DOMAIN,
204 translation_key=
"arm_away_failed",
205 translation_placeholders={
"device": self.
devicedevice.name},
210 """Arm away synchronous."""
211 ArmingHelper(self.
_partition_partition).arm_away()
214 """Send arm night command."""
218 except UsercodeInvalid
as error:
219 self.coordinator.config_entry.async_start_reauth(self.
hasshasshass)
221 translation_domain=DOMAIN,
222 translation_key=
"arm_night_invalid_code",
224 except BadResultCodeError
as error:
226 translation_domain=DOMAIN,
227 translation_key=
"arm_night_failed",
228 translation_placeholders={
"device": self.
devicedevice.name},
233 """Arm night synchronous."""
234 ArmingHelper(self.
_partition_partition).arm_stay_night()
237 """Send arm home instant command."""
240 except UsercodeInvalid
as error:
241 self.coordinator.config_entry.async_start_reauth(self.
hasshasshass)
243 translation_domain=DOMAIN,
244 translation_key=
"arm_home_instant_invalid_code",
246 except BadResultCodeError
as error:
248 translation_domain=DOMAIN,
249 translation_key=
"arm_home_instant_failed",
250 translation_placeholders={
"device": self.
devicedevice.name},
255 """Arm home instant synchronous."""
256 ArmingHelper(self.
_partition_partition).arm_stay_instant()
259 """Send arm away instant command."""
262 except UsercodeInvalid
as error:
263 self.coordinator.config_entry.async_start_reauth(self.
hasshasshass)
265 translation_domain=DOMAIN,
266 translation_key=
"arm_away_instant_invalid_code",
268 except BadResultCodeError
as error:
270 translation_domain=DOMAIN,
271 translation_key=
"arm_away_instant_failed",
272 translation_placeholders={
"device": self.
devicedevice.name},
277 """Arm away instant synchronous."""
278 ArmingHelper(self.
_partition_partition).arm_away_instant()
281 """Check if the run-time entered code matches configured code."""
284 and self.coordinator.client.usercodes[self.
_location_location.location_id] != code
287 translation_domain=DOMAIN, translation_key=
"invalid_pin"
def _check_usercode(self, code)
AlarmControlPanelState|None alarm_state(self)
None async_alarm_arm_away_instant(self)
def _arm_away_instant(self)
None async_alarm_arm_home_instant(self)
None async_alarm_arm_away(self, str|None code=None)
None async_alarm_arm_night(self, str|None code=None)
None async_alarm_disarm(self, str|None code=None)
def _arm_home_instant(self)
None __init__(self, TotalConnectDataUpdateCoordinator coordinator, TotalConnectLocation location, int partition_id, bool require_code)
None async_alarm_arm_home(self, str|None code=None)
_attr_translation_placeholders
_attr_extra_state_attributes
None async_request_refresh(self)
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)