Home Assistant Unofficial Reference 2024.12.1
binary_sensor.py
Go to the documentation of this file.
1 """Support for Homekit motion sensors."""
2 
3 from __future__ import annotations
4 
5 from aiohomekit.model.characteristics import CharacteristicsTypes
6 from aiohomekit.model.services import Service, ServicesTypes
7 
9  BinarySensorDeviceClass,
10  BinarySensorEntity,
11 )
12 from homeassistant.config_entries import ConfigEntry
13 from homeassistant.const import EntityCategory, Platform
14 from homeassistant.core import HomeAssistant, callback
15 from homeassistant.helpers.entity_platform import AddEntitiesCallback
16 
17 from . import KNOWN_DEVICES
18 from .connection import HKDevice
19 from .entity import HomeKitEntity
20 
21 
23  """Representation of a Homekit motion sensor."""
24 
25  _attr_device_class = BinarySensorDeviceClass.MOTION
26 
27  def get_characteristic_types(self) -> list[str]:
28  """Define the homekit characteristics the entity is tracking."""
29  return [CharacteristicsTypes.MOTION_DETECTED]
30 
31  @property
32  def is_on(self) -> bool:
33  """Has motion been detected."""
34  return self.serviceservice.value(CharacteristicsTypes.MOTION_DETECTED) is True
35 
36 
38  """Representation of a Homekit contact sensor."""
39 
40  _attr_device_class = BinarySensorDeviceClass.OPENING
41 
42  def get_characteristic_types(self) -> list[str]:
43  """Define the homekit characteristics the entity is tracking."""
44  return [CharacteristicsTypes.CONTACT_STATE]
45 
46  @property
47  def is_on(self) -> bool:
48  """Return true if the binary sensor is on/open."""
49  return self.serviceservice.value(CharacteristicsTypes.CONTACT_STATE) == 1
50 
51 
53  """Representation of a Homekit smoke sensor."""
54 
55  _attr_device_class = BinarySensorDeviceClass.SMOKE
56 
57  def get_characteristic_types(self) -> list[str]:
58  """Define the homekit characteristics the entity is tracking."""
59  return [CharacteristicsTypes.SMOKE_DETECTED]
60 
61  @property
62  def is_on(self) -> bool:
63  """Return true if smoke is currently detected."""
64  return self.serviceservice.value(CharacteristicsTypes.SMOKE_DETECTED) == 1
65 
66 
68  """Representation of a Homekit BO sensor."""
69 
70  _attr_device_class = BinarySensorDeviceClass.CO
71 
72  def get_characteristic_types(self) -> list[str]:
73  """Define the homekit characteristics the entity is tracking."""
74  return [CharacteristicsTypes.CARBON_MONOXIDE_DETECTED]
75 
76  @property
77  def is_on(self) -> bool:
78  """Return true if CO is currently detected."""
79  return self.serviceservice.value(CharacteristicsTypes.CARBON_MONOXIDE_DETECTED) == 1
80 
81 
83  """Representation of a Homekit occupancy sensor."""
84 
85  _attr_device_class = BinarySensorDeviceClass.OCCUPANCY
86 
87  def get_characteristic_types(self) -> list[str]:
88  """Define the homekit characteristics the entity is tracking."""
89  return [CharacteristicsTypes.OCCUPANCY_DETECTED]
90 
91  @property
92  def is_on(self) -> bool:
93  """Return true if occupancy is currently detected."""
94  return self.serviceservice.value(CharacteristicsTypes.OCCUPANCY_DETECTED) == 1
95 
96 
98  """Representation of a Homekit leak sensor."""
99 
100  _attr_device_class = BinarySensorDeviceClass.MOISTURE
101 
102  def get_characteristic_types(self) -> list[str]:
103  """Define the homekit characteristics the entity is tracking."""
104  return [CharacteristicsTypes.LEAK_DETECTED]
105 
106  @property
107  def is_on(self) -> bool:
108  """Return true if a leak is detected from the binary sensor."""
109  return self.serviceservice.value(CharacteristicsTypes.LEAK_DETECTED) == 1
110 
111 
113  """Representation of a Homekit battery low sensor."""
114 
115  _attr_device_class = BinarySensorDeviceClass.BATTERY
116  _attr_entity_category = EntityCategory.DIAGNOSTIC
117 
118  def get_characteristic_types(self) -> list[str]:
119  """Define the homekit characteristics the entity is tracking."""
120  return [CharacteristicsTypes.STATUS_LO_BATT]
121 
122  @property
123  def name(self) -> str:
124  """Return the name of the sensor."""
125  if name := self.accessoryaccessory.name:
126  return f"{name} Low Battery"
127  return "Low Battery"
128 
129  @property
130  def is_on(self) -> bool:
131  """Return true if low battery is detected from the binary sensor."""
132  return self.serviceservice.value(CharacteristicsTypes.STATUS_LO_BATT) == 1
133 
134 
135 ENTITY_TYPES = {
136  ServicesTypes.MOTION_SENSOR: HomeKitMotionSensor,
137  ServicesTypes.CONTACT_SENSOR: HomeKitContactSensor,
138  ServicesTypes.SMOKE_SENSOR: HomeKitSmokeSensor,
139  ServicesTypes.CARBON_MONOXIDE_SENSOR: HomeKitCarbonMonoxideSensor,
140  ServicesTypes.OCCUPANCY_SENSOR: HomeKitOccupancySensor,
141  ServicesTypes.LEAK_SENSOR: HomeKitLeakSensor,
142  ServicesTypes.BATTERY_SERVICE: HomeKitBatteryLowSensor,
143 }
144 
145 # Only create the entity if it has the required characteristic
146 REQUIRED_CHAR_BY_TYPE = {
147  ServicesTypes.BATTERY_SERVICE: CharacteristicsTypes.STATUS_LO_BATT,
148 }
149 # Reject the service as another platform can represent it better
150 # if it has a specific characteristic
151 REJECT_CHAR_BY_TYPE = {
152  ServicesTypes.BATTERY_SERVICE: CharacteristicsTypes.BATTERY_LEVEL,
153 }
154 
155 
157  hass: HomeAssistant,
158  config_entry: ConfigEntry,
159  async_add_entities: AddEntitiesCallback,
160 ) -> None:
161  """Set up Homekit lighting."""
162  hkid: str = config_entry.data["AccessoryPairingID"]
163  conn: HKDevice = hass.data[KNOWN_DEVICES][hkid]
164 
165  @callback
166  def async_add_service(service: Service) -> bool:
167  if not (entity_class := ENTITY_TYPES.get(service.type)):
168  return False
169  if (
170  required_char := REQUIRED_CHAR_BY_TYPE.get(service.type)
171  ) and not service.has(required_char):
172  return False
173  if (reject_char := REJECT_CHAR_BY_TYPE.get(service.type)) and service.has(
174  reject_char
175  ):
176  return False
177  info = {"aid": service.accessory.aid, "iid": service.iid}
178  entity: HomeKitEntity = entity_class(conn, info)
179  conn.async_migrate_unique_id(
180  entity.old_unique_id, entity.unique_id, Platform.BINARY_SENSOR
181  )
182  async_add_entities([entity])
183  return True
184 
185  conn.add_listener(async_add_service)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)