Home Assistant Unofficial Reference 2024.12.1
binary_sensor.py
Go to the documentation of this file.
1 """Support for TPLink Omada binary sensors."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 from dataclasses import dataclass
7 
8 from tplink_omada_client.definitions import GatewayPortMode, LinkStatus, PoEMode
9 from tplink_omada_client.devices import (
10  OmadaDevice,
11  OmadaGatewayPortConfig,
12  OmadaGatewayPortStatus,
13 )
14 
16  BinarySensorDeviceClass,
17  BinarySensorEntity,
18  BinarySensorEntityDescription,
19 )
20 from homeassistant.core import HomeAssistant, callback
21 from homeassistant.helpers.entity_platform import AddEntitiesCallback
22 
23 from . import OmadaConfigEntry
24 from .controller import OmadaGatewayCoordinator
25 from .entity import OmadaDeviceEntity
26 
27 
29  hass: HomeAssistant,
30  config_entry: OmadaConfigEntry,
31  async_add_entities: AddEntitiesCallback,
32 ) -> None:
33  """Set up binary sensors."""
34  controller = config_entry.runtime_data
35 
36  gateway_coordinator = controller.gateway_coordinator
37  if not gateway_coordinator:
38  return
39 
40  entities: list[OmadaDeviceEntity] = []
41  for gateway in gateway_coordinator.data.values():
42  entities.extend(
44  gateway_coordinator, gateway, p.port_number, desc
45  )
46  for p in gateway.port_configs
47  for desc in GATEWAY_PORT_SENSORS
48  if desc.exists_func(p)
49  )
50 
51  async_add_entities(entities)
52 
53 
54 @dataclass(frozen=True, kw_only=True)
56  """Entity description for a binary status derived from a gateway port."""
57 
58  exists_func: Callable[[OmadaGatewayPortConfig], bool] = lambda _: True
59  update_func: Callable[[OmadaGatewayPortStatus], bool]
60 
61 
62 GATEWAY_PORT_SENSORS: list[GatewayPortBinarySensorEntityDescription] = [
64  key="wan_link",
65  translation_key="wan_link",
66  device_class=BinarySensorDeviceClass.CONNECTIVITY,
67  exists_func=lambda p: p.port_status.mode == GatewayPortMode.WAN,
68  update_func=lambda p: p.wan_connected,
69  ),
71  key="online_detection",
72  translation_key="online_detection",
73  device_class=BinarySensorDeviceClass.CONNECTIVITY,
74  exists_func=lambda p: p.port_status.mode == GatewayPortMode.WAN,
75  update_func=lambda p: p.online_detection,
76  ),
78  key="lan_status",
79  translation_key="lan_status",
80  device_class=BinarySensorDeviceClass.CONNECTIVITY,
81  exists_func=lambda p: p.port_status.mode == GatewayPortMode.LAN,
82  update_func=lambda p: p.link_status == LinkStatus.LINK_UP,
83  ),
85  key="poe_delivery",
86  translation_key="poe_delivery",
87  device_class=BinarySensorDeviceClass.POWER,
88  exists_func=lambda p: (
89  p.port_status.mode == GatewayPortMode.LAN and p.poe_mode == PoEMode.ENABLED
90  ),
91  update_func=lambda p: p.poe_active,
92  ),
93 ]
94 
95 
97  OmadaDeviceEntity[OmadaGatewayCoordinator], BinarySensorEntity
98 ):
99  """Binary status of a property on an internet gateway."""
100 
101  entity_description: GatewayPortBinarySensorEntityDescription
102 
103  def __init__(
104  self,
105  coordinator: OmadaGatewayCoordinator,
106  device: OmadaDevice,
107  port_number: int,
108  entity_description: GatewayPortBinarySensorEntityDescription,
109  ) -> None:
110  """Initialize the gateway port binary sensor."""
111  super().__init__(coordinator, device)
112  self.entity_descriptionentity_description = entity_description
113  self._port_number_port_number = port_number
114  self._attr_unique_id_attr_unique_id = f"{device.mac}_{port_number}_{entity_description.key}"
115  self._attr_translation_placeholders_attr_translation_placeholders = {"port_name": f"{port_number}"}
116 
117  async def async_added_to_hass(self) -> None:
118  """When entity is added to hass."""
119  await super().async_added_to_hass()
120  self._do_update_do_update()
121 
122  def _do_update(self) -> None:
123  gateway = self.coordinator.data[self.device.mac]
124 
125  port = next(
126  p for p in gateway.port_status if p.port_number == self._port_number_port_number
127  )
128  if port:
129  self._attr_is_on_attr_is_on = self.entity_descriptionentity_description.update_func(port)
130 
131  @callback
132  def _handle_coordinator_update(self) -> None:
133  """Handle updated data from the coordinator."""
134  self._do_update_do_update()
135  self.async_write_ha_stateasync_write_ha_state()