Home Assistant Unofficial Reference 2024.12.1
binary_sensor.py
Go to the documentation of this file.
1 """Interfaces with TotalConnect sensors."""
2 
3 from collections.abc import Callable
4 from dataclasses import dataclass
5 import logging
6 
7 from total_connect_client.location import TotalConnectLocation
8 from total_connect_client.zone import TotalConnectZone
9 
11  BinarySensorDeviceClass,
12  BinarySensorEntity,
13  BinarySensorEntityDescription,
14 )
15 from homeassistant.config_entries import ConfigEntry
16 from homeassistant.const import EntityCategory
17 from homeassistant.core import HomeAssistant
18 from homeassistant.helpers.entity_platform import AddEntitiesCallback
19 
20 from .const import DOMAIN
21 from .coordinator import TotalConnectDataUpdateCoordinator
22 from .entity import TotalConnectLocationEntity, TotalConnectZoneEntity
23 
24 LOW_BATTERY = "low_battery"
25 TAMPER = "tamper"
26 POWER = "power"
27 ZONE = "zone"
28 
29 _LOGGER = logging.getLogger(__name__)
30 
31 
32 @dataclass(frozen=True, kw_only=True)
34  """Describes TotalConnect binary sensor entity."""
35 
36  device_class_fn: Callable[[TotalConnectZone], BinarySensorDeviceClass] | None = None
37  is_on_fn: Callable[[TotalConnectZone], bool]
38 
39 
40 def get_security_zone_device_class(zone: TotalConnectZone) -> BinarySensorDeviceClass:
41  """Return the device class of a TotalConnect security zone."""
42  if zone.is_type_fire():
43  return BinarySensorDeviceClass.SMOKE
44  if zone.is_type_carbon_monoxide():
45  return BinarySensorDeviceClass.GAS
46  if zone.is_type_motion():
47  return BinarySensorDeviceClass.MOTION
48  if zone.is_type_medical():
49  return BinarySensorDeviceClass.SAFETY
50  if zone.is_type_temperature():
51  return BinarySensorDeviceClass.PROBLEM
52  return BinarySensorDeviceClass.DOOR
53 
54 
56  key=ZONE,
57  name=None,
58  device_class_fn=get_security_zone_device_class,
59  is_on_fn=lambda zone: zone.is_faulted() or zone.is_triggered(),
60 )
61 
62 NO_BUTTON_BINARY_SENSORS: tuple[TotalConnectZoneBinarySensorEntityDescription, ...] = (
64  key=LOW_BATTERY,
65  device_class=BinarySensorDeviceClass.BATTERY,
66  entity_category=EntityCategory.DIAGNOSTIC,
67  is_on_fn=lambda zone: zone.is_low_battery(),
68  ),
70  key=TAMPER,
71  device_class=BinarySensorDeviceClass.TAMPER,
72  entity_category=EntityCategory.DIAGNOSTIC,
73  is_on_fn=lambda zone: zone.is_tampered(),
74  ),
75 )
76 
77 
78 @dataclass(frozen=True, kw_only=True)
80  """Describes TotalConnect binary sensor entity."""
81 
82  is_on_fn: Callable[[TotalConnectLocation], bool]
83 
84 
85 LOCATION_BINARY_SENSORS: tuple[TotalConnectAlarmBinarySensorEntityDescription, ...] = (
87  key=LOW_BATTERY,
88  device_class=BinarySensorDeviceClass.BATTERY,
89  entity_category=EntityCategory.DIAGNOSTIC,
90  is_on_fn=lambda location: location.is_low_battery(),
91  ),
93  key=TAMPER,
94  device_class=BinarySensorDeviceClass.TAMPER,
95  entity_category=EntityCategory.DIAGNOSTIC,
96  is_on_fn=lambda location: location.is_cover_tampered(),
97  ),
99  key=POWER,
100  device_class=BinarySensorDeviceClass.POWER,
101  entity_category=EntityCategory.DIAGNOSTIC,
102  is_on_fn=lambda location: location.is_ac_loss(),
103  ),
105  key="smoke",
106  device_class=BinarySensorDeviceClass.SMOKE,
107  is_on_fn=lambda location: location.arming_state.is_triggered_fire(),
108  ),
110  key="carbon_monoxide",
111  device_class=BinarySensorDeviceClass.CO,
112  is_on_fn=lambda location: location.arming_state.is_triggered_gas(),
113  ),
115  key="police",
116  translation_key="police",
117  is_on_fn=lambda location: location.arming_state.is_triggered_police(),
118  ),
119 )
120 
121 
123  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
124 ) -> None:
125  """Set up TotalConnect device sensors based on a config entry."""
126  sensors: list = []
127 
128  coordinator: TotalConnectDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
129 
130  client_locations = coordinator.client.locations
131 
132  for location_id, location in client_locations.items():
133  sensors.extend(
134  TotalConnectAlarmBinarySensor(coordinator, description, location)
135  for description in LOCATION_BINARY_SENSORS
136  )
137 
138  for zone in location.zones.values():
139  sensors.append(
141  coordinator, SECURITY_BINARY_SENSOR, zone, location_id
142  )
143  )
144 
145  if not zone.is_type_button():
146  sensors.extend(
148  coordinator,
149  description,
150  zone,
151  location_id,
152  )
153  for description in NO_BUTTON_BINARY_SENSORS
154  )
155 
156  async_add_entities(sensors)
157 
158 
160  """Represent a TotalConnect zone."""
161 
162  entity_description: TotalConnectZoneBinarySensorEntityDescription
163 
164  def __init__(
165  self,
166  coordinator: TotalConnectDataUpdateCoordinator,
167  entity_description: TotalConnectZoneBinarySensorEntityDescription,
168  zone: TotalConnectZone,
169  location_id: str,
170  ) -> None:
171  """Initialize the TotalConnect status."""
172  super().__init__(coordinator, zone, location_id, entity_description.key)
173  self.entity_descriptionentity_description = entity_description
174  self._attr_extra_state_attributes_attr_extra_state_attributes = {
175  "zone_id": zone.zoneid,
176  "location_id": location_id,
177  "partition": zone.partition,
178  }
179 
180  @property
181  def is_on(self) -> bool:
182  """Return the state of the entity."""
183  return self.entity_descriptionentity_description.is_on_fn(self._zone_zone)
184 
185  @property
186  def device_class(self) -> BinarySensorDeviceClass | None:
187  """Return the class of this zone."""
188  if self.entity_descriptionentity_description.device_class_fn:
189  return self.entity_descriptionentity_description.device_class_fn(self._zone_zone)
190  return super().device_class
191 
192 
194  """Represent a TotalConnect alarm device binary sensors."""
195 
196  entity_description: TotalConnectAlarmBinarySensorEntityDescription
197 
198  def __init__(
199  self,
200  coordinator: TotalConnectDataUpdateCoordinator,
201  entity_description: TotalConnectAlarmBinarySensorEntityDescription,
202  location: TotalConnectLocation,
203  ) -> None:
204  """Initialize the TotalConnect alarm device binary sensor."""
205  super().__init__(coordinator, location)
206  self.entity_descriptionentity_description = entity_description
207  self._attr_unique_id_attr_unique_id = f"{location.location_id}_{entity_description.key}"
208  self._attr_extra_state_attributes_attr_extra_state_attributes = {
209  "location_id": location.location_id,
210  }
211 
212  @property
213  def is_on(self) -> bool:
214  """Return the state of the entity."""
215  return self.entity_descriptionentity_description.is_on_fn(self._location_location)
None __init__(self, TotalConnectDataUpdateCoordinator coordinator, TotalConnectAlarmBinarySensorEntityDescription entity_description, TotalConnectLocation location)
None __init__(self, TotalConnectDataUpdateCoordinator coordinator, TotalConnectZoneBinarySensorEntityDescription entity_description, TotalConnectZone zone, str location_id)
BinarySensorDeviceClass get_security_zone_device_class(TotalConnectZone zone)
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)