2021-09-13 16:18:21 +00:00
|
|
|
"""Support for Netgear routers."""
|
2022-02-04 17:36:56 +00:00
|
|
|
from collections.abc import Callable
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
2021-09-13 16:18:21 +00:00
|
|
|
from homeassistant.components.sensor import (
|
2021-12-16 11:16:56 +00:00
|
|
|
SensorDeviceClass,
|
2021-09-13 16:18:21 +00:00
|
|
|
SensorEntity,
|
|
|
|
SensorEntityDescription,
|
|
|
|
)
|
|
|
|
from homeassistant.config_entries import ConfigEntry
|
2022-02-04 17:36:56 +00:00
|
|
|
from homeassistant.const import DATA_MEGABYTES, PERCENTAGE
|
2021-11-06 18:48:02 +00:00
|
|
|
from homeassistant.core import HomeAssistant, callback
|
2021-12-18 11:34:16 +00:00
|
|
|
from homeassistant.helpers.entity import EntityCategory
|
2021-09-13 16:18:21 +00:00
|
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
2022-02-03 11:28:04 +00:00
|
|
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
2021-09-13 16:18:21 +00:00
|
|
|
|
2022-02-04 17:36:56 +00:00
|
|
|
from .const import DOMAIN, KEY_COORDINATOR, KEY_COORDINATOR_TRAFFIC, KEY_ROUTER
|
|
|
|
from .router import NetgearDeviceEntity, NetgearRouter, NetgearRouterEntity
|
2021-09-13 16:18:21 +00:00
|
|
|
|
|
|
|
SENSOR_TYPES = {
|
|
|
|
"type": SensorEntityDescription(
|
|
|
|
key="type",
|
|
|
|
name="link type",
|
2021-12-18 11:34:16 +00:00
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
2022-02-04 17:36:56 +00:00
|
|
|
icon="mdi:lan",
|
2021-09-13 16:18:21 +00:00
|
|
|
),
|
|
|
|
"link_rate": SensorEntityDescription(
|
|
|
|
key="link_rate",
|
|
|
|
name="link rate",
|
|
|
|
native_unit_of_measurement="Mbps",
|
2021-12-18 11:34:16 +00:00
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
2022-02-04 17:36:56 +00:00
|
|
|
icon="mdi:speedometer",
|
2021-09-13 16:18:21 +00:00
|
|
|
),
|
|
|
|
"signal": SensorEntityDescription(
|
|
|
|
key="signal",
|
|
|
|
name="signal strength",
|
|
|
|
native_unit_of_measurement=PERCENTAGE,
|
2021-12-16 11:16:56 +00:00
|
|
|
device_class=SensorDeviceClass.SIGNAL_STRENGTH,
|
2021-12-18 11:34:16 +00:00
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
2021-09-13 16:18:21 +00:00
|
|
|
),
|
2021-10-11 11:08:56 +00:00
|
|
|
"ssid": SensorEntityDescription(
|
|
|
|
key="ssid",
|
|
|
|
name="ssid",
|
2021-12-18 11:34:16 +00:00
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
2022-02-04 17:36:56 +00:00
|
|
|
icon="mdi:wifi-marker",
|
2021-10-11 11:08:56 +00:00
|
|
|
),
|
|
|
|
"conn_ap_mac": SensorEntityDescription(
|
|
|
|
key="conn_ap_mac",
|
|
|
|
name="access point mac",
|
2021-12-18 11:34:16 +00:00
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
2022-02-04 17:36:56 +00:00
|
|
|
icon="mdi:router-network",
|
2021-10-11 11:08:56 +00:00
|
|
|
),
|
2021-09-13 16:18:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-02-04 17:36:56 +00:00
|
|
|
@dataclass
|
|
|
|
class NetgearSensorEntityDescription(SensorEntityDescription):
|
|
|
|
"""Class describing Netgear sensor entities."""
|
|
|
|
|
|
|
|
value: Callable = lambda data: data
|
|
|
|
index: int = 0
|
|
|
|
|
|
|
|
|
|
|
|
SENSOR_TRAFFIC_TYPES = [
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewTodayUpload",
|
|
|
|
name="Upload today",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:upload",
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewTodayDownload",
|
|
|
|
name="Download today",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:download",
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewYesterdayUpload",
|
|
|
|
name="Upload yesterday",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:upload",
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewYesterdayDownload",
|
|
|
|
name="Download yesterday",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:download",
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewWeekUpload",
|
|
|
|
name="Upload week",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:upload",
|
|
|
|
index=0,
|
|
|
|
value=lambda data: data[0] if data is not None else None,
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewWeekUpload",
|
|
|
|
name="Upload week average",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:upload",
|
|
|
|
index=1,
|
|
|
|
value=lambda data: data[1] if data is not None else None,
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewWeekDownload",
|
|
|
|
name="Download week",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:download",
|
|
|
|
index=0,
|
|
|
|
value=lambda data: data[0] if data is not None else None,
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewWeekDownload",
|
|
|
|
name="Download week average",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:download",
|
|
|
|
index=1,
|
|
|
|
value=lambda data: data[1] if data is not None else None,
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewMonthUpload",
|
|
|
|
name="Upload month",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:upload",
|
|
|
|
index=0,
|
|
|
|
value=lambda data: data[0] if data is not None else None,
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewMonthUpload",
|
|
|
|
name="Upload month average",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:upload",
|
|
|
|
index=1,
|
|
|
|
value=lambda data: data[1] if data is not None else None,
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewMonthDownload",
|
|
|
|
name="Download month",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:download",
|
|
|
|
index=0,
|
|
|
|
value=lambda data: data[0] if data is not None else None,
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewMonthDownload",
|
|
|
|
name="Download month average",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:download",
|
|
|
|
index=1,
|
|
|
|
value=lambda data: data[1] if data is not None else None,
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewLastMonthUpload",
|
|
|
|
name="Upload last month",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:upload",
|
|
|
|
index=0,
|
|
|
|
value=lambda data: data[0] if data is not None else None,
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewLastMonthUpload",
|
|
|
|
name="Upload last month average",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:upload",
|
|
|
|
index=1,
|
|
|
|
value=lambda data: data[1] if data is not None else None,
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewLastMonthDownload",
|
|
|
|
name="Download last month",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:download",
|
|
|
|
index=0,
|
|
|
|
value=lambda data: data[0] if data is not None else None,
|
|
|
|
),
|
|
|
|
NetgearSensorEntityDescription(
|
|
|
|
key="NewLastMonthDownload",
|
|
|
|
name="Download last month average",
|
|
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
|
|
native_unit_of_measurement=DATA_MEGABYTES,
|
|
|
|
icon="mdi:download",
|
|
|
|
index=1,
|
|
|
|
value=lambda data: data[1] if data is not None else None,
|
|
|
|
),
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2021-09-13 16:18:21 +00:00
|
|
|
async def async_setup_entry(
|
2021-11-06 18:48:02 +00:00
|
|
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
2021-09-13 16:18:21 +00:00
|
|
|
) -> None:
|
|
|
|
"""Set up device tracker for Netgear component."""
|
2022-02-03 11:28:04 +00:00
|
|
|
router = hass.data[DOMAIN][entry.entry_id][KEY_ROUTER]
|
|
|
|
coordinator = hass.data[DOMAIN][entry.entry_id][KEY_COORDINATOR]
|
2022-02-04 17:36:56 +00:00
|
|
|
coordinator_traffic = hass.data[DOMAIN][entry.entry_id][KEY_COORDINATOR_TRAFFIC]
|
|
|
|
|
|
|
|
# Router entities
|
|
|
|
router_entities = []
|
2021-09-13 16:18:21 +00:00
|
|
|
|
2022-02-04 17:36:56 +00:00
|
|
|
for description in SENSOR_TRAFFIC_TYPES:
|
|
|
|
router_entities.append(
|
|
|
|
NetgearRouterSensorEntity(coordinator_traffic, router, description)
|
|
|
|
)
|
|
|
|
|
|
|
|
async_add_entities(router_entities)
|
|
|
|
|
|
|
|
# Entities per network device
|
|
|
|
tracked = set()
|
2022-02-03 11:28:04 +00:00
|
|
|
sensors = ["type", "link_rate", "signal"]
|
|
|
|
if router.method_version == 2:
|
|
|
|
sensors.extend(["ssid", "conn_ap_mac"])
|
2021-10-11 11:08:56 +00:00
|
|
|
|
2022-02-03 11:28:04 +00:00
|
|
|
@callback
|
|
|
|
def new_device_callback() -> None:
|
|
|
|
"""Add new devices if needed."""
|
|
|
|
if not coordinator.data:
|
|
|
|
return
|
|
|
|
|
|
|
|
new_entities = []
|
|
|
|
|
|
|
|
for mac, device in router.devices.items():
|
|
|
|
if mac in tracked:
|
|
|
|
continue
|
|
|
|
|
|
|
|
new_entities.extend(
|
|
|
|
[
|
|
|
|
NetgearSensorEntity(coordinator, router, device, attribute)
|
|
|
|
for attribute in sensors
|
|
|
|
]
|
|
|
|
)
|
|
|
|
tracked.add(mac)
|
2021-09-13 16:18:21 +00:00
|
|
|
|
2022-02-03 11:28:04 +00:00
|
|
|
if new_entities:
|
|
|
|
async_add_entities(new_entities)
|
|
|
|
|
|
|
|
entry.async_on_unload(coordinator.async_add_listener(new_device_callback))
|
|
|
|
|
|
|
|
coordinator.data = True
|
|
|
|
new_device_callback()
|
2021-09-13 16:18:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
class NetgearSensorEntity(NetgearDeviceEntity, SensorEntity):
|
|
|
|
"""Representation of a device connected to a Netgear router."""
|
|
|
|
|
|
|
|
_attr_entity_registry_enabled_default = False
|
|
|
|
|
2022-02-03 11:28:04 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
coordinator: DataUpdateCoordinator,
|
|
|
|
router: NetgearRouter,
|
|
|
|
device: dict,
|
|
|
|
attribute: str,
|
|
|
|
) -> None:
|
2021-09-13 16:18:21 +00:00
|
|
|
"""Initialize a Netgear device."""
|
2022-02-03 11:28:04 +00:00
|
|
|
super().__init__(coordinator, router, device)
|
2021-09-13 16:18:21 +00:00
|
|
|
self._attribute = attribute
|
|
|
|
self.entity_description = SENSOR_TYPES[self._attribute]
|
|
|
|
self._name = f"{self.get_device_name()} {self.entity_description.name}"
|
|
|
|
self._unique_id = f"{self._mac}-{self._attribute}"
|
2021-11-17 10:49:12 +00:00
|
|
|
self._state = self._device.get(self._attribute)
|
2021-09-13 16:18:21 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def native_value(self):
|
|
|
|
"""Return the state of the sensor."""
|
|
|
|
return self._state
|
|
|
|
|
|
|
|
@callback
|
|
|
|
def async_update_device(self) -> None:
|
|
|
|
"""Update the Netgear device."""
|
|
|
|
self._device = self._router.devices[self._mac]
|
|
|
|
self._active = self._device["active"]
|
2021-11-17 10:49:12 +00:00
|
|
|
if self._device.get(self._attribute) is not None:
|
2021-09-13 16:18:21 +00:00
|
|
|
self._state = self._device[self._attribute]
|
2022-02-04 17:36:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
class NetgearRouterSensorEntity(NetgearRouterEntity, SensorEntity):
|
|
|
|
"""Representation of a device connected to a Netgear router."""
|
|
|
|
|
|
|
|
_attr_entity_registry_enabled_default = False
|
|
|
|
entity_description: NetgearSensorEntityDescription
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
coordinator: DataUpdateCoordinator,
|
|
|
|
router: NetgearRouter,
|
|
|
|
entity_description: NetgearSensorEntityDescription,
|
|
|
|
) -> None:
|
|
|
|
"""Initialize a Netgear device."""
|
|
|
|
super().__init__(coordinator, router)
|
|
|
|
self.entity_description = entity_description
|
|
|
|
self._name = f"{router.device_name} {entity_description.name}"
|
|
|
|
self._unique_id = f"{router.serial_number}-{entity_description.key}-{entity_description.index}"
|
|
|
|
|
|
|
|
self._value = None
|
|
|
|
self.async_update_device()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def native_value(self):
|
|
|
|
"""Return the state of the sensor."""
|
|
|
|
return self._value
|
|
|
|
|
|
|
|
@callback
|
|
|
|
def async_update_device(self) -> None:
|
|
|
|
"""Update the Netgear device."""
|
|
|
|
if self.coordinator.data is not None:
|
|
|
|
data = self.coordinator.data.get(self.entity_description.key)
|
|
|
|
self._value = self.entity_description.value(data)
|