Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """Component to interface with binary sensors."""
2 
3 from __future__ import annotations
4 
5 from datetime import timedelta
6 from enum import StrEnum
7 from functools import partial
8 import logging
9 from typing import Literal, final
10 
11 from propcache import cached_property
12 import voluptuous as vol
13 
14 from homeassistant.config_entries import ConfigEntry
15 from homeassistant.const import STATE_OFF, STATE_ON, EntityCategory
16 from homeassistant.core import HomeAssistant
17 from homeassistant.exceptions import HomeAssistantError
18 from homeassistant.helpers import config_validation as cv
20  DeprecatedConstantEnum,
21  all_with_deprecated_constants,
22  check_if_deprecated_constant,
23  dir_with_deprecated_constants,
24 )
25 from homeassistant.helpers.entity import Entity, EntityDescription
26 from homeassistant.helpers.entity_component import EntityComponent
27 from homeassistant.helpers.typing import ConfigType
28 from homeassistant.util.hass_dict import HassKey
29 
30 _LOGGER = logging.getLogger(__name__)
31 
32 DOMAIN = "binary_sensor"
33 DATA_COMPONENT: HassKey[EntityComponent[BinarySensorEntity]] = HassKey(DOMAIN)
34 ENTITY_ID_FORMAT = DOMAIN + ".{}"
35 PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA
36 PLATFORM_SCHEMA_BASE = cv.PLATFORM_SCHEMA_BASE
37 SCAN_INTERVAL = timedelta(seconds=30)
38 
39 
40 class BinarySensorDeviceClass(StrEnum):
41  """Device class for binary sensors."""
42 
43  # On means low, Off means normal
44  BATTERY = "battery"
45 
46  # On means charging, Off means not charging
47  BATTERY_CHARGING = "battery_charging"
48 
49  # On means carbon monoxide detected, Off means no carbon monoxide (clear)
50  CO = "carbon_monoxide"
51 
52  # On means cold, Off means normal
53  COLD = "cold"
54 
55  # On means connected, Off means disconnected
56  CONNECTIVITY = "connectivity"
57 
58  # On means open, Off means closed
59  DOOR = "door"
60 
61  # On means open, Off means closed
62  GARAGE_DOOR = "garage_door"
63 
64  # On means gas detected, Off means no gas (clear)
65  GAS = "gas"
66 
67  # On means hot, Off means normal
68  HEAT = "heat"
69 
70  # On means light detected, Off means no light
71  LIGHT = "light"
72 
73  # On means open (unlocked), Off means closed (locked)
74  LOCK = "lock"
75 
76  # On means wet, Off means dry
77  MOISTURE = "moisture"
78 
79  # On means motion detected, Off means no motion (clear)
80  MOTION = "motion"
81 
82  # On means moving, Off means not moving (stopped)
83  MOVING = "moving"
84 
85  # On means occupied, Off means not occupied (clear)
86  OCCUPANCY = "occupancy"
87 
88  # On means open, Off means closed
89  OPENING = "opening"
90 
91  # On means plugged in, Off means unplugged
92  PLUG = "plug"
93 
94  # On means power detected, Off means no power
95  POWER = "power"
96 
97  # On means home, Off means away
98  PRESENCE = "presence"
99 
100  # On means problem detected, Off means no problem (OK)
101  PROBLEM = "problem"
102 
103  # On means running, Off means not running
104  RUNNING = "running"
105 
106  # On means unsafe, Off means safe
107  SAFETY = "safety"
108 
109  # On means smoke detected, Off means no smoke (clear)
110  SMOKE = "smoke"
111 
112  # On means sound detected, Off means no sound (clear)
113  SOUND = "sound"
114 
115  # On means tampering detected, Off means no tampering (clear)
116  TAMPER = "tamper"
117 
118  # On means update available, Off means up-to-date
119  UPDATE = "update"
120 
121  # On means vibration detected, Off means no vibration
122  VIBRATION = "vibration"
123 
124  # On means open, Off means closed
125  WINDOW = "window"
126 
127 
128 DEVICE_CLASSES_SCHEMA = vol.All(vol.Lower, vol.Coerce(BinarySensorDeviceClass))
129 
130 # DEVICE_CLASS* below are deprecated as of 2021.12
131 # use the BinarySensorDeviceClass enum instead.
132 DEVICE_CLASSES = [cls.value for cls in BinarySensorDeviceClass]
133 _DEPRECATED_DEVICE_CLASS_BATTERY = DeprecatedConstantEnum(
134  BinarySensorDeviceClass.BATTERY, "2025.1"
135 )
136 _DEPRECATED_DEVICE_CLASS_BATTERY_CHARGING = DeprecatedConstantEnum(
137  BinarySensorDeviceClass.BATTERY_CHARGING, "2025.1"
138 )
139 _DEPRECATED_DEVICE_CLASS_CO = DeprecatedConstantEnum(
140  BinarySensorDeviceClass.CO, "2025.1"
141 )
142 _DEPRECATED_DEVICE_CLASS_COLD = DeprecatedConstantEnum(
143  BinarySensorDeviceClass.COLD, "2025.1"
144 )
145 _DEPRECATED_DEVICE_CLASS_CONNECTIVITY = DeprecatedConstantEnum(
146  BinarySensorDeviceClass.CONNECTIVITY, "2025.1"
147 )
148 _DEPRECATED_DEVICE_CLASS_DOOR = DeprecatedConstantEnum(
149  BinarySensorDeviceClass.DOOR, "2025.1"
150 )
151 _DEPRECATED_DEVICE_CLASS_GARAGE_DOOR = DeprecatedConstantEnum(
152  BinarySensorDeviceClass.GARAGE_DOOR, "2025.1"
153 )
154 _DEPRECATED_DEVICE_CLASS_GAS = DeprecatedConstantEnum(
155  BinarySensorDeviceClass.GAS, "2025.1"
156 )
157 _DEPRECATED_DEVICE_CLASS_HEAT = DeprecatedConstantEnum(
158  BinarySensorDeviceClass.HEAT, "2025.1"
159 )
160 _DEPRECATED_DEVICE_CLASS_LIGHT = DeprecatedConstantEnum(
161  BinarySensorDeviceClass.LIGHT, "2025.1"
162 )
163 _DEPRECATED_DEVICE_CLASS_LOCK = DeprecatedConstantEnum(
164  BinarySensorDeviceClass.LOCK, "2025.1"
165 )
166 _DEPRECATED_DEVICE_CLASS_MOISTURE = DeprecatedConstantEnum(
167  BinarySensorDeviceClass.MOISTURE, "2025.1"
168 )
169 _DEPRECATED_DEVICE_CLASS_MOTION = DeprecatedConstantEnum(
170  BinarySensorDeviceClass.MOTION, "2025.1"
171 )
172 _DEPRECATED_DEVICE_CLASS_MOVING = DeprecatedConstantEnum(
173  BinarySensorDeviceClass.MOVING, "2025.1"
174 )
175 _DEPRECATED_DEVICE_CLASS_OCCUPANCY = DeprecatedConstantEnum(
176  BinarySensorDeviceClass.OCCUPANCY, "2025.1"
177 )
178 _DEPRECATED_DEVICE_CLASS_OPENING = DeprecatedConstantEnum(
179  BinarySensorDeviceClass.OPENING, "2025.1"
180 )
181 _DEPRECATED_DEVICE_CLASS_PLUG = DeprecatedConstantEnum(
182  BinarySensorDeviceClass.PLUG, "2025.1"
183 )
184 _DEPRECATED_DEVICE_CLASS_POWER = DeprecatedConstantEnum(
185  BinarySensorDeviceClass.POWER, "2025.1"
186 )
187 _DEPRECATED_DEVICE_CLASS_PRESENCE = DeprecatedConstantEnum(
188  BinarySensorDeviceClass.PRESENCE, "2025.1"
189 )
190 _DEPRECATED_DEVICE_CLASS_PROBLEM = DeprecatedConstantEnum(
191  BinarySensorDeviceClass.PROBLEM, "2025.1"
192 )
193 _DEPRECATED_DEVICE_CLASS_RUNNING = DeprecatedConstantEnum(
194  BinarySensorDeviceClass.RUNNING, "2025.1"
195 )
196 _DEPRECATED_DEVICE_CLASS_SAFETY = DeprecatedConstantEnum(
197  BinarySensorDeviceClass.SAFETY, "2025.1"
198 )
199 _DEPRECATED_DEVICE_CLASS_SMOKE = DeprecatedConstantEnum(
200  BinarySensorDeviceClass.SMOKE, "2025.1"
201 )
202 _DEPRECATED_DEVICE_CLASS_SOUND = DeprecatedConstantEnum(
203  BinarySensorDeviceClass.SOUND, "2025.1"
204 )
205 _DEPRECATED_DEVICE_CLASS_TAMPER = DeprecatedConstantEnum(
206  BinarySensorDeviceClass.TAMPER, "2025.1"
207 )
208 _DEPRECATED_DEVICE_CLASS_UPDATE = DeprecatedConstantEnum(
209  BinarySensorDeviceClass.UPDATE, "2025.1"
210 )
211 _DEPRECATED_DEVICE_CLASS_VIBRATION = DeprecatedConstantEnum(
212  BinarySensorDeviceClass.VIBRATION, "2025.1"
213 )
214 _DEPRECATED_DEVICE_CLASS_WINDOW = DeprecatedConstantEnum(
215  BinarySensorDeviceClass.WINDOW, "2025.1"
216 )
217 
218 # mypy: disallow-any-generics
219 
220 
221 async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
222  """Track states and offer events for binary sensors."""
223  component = hass.data[DATA_COMPONENT] = EntityComponent[BinarySensorEntity](
224  logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL
225  )
226 
227  await component.async_setup(config)
228  return True
229 
230 
231 async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
232  """Set up a config entry."""
233  return await hass.data[DATA_COMPONENT].async_setup_entry(entry)
234 
235 
236 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
237  """Unload a config entry."""
238  return await hass.data[DATA_COMPONENT].async_unload_entry(entry)
239 
240 
241 class BinarySensorEntityDescription(EntityDescription, frozen_or_thawed=True):
242  """A class that describes binary sensor entities."""
243 
244  device_class: BinarySensorDeviceClass | None = None
245 
246 
247 CACHED_PROPERTIES_WITH_ATTR_ = {
248  "device_class",
249  "is_on",
250 }
251 
252 
253 class BinarySensorEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
254  """Represent a binary sensor."""
255 
256  entity_description: BinarySensorEntityDescription
257  _attr_device_class: BinarySensorDeviceClass | None
258  _attr_is_on: bool | None = None
259  _attr_state: None = None
260 
261  async def async_internal_added_to_hass(self) -> None:
262  """Call when the binary sensor entity is added to hass."""
263  await super().async_internal_added_to_hass()
264  if self.entity_categoryentity_categoryentity_category == EntityCategory.CONFIG:
265  raise HomeAssistantError(
266  f"Entity {self.entity_id} cannot be added as the entity category is set to config"
267  )
268 
269  def _default_to_device_class_name(self) -> bool:
270  """Return True if an unnamed entity should be named by its device class.
271 
272  For binary sensors this is True if the entity has a device class.
273  """
274  return self.device_classdevice_class is not None
275 
276  @cached_property
277  def device_class(self) -> BinarySensorDeviceClass | None:
278  """Return the class of this entity."""
279  if hasattr(self, "_attr_device_class"):
280  return self._attr_device_class
281  if hasattr(self, "entity_description"):
282  return self.entity_description.device_class
283  return None
284 
285  @cached_property
286  def is_on(self) -> bool | None:
287  """Return true if the binary sensor is on."""
288  return self._attr_is_on
289 
290  @final
291  @property
292  def state(self) -> Literal["on", "off"] | None:
293  """Return the state of the binary sensor."""
294  if (is_on := self.is_on) is None:
295  return None
296  return STATE_ON if is_on else STATE_OFF
297 
298 
299 # These can be removed if no deprecated constant are in this module anymore
300 __getattr__ = partial(check_if_deprecated_constant, module_globals=globals())
301 __dir__ = partial(
302  dir_with_deprecated_constants, module_globals_keys=[*globals().keys()]
303 )
304 __all__ = all_with_deprecated_constants(globals())
EntityCategory|None entity_category(self)
Definition: entity.py:895
bool _default_to_device_class_name(self)
Definition: entity.py:635
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:236
bool async_setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:221
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:231
bool is_on(HomeAssistant hass, str entity_id)
Definition: __init__.py:131
list[str] all_with_deprecated_constants(dict[str, Any] module_globals)
Definition: deprecation.py:356