mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Implement generic in Deconz base device (#76015)
* Make DevonzBase a generic * Adjust alarm_control_panel * Adjust binary_sensor * Adjust climate * More platforms * Adjust light * Ignore type-var * Add space * Implement recommendation * Use type: ignore[union-attr] * Revert "Use type: ignore[union-attr]" This reverts commit 983443062aab0a9c599b2750d823d0c5148c05ce. * Adjust assert * Adjust lock * Rename type variables * type: ignore[union-attr] * Formatting Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
This commit is contained in:
parent
567f181a21
commit
deff0ad61e
@ -80,11 +80,10 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
|
||||
class DeconzAlarmControlPanel(DeconzDevice, AlarmControlPanelEntity):
|
||||
class DeconzAlarmControlPanel(DeconzDevice[AncillaryControl], AlarmControlPanelEntity):
|
||||
"""Representation of a deCONZ alarm control panel."""
|
||||
|
||||
TYPE = DOMAIN
|
||||
_device: AncillaryControl
|
||||
|
||||
_attr_code_format = CodeFormat.NUMBER
|
||||
_attr_supported_features = (
|
||||
|
@ -233,11 +233,10 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
|
||||
class DeconzBinarySensor(DeconzDevice, BinarySensorEntity):
|
||||
class DeconzBinarySensor(DeconzDevice[SensorResources], BinarySensorEntity):
|
||||
"""Representation of a deCONZ binary sensor."""
|
||||
|
||||
TYPE = DOMAIN
|
||||
_device: SensorResources
|
||||
entity_description: DeconzBinarySensorDescription
|
||||
|
||||
def __init__(
|
||||
|
@ -92,11 +92,10 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
|
||||
class DeconzThermostat(DeconzDevice, ClimateEntity):
|
||||
class DeconzThermostat(DeconzDevice[Thermostat], ClimateEntity):
|
||||
"""Representation of a deCONZ thermostat."""
|
||||
|
||||
TYPE = DOMAIN
|
||||
_device: Thermostat
|
||||
|
||||
_attr_temperature_unit = TEMP_CELSIUS
|
||||
|
||||
|
@ -49,11 +49,10 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
|
||||
class DeconzCover(DeconzDevice, CoverEntity):
|
||||
class DeconzCover(DeconzDevice[Cover], CoverEntity):
|
||||
"""Representation of a deCONZ cover."""
|
||||
|
||||
TYPE = DOMAIN
|
||||
_device: Cover
|
||||
|
||||
def __init__(self, cover_id: str, gateway: DeconzGateway) -> None:
|
||||
"""Set up cover device."""
|
||||
|
@ -2,10 +2,13 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pydeconz.models.group import Group as DeconzGroup
|
||||
from pydeconz.models.light import LightBase as DeconzLight
|
||||
from typing import Generic, TypeVar, Union
|
||||
|
||||
from pydeconz.models.deconz_device import DeconzDevice as PydeconzDevice
|
||||
from pydeconz.models.group import Group as PydeconzGroup
|
||||
from pydeconz.models.light import LightBase as PydeconzLightBase
|
||||
from pydeconz.models.scene import Scene as PydeconzScene
|
||||
from pydeconz.models.sensor import SensorBase as DeconzSensor
|
||||
from pydeconz.models.sensor import SensorBase as PydeconzSensorBase
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE
|
||||
@ -15,29 +18,39 @@ from homeassistant.helpers.entity import DeviceInfo, Entity
|
||||
from .const import DOMAIN as DECONZ_DOMAIN
|
||||
from .gateway import DeconzGateway
|
||||
|
||||
_DeviceT = TypeVar(
|
||||
"_DeviceT",
|
||||
bound=Union[
|
||||
PydeconzGroup,
|
||||
PydeconzLightBase,
|
||||
PydeconzSensorBase,
|
||||
PydeconzScene,
|
||||
],
|
||||
)
|
||||
|
||||
class DeconzBase:
|
||||
|
||||
class DeconzBase(Generic[_DeviceT]):
|
||||
"""Common base for deconz entities and events."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device: DeconzGroup | DeconzLight | DeconzSensor | PydeconzScene,
|
||||
device: _DeviceT,
|
||||
gateway: DeconzGateway,
|
||||
) -> None:
|
||||
"""Set up device and add update callback to get data from websocket."""
|
||||
self._device = device
|
||||
self._device: _DeviceT = device
|
||||
self.gateway = gateway
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return a unique identifier for this device."""
|
||||
assert not isinstance(self._device, PydeconzScene)
|
||||
assert isinstance(self._device, PydeconzDevice)
|
||||
return self._device.unique_id
|
||||
|
||||
@property
|
||||
def serial(self) -> str | None:
|
||||
"""Return a serial number for this device."""
|
||||
assert not isinstance(self._device, PydeconzScene)
|
||||
assert isinstance(self._device, PydeconzDevice)
|
||||
if not self._device.unique_id or self._device.unique_id.count(":") != 7:
|
||||
return None
|
||||
return self._device.unique_id.split("-", 1)[0]
|
||||
@ -45,7 +58,7 @@ class DeconzBase:
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo | None:
|
||||
"""Return a device description for device registry."""
|
||||
assert not isinstance(self._device, PydeconzScene)
|
||||
assert isinstance(self._device, PydeconzDevice)
|
||||
if self.serial is None:
|
||||
return None
|
||||
|
||||
@ -60,7 +73,7 @@ class DeconzBase:
|
||||
)
|
||||
|
||||
|
||||
class DeconzDevice(DeconzBase, Entity):
|
||||
class DeconzDevice(DeconzBase[_DeviceT], Entity):
|
||||
"""Representation of a deCONZ device."""
|
||||
|
||||
_attr_should_poll = False
|
||||
@ -69,7 +82,7 @@ class DeconzDevice(DeconzBase, Entity):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device: DeconzGroup | DeconzLight | DeconzSensor | PydeconzScene,
|
||||
device: _DeviceT,
|
||||
gateway: DeconzGateway,
|
||||
) -> None:
|
||||
"""Set up device and add update callback to get data from websocket."""
|
||||
@ -114,16 +127,14 @@ class DeconzDevice(DeconzBase, Entity):
|
||||
"""Return True if device is available."""
|
||||
if isinstance(self._device, PydeconzScene):
|
||||
return self.gateway.available
|
||||
return self.gateway.available and self._device.reachable
|
||||
return self.gateway.available and self._device.reachable # type: ignore[union-attr]
|
||||
|
||||
|
||||
class DeconzSceneMixin(DeconzDevice):
|
||||
class DeconzSceneMixin(DeconzDevice[PydeconzScene]):
|
||||
"""Representation of a deCONZ scene."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
_device: PydeconzScene
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device: PydeconzScene,
|
||||
|
@ -49,11 +49,10 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
|
||||
class DeconzFan(DeconzDevice, FanEntity):
|
||||
class DeconzFan(DeconzDevice[Light], FanEntity):
|
||||
"""Representation of a deCONZ fan."""
|
||||
|
||||
TYPE = DOMAIN
|
||||
_device: Light
|
||||
_default_on_speed = LightFanSpeed.PERCENT_50
|
||||
|
||||
_attr_supported_features = FanEntityFeature.SET_SPEED
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""Support for deCONZ lights."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Generic, TypedDict, TypeVar
|
||||
from typing import Any, TypedDict, TypeVar, Union
|
||||
|
||||
from pydeconz.interfaces.groups import GroupHandler
|
||||
from pydeconz.interfaces.lights import LightHandler
|
||||
@ -47,7 +47,7 @@ DECONZ_TO_COLOR_MODE = {
|
||||
LightColorMode.XY: ColorMode.XY,
|
||||
}
|
||||
|
||||
_L = TypeVar("_L", Group, Light)
|
||||
_LightDeviceT = TypeVar("_LightDeviceT", bound=Union[Group, Light])
|
||||
|
||||
|
||||
class SetStateAttributes(TypedDict, total=False):
|
||||
@ -121,14 +121,12 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
|
||||
class DeconzBaseLight(Generic[_L], DeconzDevice, LightEntity):
|
||||
class DeconzBaseLight(DeconzDevice[_LightDeviceT], LightEntity):
|
||||
"""Representation of a deCONZ light."""
|
||||
|
||||
TYPE = DOMAIN
|
||||
|
||||
_device: _L
|
||||
|
||||
def __init__(self, device: _L, gateway: DeconzGateway) -> None:
|
||||
def __init__(self, device: _LightDeviceT, gateway: DeconzGateway) -> None:
|
||||
"""Set up light."""
|
||||
super().__init__(device, gateway)
|
||||
|
||||
@ -261,8 +259,6 @@ class DeconzBaseLight(Generic[_L], DeconzDevice, LightEntity):
|
||||
class DeconzLight(DeconzBaseLight[Light]):
|
||||
"""Representation of a deCONZ light."""
|
||||
|
||||
_device: Light
|
||||
|
||||
@property
|
||||
def max_mireds(self) -> int:
|
||||
"""Return the warmest color_temp that this light supports."""
|
||||
@ -289,8 +285,6 @@ class DeconzGroup(DeconzBaseLight[Group]):
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
_device: Group
|
||||
|
||||
def __init__(self, device: Group, gateway: DeconzGateway) -> None:
|
||||
"""Set up group and create an unique id."""
|
||||
self._unique_id = f"{gateway.bridgeid}-{device.deconz_id}"
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from typing import Any, Union
|
||||
|
||||
from pydeconz.models.event import EventType
|
||||
from pydeconz.models.light.lock import Lock
|
||||
@ -50,11 +50,10 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
|
||||
class DeconzLock(DeconzDevice, LockEntity):
|
||||
class DeconzLock(DeconzDevice[Union[DoorLock, Lock]], LockEntity):
|
||||
"""Representation of a deCONZ lock."""
|
||||
|
||||
TYPE = DOMAIN
|
||||
_device: DoorLock | Lock
|
||||
|
||||
@property
|
||||
def is_locked(self) -> bool:
|
||||
|
@ -81,11 +81,10 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
|
||||
class DeconzNumber(DeconzDevice, NumberEntity):
|
||||
class DeconzNumber(DeconzDevice[Presence], NumberEntity):
|
||||
"""Representation of a deCONZ number entity."""
|
||||
|
||||
TYPE = DOMAIN
|
||||
_device: Presence
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -273,11 +273,10 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
|
||||
class DeconzSensor(DeconzDevice, SensorEntity):
|
||||
class DeconzSensor(DeconzDevice[SensorResources], SensorEntity):
|
||||
"""Representation of a deCONZ sensor."""
|
||||
|
||||
TYPE = DOMAIN
|
||||
_device: SensorResources
|
||||
entity_description: DeconzSensorDescription
|
||||
|
||||
def __init__(
|
||||
|
@ -41,7 +41,7 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
|
||||
class DeconzSiren(DeconzDevice, SirenEntity):
|
||||
class DeconzSiren(DeconzDevice[Siren], SirenEntity):
|
||||
"""Representation of a deCONZ siren."""
|
||||
|
||||
TYPE = DOMAIN
|
||||
@ -50,7 +50,6 @@ class DeconzSiren(DeconzDevice, SirenEntity):
|
||||
| SirenEntityFeature.TURN_OFF
|
||||
| SirenEntityFeature.DURATION
|
||||
)
|
||||
_device: Siren
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
|
@ -43,11 +43,10 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
|
||||
class DeconzPowerPlug(DeconzDevice, SwitchEntity):
|
||||
class DeconzPowerPlug(DeconzDevice[Light], SwitchEntity):
|
||||
"""Representation of a deCONZ power plug."""
|
||||
|
||||
TYPE = DOMAIN
|
||||
_device: Light
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
|
Loading…
x
Reference in New Issue
Block a user