Home Assistant Unofficial Reference 2024.12.1
binary_sensor.py
Go to the documentation of this file.
1 """Support for Freebox devices (Freebox v6 and Freebox mini 4K)."""
2 
3 from __future__ import annotations
4 
5 import logging
6 from typing import Any
7 
9  BinarySensorDeviceClass,
10  BinarySensorEntity,
11  BinarySensorEntityDescription,
12 )
13 from homeassistant.config_entries import ConfigEntry
14 from homeassistant.const import EntityCategory
15 from homeassistant.core import HomeAssistant, callback
16 from homeassistant.helpers.dispatcher import async_dispatcher_connect
17 from homeassistant.helpers.entity_platform import AddEntitiesCallback
18 
19 from .const import DOMAIN, FreeboxHomeCategory
20 from .entity import FreeboxHomeEntity
21 from .router import FreeboxRouter
22 
23 _LOGGER = logging.getLogger(__name__)
24 
25 
26 RAID_SENSORS: tuple[BinarySensorEntityDescription, ...] = (
28  key="raid_degraded",
29  name="degraded",
30  device_class=BinarySensorDeviceClass.PROBLEM,
31  entity_category=EntityCategory.DIAGNOSTIC,
32  ),
33 )
34 
35 
37  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
38 ) -> None:
39  """Set up binary sensors."""
40  router: FreeboxRouter = hass.data[DOMAIN][entry.unique_id]
41 
42  _LOGGER.debug("%s - %s - %s raid(s)", router.name, router.mac, len(router.raids))
43 
44  binary_entities: list[BinarySensorEntity] = [
45  FreeboxRaidDegradedSensor(router, raid, description)
46  for raid in router.raids.values()
47  for description in RAID_SENSORS
48  ]
49 
50  for node in router.home_devices.values():
51  if node["category"] == FreeboxHomeCategory.PIR:
52  binary_entities.append(FreeboxPirSensor(hass, router, node))
53  elif node["category"] == FreeboxHomeCategory.DWS:
54  binary_entities.append(FreeboxDwsSensor(hass, router, node))
55 
56  binary_entities.extend(
57  FreeboxCoverSensor(hass, router, node)
58  for endpoint in node["show_endpoints"]
59  if (
60  endpoint["name"] == "cover"
61  and endpoint["ep_type"] == "signal"
62  and endpoint.get("value") is not None
63  )
64  )
65 
66  async_add_entities(binary_entities, True)
67 
68 
70  """Representation of a Freebox binary sensor."""
71 
72  _sensor_name = "trigger"
73 
74  def __init__(
75  self,
76  hass: HomeAssistant,
77  router: FreeboxRouter,
78  node: dict[str, Any],
79  sub_node: dict[str, Any] | None = None,
80  ) -> None:
81  """Initialize a Freebox binary sensor."""
82  super().__init__(hass, router, node, sub_node)
83  self._command_id_command_id = self.get_command_idget_command_id(
84  node["type"]["endpoints"], "signal", self._sensor_name_sensor_name_sensor_name
85  )
86  self._attr_is_on_attr_is_on = self._edit_state_edit_state(self.get_valueget_value("signal", self._sensor_name_sensor_name_sensor_name))
87 
88  async def async_update_signal(self) -> None:
89  """Update name & state."""
90  self._attr_is_on_attr_is_on = self._edit_state_edit_state(
91  await self.get_home_endpoint_valueget_home_endpoint_value(self._command_id_command_id)
92  )
93  await FreeboxHomeEntity.async_update_signal(self)
94 
95  def _edit_state(self, state: bool | None) -> bool | None:
96  """Edit state depending on sensor name."""
97  if state is None:
98  return None
99  if self._sensor_name_sensor_name_sensor_name == "trigger":
100  return not state
101  return state
102 
103 
105  """Representation of a Freebox motion binary sensor."""
106 
107  _attr_device_class = BinarySensorDeviceClass.MOTION
108 
109 
111  """Representation of a Freebox door opener binary sensor."""
112 
113  _attr_device_class = BinarySensorDeviceClass.DOOR
114 
115 
117  """Representation of a cover Freebox plastic removal cover binary sensor (for some sensors: motion detector, door opener detector...)."""
118 
119  _attr_device_class = BinarySensorDeviceClass.SAFETY
120  _attr_entity_category = EntityCategory.DIAGNOSTIC
121  _attr_entity_registry_enabled_default = False
122 
123  _sensor_name = "cover"
124 
125  def __init__(
126  self, hass: HomeAssistant, router: FreeboxRouter, node: dict[str, Any]
127  ) -> None:
128  """Initialize a cover for another device."""
129  cover_node = next(
130  filter(
131  lambda x: (x["name"] == self._sensor_name_sensor_name_sensor_name_sensor_name and x["ep_type"] == "signal"),
132  node["type"]["endpoints"],
133  ),
134  None,
135  )
136  super().__init__(hass, router, node, cover_node)
137 
138 
140  """Representation of a Freebox raid sensor."""
141 
142  _attr_should_poll = False
143  _attr_has_entity_name = True
144 
145  def __init__(
146  self,
147  router: FreeboxRouter,
148  raid: dict[str, Any],
149  description: BinarySensorEntityDescription,
150  ) -> None:
151  """Initialize a Freebox raid degraded sensor."""
152  self.entity_descriptionentity_description = description
153  self._router_router = router
154  self._attr_device_info_attr_device_info = router.device_info
155  self._raid_raid = raid
156  self._attr_name_attr_name = f"Raid array {raid['id']} {description.name}"
157  self._attr_unique_id_attr_unique_id = (
158  f"{router.mac} {description.key} {raid['name']} {raid['id']}"
159  )
160 
161  @callback
162  def async_update_state(self) -> None:
163  """Update the Freebox Raid sensor."""
164  self._raid_raid = self._router_router.raids[self._raid_raid["id"]]
165 
166  @property
167  def is_on(self) -> bool:
168  """Return true if degraded."""
169  return self._raid_raid["degraded"]
170 
171  @callback
172  def async_on_demand_update(self) -> None:
173  """Update state."""
174  self.async_update_stateasync_update_state()
175  self.async_write_ha_stateasync_write_ha_state()
176 
177  async def async_added_to_hass(self) -> None:
178  """Register state update callback."""
179  self.async_update_stateasync_update_state()
180  self.async_on_removeasync_on_remove(
182  self.hasshass,
183  self._router_router.signal_sensor_update,
184  self.async_on_demand_updateasync_on_demand_update,
185  )
186  )
None __init__(self, HomeAssistant hass, FreeboxRouter router, dict[str, Any] node)
None __init__(self, HomeAssistant hass, FreeboxRouter router, dict[str, Any] node, dict[str, Any]|None sub_node=None)
None __init__(self, FreeboxRouter router, dict[str, Any] raid, BinarySensorEntityDescription description)
def get_value(self, str ep_type, str name)
Definition: entity.py:136
Any|None get_home_endpoint_value(self, Any command_id)
Definition: entity.py:95
int|None get_command_id(self, nodes, str ep_type, str name)
Definition: entity.py:104
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103