Improve devolo_home_network generic typing (#85328)

This commit is contained in:
Marc Mueller 2023-01-07 14:12:03 +01:00 committed by GitHub
parent b27e89b40e
commit e99840f82c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 60 additions and 25 deletions

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
from typing import Any
import async_timeout import async_timeout
from devolo_plc_api import Device from devolo_plc_api import Device
@ -80,7 +81,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Disconnect from device.""" """Disconnect from device."""
await device.async_disconnect() await device.async_disconnect()
coordinators: dict[str, DataUpdateCoordinator] = {} coordinators: dict[str, DataUpdateCoordinator[Any]] = {}
if device.plcnet: if device.plcnet:
coordinators[CONNECTED_PLC_DEVICES] = DataUpdateCoordinator( coordinators[CONNECTED_PLC_DEVICES] = DataUpdateCoordinator(
hass, hass,

View File

@ -3,8 +3,10 @@ from __future__ import annotations
from collections.abc import Callable from collections.abc import Callable
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any
from devolo_plc_api import Device from devolo_plc_api import Device
from devolo_plc_api.plcnet_api import LogicalNetwork
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass, BinarySensorDeviceClass,
@ -62,9 +64,9 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Get all devices and sensors and setup them via config entry.""" """Get all devices and sensors and setup them via config entry."""
device: Device = hass.data[DOMAIN][entry.entry_id]["device"] device: Device = hass.data[DOMAIN][entry.entry_id]["device"]
coordinators: dict[str, DataUpdateCoordinator] = hass.data[DOMAIN][entry.entry_id][ coordinators: dict[str, DataUpdateCoordinator[Any]] = hass.data[DOMAIN][
"coordinators" entry.entry_id
] ]["coordinators"]
entities: list[BinarySensorEntity] = [] entities: list[BinarySensorEntity] = []
if device.plcnet: if device.plcnet:
@ -79,12 +81,12 @@ async def async_setup_entry(
async_add_entities(entities) async_add_entities(entities)
class DevoloBinarySensorEntity(DevoloEntity, BinarySensorEntity): class DevoloBinarySensorEntity(DevoloEntity[LogicalNetwork], BinarySensorEntity):
"""Representation of a devolo binary sensor.""" """Representation of a devolo binary sensor."""
def __init__( def __init__(
self, self,
coordinator: DataUpdateCoordinator, coordinator: DataUpdateCoordinator[LogicalNetwork],
description: DevoloBinarySensorEntityDescription, description: DevoloBinarySensorEntityDescription,
device: Device, device: Device,
device_name: str, device_name: str,

View File

@ -88,7 +88,10 @@ class DevoloScannerEntity(
"""Representation of a devolo device tracker.""" """Representation of a devolo device tracker."""
def __init__( def __init__(
self, coordinator: DataUpdateCoordinator, device: Device, mac: str self,
coordinator: DataUpdateCoordinator[list[ConnectedStationInfo]],
device: Device,
mac: str,
) -> None: ) -> None:
"""Initialize entity.""" """Initialize entity."""
super().__init__(coordinator) super().__init__(coordinator)

View File

@ -1,7 +1,11 @@
"""Generic platform.""" """Generic platform."""
from __future__ import annotations from __future__ import annotations
from typing import TypeVar, Union
from devolo_plc_api.device import Device from devolo_plc_api.device import Device
from devolo_plc_api.device_api import ConnectedStationInfo, NeighborAPInfo
from devolo_plc_api.plcnet_api import LogicalNetwork
from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import ( from homeassistant.helpers.update_coordinator import (
@ -11,14 +15,26 @@ from homeassistant.helpers.update_coordinator import (
from .const import DOMAIN from .const import DOMAIN
_DataT = TypeVar(
"_DataT",
bound=Union[
LogicalNetwork,
list[ConnectedStationInfo],
list[NeighborAPInfo],
],
)
class DevoloEntity(CoordinatorEntity):
class DevoloEntity(CoordinatorEntity[DataUpdateCoordinator[_DataT]]):
"""Representation of a devolo home network device.""" """Representation of a devolo home network device."""
_attr_has_entity_name = True _attr_has_entity_name = True
def __init__( def __init__(
self, coordinator: DataUpdateCoordinator, device: Device, device_name: str self,
coordinator: DataUpdateCoordinator[_DataT],
device: Device,
device_name: str,
) -> None: ) -> None:
"""Initialize a devolo home network device.""" """Initialize a devolo home network device."""
super().__init__(coordinator) super().__init__(coordinator)

View File

@ -3,9 +3,11 @@ from __future__ import annotations
from collections.abc import Callable from collections.abc import Callable
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any from typing import Any, Generic, TypeVar, Union
from devolo_plc_api.device import Device from devolo_plc_api.device import Device
from devolo_plc_api.device_api import ConnectedStationInfo, NeighborAPInfo
from devolo_plc_api.plcnet_api import LogicalNetwork
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
SensorEntity, SensorEntity,
@ -26,23 +28,32 @@ from .const import (
) )
from .entity import DevoloEntity from .entity import DevoloEntity
_DataT = TypeVar(
"_DataT",
bound=Union[
LogicalNetwork,
list[ConnectedStationInfo],
list[NeighborAPInfo],
],
)
@dataclass @dataclass
class DevoloSensorRequiredKeysMixin: class DevoloSensorRequiredKeysMixin(Generic[_DataT]):
"""Mixin for required keys.""" """Mixin for required keys."""
value_func: Callable[[Any], int] value_func: Callable[[_DataT], int]
@dataclass @dataclass
class DevoloSensorEntityDescription( class DevoloSensorEntityDescription(
SensorEntityDescription, DevoloSensorRequiredKeysMixin SensorEntityDescription, DevoloSensorRequiredKeysMixin[_DataT]
): ):
"""Describes devolo sensor entity.""" """Describes devolo sensor entity."""
SENSOR_TYPES: dict[str, DevoloSensorEntityDescription] = { SENSOR_TYPES: dict[str, DevoloSensorEntityDescription[Any]] = {
CONNECTED_PLC_DEVICES: DevoloSensorEntityDescription( CONNECTED_PLC_DEVICES: DevoloSensorEntityDescription[LogicalNetwork](
key=CONNECTED_PLC_DEVICES, key=CONNECTED_PLC_DEVICES,
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
@ -52,7 +63,7 @@ SENSOR_TYPES: dict[str, DevoloSensorEntityDescription] = {
{device.mac_address_from for device in data.data_rates} {device.mac_address_from for device in data.data_rates}
), ),
), ),
CONNECTED_WIFI_CLIENTS: DevoloSensorEntityDescription( CONNECTED_WIFI_CLIENTS: DevoloSensorEntityDescription[list[ConnectedStationInfo]](
key=CONNECTED_WIFI_CLIENTS, key=CONNECTED_WIFI_CLIENTS,
entity_registry_enabled_default=True, entity_registry_enabled_default=True,
icon="mdi:wifi", icon="mdi:wifi",
@ -60,7 +71,7 @@ SENSOR_TYPES: dict[str, DevoloSensorEntityDescription] = {
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
value_func=len, value_func=len,
), ),
NEIGHBORING_WIFI_NETWORKS: DevoloSensorEntityDescription( NEIGHBORING_WIFI_NETWORKS: DevoloSensorEntityDescription[list[NeighborAPInfo]](
key=NEIGHBORING_WIFI_NETWORKS, key=NEIGHBORING_WIFI_NETWORKS,
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
@ -76,11 +87,11 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Get all devices and sensors and setup them via config entry.""" """Get all devices and sensors and setup them via config entry."""
device: Device = hass.data[DOMAIN][entry.entry_id]["device"] device: Device = hass.data[DOMAIN][entry.entry_id]["device"]
coordinators: dict[str, DataUpdateCoordinator] = hass.data[DOMAIN][entry.entry_id][ coordinators: dict[str, DataUpdateCoordinator[Any]] = hass.data[DOMAIN][
"coordinators" entry.entry_id
] ]["coordinators"]
entities: list[DevoloSensorEntity] = [] entities: list[DevoloSensorEntity[Any]] = []
if device.plcnet: if device.plcnet:
entities.append( entities.append(
DevoloSensorEntity( DevoloSensorEntity(
@ -110,18 +121,20 @@ async def async_setup_entry(
async_add_entities(entities) async_add_entities(entities)
class DevoloSensorEntity(DevoloEntity, SensorEntity): class DevoloSensorEntity(DevoloEntity[_DataT], SensorEntity):
"""Representation of a devolo sensor.""" """Representation of a devolo sensor."""
entity_description: DevoloSensorEntityDescription[_DataT]
def __init__( def __init__(
self, self,
coordinator: DataUpdateCoordinator, coordinator: DataUpdateCoordinator[_DataT],
description: DevoloSensorEntityDescription, description: DevoloSensorEntityDescription[_DataT],
device: Device, device: Device,
device_name: str, device_name: str,
) -> None: ) -> None:
"""Initialize entity.""" """Initialize entity."""
self.entity_description: DevoloSensorEntityDescription = description self.entity_description = description
super().__init__(coordinator, device, device_name) super().__init__(coordinator, device, device_name)
@property @property