From 98c9edc00c985a9328e5f9596462be839a5644ac Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Thu, 14 Sep 2023 12:06:40 +0200 Subject: [PATCH] Netgear cleanup (#99505) Co-authored-by: Robert Resch Co-authored-by: Joost Lekkerkerker --- .coveragerc | 1 + homeassistant/components/netgear/__init__.py | 19 +-- homeassistant/components/netgear/button.py | 7 +- .../components/netgear/device_tracker.py | 8 +- homeassistant/components/netgear/entity.py | 107 +++++++++++++ homeassistant/components/netgear/router.py | 143 +----------------- homeassistant/components/netgear/sensor.py | 13 +- homeassistant/components/netgear/switch.py | 10 +- homeassistant/components/netgear/update.py | 6 +- 9 files changed, 132 insertions(+), 182 deletions(-) create mode 100644 homeassistant/components/netgear/entity.py diff --git a/.coveragerc b/.coveragerc index 305d02f2dbd..4835ec5a05b 100644 --- a/.coveragerc +++ b/.coveragerc @@ -793,6 +793,7 @@ omit = homeassistant/components/netgear/__init__.py homeassistant/components/netgear/button.py homeassistant/components/netgear/device_tracker.py + homeassistant/components/netgear/entity.py homeassistant/components/netgear/router.py homeassistant/components/netgear/sensor.py homeassistant/components/netgear/switch.py diff --git a/homeassistant/components/netgear/__init__.py b/homeassistant/components/netgear/__init__.py index 522b60749d0..b21286ff05b 100644 --- a/homeassistant/components/netgear/__init__.py +++ b/homeassistant/components/netgear/__init__.py @@ -6,7 +6,7 @@ import logging from typing import Any from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_HOST, CONF_PORT, CONF_SSL +from homeassistant.const import CONF_PORT, CONF_SSL from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import device_registry as dr, entity_registry as er @@ -62,23 +62,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: entry.async_on_unload(entry.add_update_listener(update_listener)) - configuration_url = None - if host := entry.data[CONF_HOST]: - configuration_url = f"http://{host}/" - - assert entry.unique_id - device_registry = dr.async_get(hass) - device_registry.async_get_or_create( - config_entry_id=entry.entry_id, - identifiers={(DOMAIN, entry.unique_id)}, - manufacturer="Netgear", - name=router.device_name, - model=router.model, - sw_version=router.firmware_version, - hw_version=router.hardware_version, - configuration_url=configuration_url, - ) - async def async_update_devices() -> bool: """Fetch data from the router.""" if router.track_devices: diff --git a/homeassistant/components/netgear/button.py b/homeassistant/components/netgear/button.py index e45e0582d69..f3283f8d7b5 100644 --- a/homeassistant/components/netgear/button.py +++ b/homeassistant/components/netgear/button.py @@ -15,7 +15,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from .const import DOMAIN, KEY_COORDINATOR, KEY_ROUTER -from .router import NetgearRouter, NetgearRouterCoordinatorEntity +from .entity import NetgearRouterCoordinatorEntity +from .router import NetgearRouter @dataclass @@ -35,7 +36,6 @@ class NetgearButtonEntityDescription( BUTTONS = [ NetgearButtonEntityDescription( key="reboot", - name="Reboot", device_class=ButtonDeviceClass.RESTART, entity_category=EntityCategory.CONFIG, action=lambda router: router.async_reboot, @@ -69,8 +69,7 @@ class NetgearRouterButtonEntity(NetgearRouterCoordinatorEntity, ButtonEntity): """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}" + self._attr_unique_id = f"{router.serial_number}-{entity_description.key}" async def async_press(self) -> None: """Triggers the button press service.""" diff --git a/homeassistant/components/netgear/device_tracker.py b/homeassistant/components/netgear/device_tracker.py index ffb33d5ebeb..38ad024a2c4 100644 --- a/homeassistant/components/netgear/device_tracker.py +++ b/homeassistant/components/netgear/device_tracker.py @@ -10,7 +10,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from .const import DEVICE_ICONS, DOMAIN, KEY_COORDINATOR, KEY_ROUTER -from .router import NetgearBaseEntity, NetgearRouter +from .entity import NetgearDeviceEntity +from .router import NetgearRouter _LOGGER = logging.getLogger(__name__) @@ -46,9 +47,11 @@ async def async_setup_entry( new_device_callback() -class NetgearScannerEntity(NetgearBaseEntity, ScannerEntity): +class NetgearScannerEntity(NetgearDeviceEntity, ScannerEntity): """Representation of a device connected to a Netgear router.""" + _attr_has_entity_name = False + def __init__( self, coordinator: DataUpdateCoordinator, router: NetgearRouter, device: dict ) -> None: @@ -56,6 +59,7 @@ class NetgearScannerEntity(NetgearBaseEntity, ScannerEntity): super().__init__(coordinator, router, device) self._hostname = self.get_hostname() self._icon = DEVICE_ICONS.get(device["device_type"], "mdi:help-network") + self._attr_name = self._device_name def get_hostname(self) -> str | None: """Return the hostname of the given device or None if we don't know.""" diff --git a/homeassistant/components/netgear/entity.py b/homeassistant/components/netgear/entity.py new file mode 100644 index 00000000000..45418681db0 --- /dev/null +++ b/homeassistant/components/netgear/entity.py @@ -0,0 +1,107 @@ +"""Represent the Netgear router and its devices.""" +from __future__ import annotations + +from abc import abstractmethod + +from homeassistant.const import CONF_HOST +from homeassistant.core import callback +from homeassistant.helpers import device_registry as dr +from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.entity import Entity +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, + DataUpdateCoordinator, +) + +from .const import DOMAIN +from .router import NetgearRouter + + +class NetgearDeviceEntity(CoordinatorEntity): + """Base class for a device connected to a Netgear router.""" + + _attr_has_entity_name = True + + def __init__( + self, coordinator: DataUpdateCoordinator, router: NetgearRouter, device: dict + ) -> None: + """Initialize a Netgear device.""" + super().__init__(coordinator) + self._router = router + self._device = device + self._mac = device["mac"] + self._device_name = self.get_device_name() + self._active = device["active"] + self._attr_unique_id = self._mac + self._attr_device_info = DeviceInfo( + connections={(dr.CONNECTION_NETWORK_MAC, self._mac)}, + default_name=self._device_name, + default_model=device["device_model"], + via_device=(DOMAIN, router.unique_id), + ) + + def get_device_name(self): + """Return the name of the given device or the MAC if we don't know.""" + name = self._device["name"] + if not name or name == "--": + name = self._mac + + return name + + @abstractmethod + @callback + def async_update_device(self) -> None: + """Update the Netgear device.""" + + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + self.async_update_device() + super()._handle_coordinator_update() + + +class NetgearRouterEntity(Entity): + """Base class for a Netgear router entity without coordinator.""" + + _attr_has_entity_name = True + + def __init__(self, router: NetgearRouter) -> None: + """Initialize a Netgear device.""" + self._router = router + + configuration_url = None + if host := router.entry.data[CONF_HOST]: + configuration_url = f"http://{host}/" + + self._attr_unique_id = router.serial_number + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, router.unique_id)}, + manufacturer="Netgear", + name=router.device_name, + model=router.model, + sw_version=router.firmware_version, + hw_version=router.hardware_version, + configuration_url=configuration_url, + ) + + +class NetgearRouterCoordinatorEntity(NetgearRouterEntity, CoordinatorEntity): + """Base class for a Netgear router entity.""" + + def __init__( + self, coordinator: DataUpdateCoordinator, router: NetgearRouter + ) -> None: + """Initialize a Netgear device.""" + CoordinatorEntity.__init__(self, coordinator) + NetgearRouterEntity.__init__(self, router) + + @abstractmethod + @callback + def async_update_device(self) -> None: + """Update the Netgear device.""" + + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + self.async_update_device() + super()._handle_coordinator_update() diff --git a/homeassistant/components/netgear/router.py b/homeassistant/components/netgear/router.py index 2dc86833003..3c3be7fe9fb 100644 --- a/homeassistant/components/netgear/router.py +++ b/homeassistant/components/netgear/router.py @@ -1,7 +1,6 @@ """Represent the Netgear router and its devices.""" from __future__ import annotations -from abc import abstractmethod import asyncio from datetime import timedelta import logging @@ -17,14 +16,8 @@ from homeassistant.const import ( CONF_SSL, CONF_USERNAME, ) -from homeassistant.core import HomeAssistant, callback +from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr -from homeassistant.helpers.device_registry import DeviceInfo -from homeassistant.helpers.entity import Entity -from homeassistant.helpers.update_coordinator import ( - CoordinatorEntity, - DataUpdateCoordinator, -) from homeassistant.util import dt as dt_util from .const import ( @@ -275,137 +268,3 @@ class NetgearRouter: def ssl(self) -> bool: """SSL used by the API.""" return self.api.ssl - - -class NetgearBaseEntity(CoordinatorEntity): - """Base class for a device connected to a Netgear router.""" - - def __init__( - self, coordinator: DataUpdateCoordinator, router: NetgearRouter, device: dict - ) -> None: - """Initialize a Netgear device.""" - super().__init__(coordinator) - self._router = router - self._device = device - self._mac = device["mac"] - self._name = self.get_device_name() - self._device_name = self._name - self._active = device["active"] - - def get_device_name(self): - """Return the name of the given device or the MAC if we don't know.""" - name = self._device["name"] - if not name or name == "--": - name = self._mac - - return name - - @abstractmethod - @callback - def async_update_device(self) -> None: - """Update the Netgear device.""" - - @callback - def _handle_coordinator_update(self) -> None: - """Handle updated data from the coordinator.""" - self.async_update_device() - super()._handle_coordinator_update() - - @property - def name(self) -> str: - """Return the name.""" - return self._name - - -class NetgearDeviceEntity(NetgearBaseEntity): - """Base class for a device connected to a Netgear router.""" - - def __init__( - self, coordinator: DataUpdateCoordinator, router: NetgearRouter, device: dict - ) -> None: - """Initialize a Netgear device.""" - super().__init__(coordinator, router, device) - self._unique_id = self._mac - - @property - def unique_id(self) -> str: - """Return a unique ID.""" - return self._unique_id - - @property - def device_info(self) -> DeviceInfo: - """Return the device information.""" - return DeviceInfo( - connections={(dr.CONNECTION_NETWORK_MAC, self._mac)}, - default_name=self._device_name, - default_model=self._device["device_model"], - via_device=(DOMAIN, self._router.unique_id), - ) - - -class NetgearRouterCoordinatorEntity(CoordinatorEntity): - """Base class for a Netgear router entity.""" - - def __init__( - self, coordinator: DataUpdateCoordinator, router: NetgearRouter - ) -> None: - """Initialize a Netgear device.""" - super().__init__(coordinator) - self._router = router - self._name = router.device_name - self._unique_id = router.serial_number - - @abstractmethod - @callback - def async_update_device(self) -> None: - """Update the Netgear device.""" - - @callback - def _handle_coordinator_update(self) -> None: - """Handle updated data from the coordinator.""" - self.async_update_device() - super()._handle_coordinator_update() - - @property - def unique_id(self) -> str: - """Return a unique ID.""" - return self._unique_id - - @property - def name(self) -> str: - """Return the name.""" - return self._name - - @property - def device_info(self) -> DeviceInfo: - """Return the device information.""" - return DeviceInfo( - identifiers={(DOMAIN, self._router.unique_id)}, - ) - - -class NetgearRouterEntity(Entity): - """Base class for a Netgear router entity without coordinator.""" - - def __init__(self, router: NetgearRouter) -> None: - """Initialize a Netgear device.""" - self._router = router - self._name = router.device_name - self._unique_id = router.serial_number - - @property - def unique_id(self) -> str: - """Return a unique ID.""" - return self._unique_id - - @property - def name(self) -> str: - """Return the name.""" - return self._name - - @property - def device_info(self) -> DeviceInfo: - """Return the device information.""" - return DeviceInfo( - identifiers={(DOMAIN, self._router.unique_id)}, - ) diff --git a/homeassistant/components/netgear/sensor.py b/homeassistant/components/netgear/sensor.py index 239eca5ff83..0de98515a87 100644 --- a/homeassistant/components/netgear/sensor.py +++ b/homeassistant/components/netgear/sensor.py @@ -36,7 +36,8 @@ from .const import ( KEY_COORDINATOR_UTIL, KEY_ROUTER, ) -from .router import NetgearDeviceEntity, NetgearRouter, NetgearRouterCoordinatorEntity +from .entity import NetgearDeviceEntity, NetgearRouterCoordinatorEntity +from .router import NetgearRouter _LOGGER = logging.getLogger(__name__) @@ -379,10 +380,9 @@ class NetgearSensorEntity(NetgearDeviceEntity, SensorEntity): """Initialize a Netgear device.""" super().__init__(coordinator, router, device) 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}" - self._state = self._device.get(self._attribute) + self.entity_description = SENSOR_TYPES[attribute] + self._attr_unique_id = f"{self._mac}-{attribute}" + self._state = device.get(attribute) @property def native_value(self): @@ -413,8 +413,7 @@ class NetgearRouterSensorEntity(NetgearRouterCoordinatorEntity, RestoreSensor): """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._attr_unique_id = f"{router.serial_number}-{entity_description.key}-{entity_description.index}" self._value: StateType | date | datetime | Decimal = None self.async_update_device() diff --git a/homeassistant/components/netgear/switch.py b/homeassistant/components/netgear/switch.py index 88a89dd32c9..f594506cbfb 100644 --- a/homeassistant/components/netgear/switch.py +++ b/homeassistant/components/netgear/switch.py @@ -15,7 +15,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from .const import DOMAIN, KEY_COORDINATOR, KEY_ROUTER -from .router import NetgearDeviceEntity, NetgearRouter, NetgearRouterEntity +from .entity import NetgearDeviceEntity, NetgearRouterEntity +from .router import NetgearRouter _LOGGER = logging.getLogger(__name__) @@ -166,9 +167,7 @@ class NetgearAllowBlock(NetgearDeviceEntity, SwitchEntity): """Initialize a Netgear device.""" super().__init__(coordinator, router, device) self.entity_description = entity_description - self._name = f"{self.get_device_name()} {self.entity_description.name}" - self._unique_id = f"{self._mac}-{self.entity_description.key}" - self._attr_is_on = None + self._attr_unique_id = f"{self._mac}-{entity_description.key}" self.async_update_device() async def async_turn_on(self, **kwargs: Any) -> None: @@ -206,8 +205,7 @@ class NetgearRouterSwitchEntity(NetgearRouterEntity, SwitchEntity): """Initialize a Netgear device.""" super().__init__(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}" + self._attr_unique_id = f"{router.serial_number}-{entity_description.key}" self._attr_is_on = None self._attr_available = False diff --git a/homeassistant/components/netgear/update.py b/homeassistant/components/netgear/update.py index b0e9a26864b..78e11e7c174 100644 --- a/homeassistant/components/netgear/update.py +++ b/homeassistant/components/netgear/update.py @@ -15,7 +15,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from .const import DOMAIN, KEY_COORDINATOR_FIRMWARE, KEY_ROUTER -from .router import NetgearRouter, NetgearRouterCoordinatorEntity +from .entity import NetgearRouterCoordinatorEntity +from .router import NetgearRouter LOGGER = logging.getLogger(__name__) @@ -44,8 +45,7 @@ class NetgearUpdateEntity(NetgearRouterCoordinatorEntity, UpdateEntity): ) -> None: """Initialize a Netgear device.""" super().__init__(coordinator, router) - self._name = f"{router.device_name} Update" - self._unique_id = f"{router.serial_number}-update" + self._attr_unique_id = f"{router.serial_number}-update" @property def installed_version(self) -> str | None: