|
11 | 11 | SensorEntityDescription,
|
12 | 12 | SensorStateClass,
|
13 | 13 | )
|
14 |
| -from homeassistant.const import PERCENTAGE, UnitOfDataRate, UnitOfTemperature |
| 14 | +from homeassistant.const import ( |
| 15 | + PERCENTAGE, |
| 16 | + SIGNAL_STRENGTH_DECIBELS_MILLIWATT, |
| 17 | + EntityCategory, |
| 18 | + UnitOfDataRate, |
| 19 | + UnitOfTemperature, |
| 20 | +) |
15 | 21 | from homeassistant.core import HomeAssistant, callback
|
16 |
| -from homeassistant.helpers.device_registry import DeviceInfo |
| 22 | +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo |
17 | 23 | from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
18 | 24 | from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
19 | 25 | from homeassistant.util import dt as dt_util
|
20 | 26 |
|
21 |
| -from .const import DOMAIN |
| 27 | +from .const import DOMAIN, WIFI_BANDS_TO_CONNECTIVITY, DeviceConnectivityType |
22 | 28 | from .entity import FreeboxHomeEntity
|
23 | 29 | from .router import FreeboxConfigEntry, FreeboxRouter
|
24 | 30 |
|
|
60 | 66 | ),
|
61 | 67 | )
|
62 | 68 |
|
| 69 | +DEVICE_SENSORS: tuple[SensorEntityDescription, ...] = ( |
| 70 | + SensorEntityDescription( |
| 71 | + key="connectivity", |
|
10000
72 | + name="Connectivity", |
| 73 | + device_class=SensorDeviceClass.ENUM, |
| 74 | + options=[e.value for e in DeviceConnectivityType.__members__.values()], |
| 75 | + icon="mdi:network", |
| 76 | + entity_category=EntityCategory.DIAGNOSTIC, |
| 77 | + entity_registry_enabled_default=True, |
| 78 | + ), |
| 79 | +) |
| 80 | + |
| 81 | +WIFI_DEVICE_SENSORS: tuple[SensorEntityDescription, ...] = ( |
| 82 | + SensorEntityDescription( |
| 83 | + key="wifi_signal_dbm", |
| 84 | + name="Wifi signal strength", |
| 85 | + device_class=SensorDeviceClass.SIGNAL_STRENGTH, |
| 86 | + native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT, |
| 87 | + icon="mdi:signal", |
| 88 | + entity_category=EntityCategory.DIAGNOSTIC, |
| 89 | + entity_registry_enabled_default=True, |
| 90 | + ), |
| 91 | + SensorEntityDescription( |
| 92 | + key="wifi_signal_percentage", |
| 93 | + name="Wifi signal level", |
| 94 | + native_unit_of_measurement=PERCENTAGE, |
| 95 | + icon="mdi:signal", |
| 96 | + entity_category=EntityCategory.DIAGNOSTIC, |
| 97 | + entity_registry_enabled_default=True, |
| 98 | + ), |
| 99 | +) |
| 100 | + |
63 | 101 |
|
64 | 102 | async def async_setup_entry(
|
65 | 103 | hass: HomeAssistant,
|
@@ -113,6 +151,20 @@ async def async_setup_entry(
|
113 | 151 | ):
|
114 | 152 | entities.append(FreeboxBatterySensor(hass, router, node, endpoint))
|
115 | 153 |
|
| 154 | + for device in router.devices.values(): |
| 155 | + if not device.get("persistent", False): |
| 156 | + continue |
| 157 | + entities.extend( |
| 158 | + FreeboxDeviceSensor(router, device, description) |
| 159 | + for description in DEVICE_SENSORS |
| 160 | + ) |
| 161 | + if ( |
| 162 | + connectivity_type := get_device_connectity_type(device) |
| 163 | + ) and connectivity_type != DeviceConnectivityType.ETHERNET: |
| 164 | + entities.extend( |
| 165 | + FreeboxDeviceSensor(router, device, description) |
| 166 | + for description in WIFI_DEVICE_SENSORS |
| 167 | + ) |
116 | 168 | if entities:
|
117 | 169 | async_add_entities(entities, True)
|
118 | 170 |
|
@@ -241,3 +293,66 @@ class FreeboxBatterySensor(FreeboxHomeEntity, SensorEntity):
|
241 | 293 | def native_value(self) -> int:
|
242 | 294 | """Return the current state of the device."""
|
243 | 295 | return self.get_value("signal", "battery")
|
| 296 | + |
| 297 | + |
| 298 | +class FreeboxDeviceSensor(FreeboxSensor): |
| 299 | + """Representation of a Freebox device sensor.""" |
| 300 | + |
| 301 | + def __init__( |
| 302 | + self, |
| 303 | + router: FreeboxRouter, |
| 304 | + device: dict[str, Any], |
| 305 | + description: SensorEntityDescription, |
| 306 | + ) -> None: |
| 307 | + """Initialize a Freebox device sensor.""" |
| 308 | + super().__init__(router, description) |
| 309 | + self._device = device |
| 310 | + mac_address = device["l2ident"]["id"] |
| 311 | + self._attr_unique_id = f"{router.mac} {description.key} {mac_address}" |
| 312 | + self._attr_device_info = DeviceInfo( |
| 313 | + identifiers={(DOMAIN, mac_address)}, |
| 314 | + manufacturer=device["vendor_name"], |
| 315 | + name=device["primary_name"], |
| 316 | + via_device=(DOMAIN, router.mac), |
| 317 | + connections={(CONNECTION_NETWORK_MAC, mac_address)}, |
| 318 | + ) |
| 319 | + self._attr_name = f"{device['primary_name']} {description.name}" |
| 320 | + |
| 321 | + def async_update_state(self) -> None: |
| 322 | + """Update the Freebox device sensor.""" |
| 323 | + if self.entity_description.key == "connectivity": |
| 324 | + self._attr_native_value = get_device_connectity_type(self._device) |
| 325 | + elif self.entity_description.key == "wifi_signal_dbm": |
| 326 | + self._attr_native_value = get_device_wifi_signal_strength_dbm(self._device) |
| 327 | + elif self.entity_description.key == "wifi_signal_percentage": |
| 328 | + self._attr_native_value = get_device_wifi_signal_strength_percentage( |
| 329 | + self._device |
| 330 | + ) |
| 331 | + |
| 332 | + |
| 333 | +def get_device_connectity_type(device: dict[str, Any]) -> str | None: |
| 334 | + """Get the connectivity type of a device.""" |
| 335 | + result = None |
| 336 | + access_point = device.get("access_point", {}) |
| 337 | + if connectivity_type := access_point.get("connectivity_type"): |
| 338 | + if connectivity_type == "wifi": |
| 339 | + wifi_information = access_point.get("wifi_information", {}) |
| 340 | + band = wifi_information.get("band", "") |
| 341 | + result = WIFI_BANDS_TO_CONNECTIVITY.get(band, DeviceConnectivityType.WIFI) |
| 342 | + if connectivity_type == "ethernet": |
| 343 | + result = DeviceConnectivityType.ETHERNET |
| 344 | + return result.value if result else None |
| 345 | + |
| 346 | + |
| 347 | +def get_device_wifi_signal_strength_dbm(device: dict[str, Any]) -> int | None: |
| 348 | + """Get the wifi signal strength of a device in dBm.""" |
| 349 | + access_point = device.get("access_point", {}) |
| 350 | + wifi_information = access_point.get("wifi_information", {}) |
| 351 | + return wifi_information.get("signal") |
| 352 | + |
| 353 | + |
| 354 | +def get_device_wifi_signal_strength_percentage(device: dict[str, Any]) -> int | None: |
| 355 | + """Get the wifi signal strength of a device in percentage.""" |
| 356 | + if dbm := get_device_wifi_signal_strength_dbm(device): |
| 357 | + return min(max(2 * (dbm + 100), 0), 100) |
| 358 | + return None |
0 commit comments