mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 06:07:17 +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."""
|
"""Representation of a deCONZ alarm control panel."""
|
||||||
|
|
||||||
TYPE = DOMAIN
|
TYPE = DOMAIN
|
||||||
_device: AncillaryControl
|
|
||||||
|
|
||||||
_attr_code_format = CodeFormat.NUMBER
|
_attr_code_format = CodeFormat.NUMBER
|
||||||
_attr_supported_features = (
|
_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."""
|
"""Representation of a deCONZ binary sensor."""
|
||||||
|
|
||||||
TYPE = DOMAIN
|
TYPE = DOMAIN
|
||||||
_device: SensorResources
|
|
||||||
entity_description: DeconzBinarySensorDescription
|
entity_description: DeconzBinarySensorDescription
|
||||||
|
|
||||||
def __init__(
|
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."""
|
"""Representation of a deCONZ thermostat."""
|
||||||
|
|
||||||
TYPE = DOMAIN
|
TYPE = DOMAIN
|
||||||
_device: Thermostat
|
|
||||||
|
|
||||||
_attr_temperature_unit = TEMP_CELSIUS
|
_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."""
|
"""Representation of a deCONZ cover."""
|
||||||
|
|
||||||
TYPE = DOMAIN
|
TYPE = DOMAIN
|
||||||
_device: Cover
|
|
||||||
|
|
||||||
def __init__(self, cover_id: str, gateway: DeconzGateway) -> None:
|
def __init__(self, cover_id: str, gateway: DeconzGateway) -> None:
|
||||||
"""Set up cover device."""
|
"""Set up cover device."""
|
||||||
|
@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pydeconz.models.group import Group as DeconzGroup
|
from typing import Generic, TypeVar, Union
|
||||||
from pydeconz.models.light import LightBase as DeconzLight
|
|
||||||
|
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.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.core import callback
|
||||||
from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE
|
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 .const import DOMAIN as DECONZ_DOMAIN
|
||||||
from .gateway import DeconzGateway
|
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."""
|
"""Common base for deconz entities and events."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
device: DeconzGroup | DeconzLight | DeconzSensor | PydeconzScene,
|
device: _DeviceT,
|
||||||
gateway: DeconzGateway,
|
gateway: DeconzGateway,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up device and add update callback to get data from websocket."""
|
"""Set up device and add update callback to get data from websocket."""
|
||||||
self._device = device
|
self._device: _DeviceT = device
|
||||||
self.gateway = gateway
|
self.gateway = gateway
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self) -> str:
|
def unique_id(self) -> str:
|
||||||
"""Return a unique identifier for this device."""
|
"""Return a unique identifier for this device."""
|
||||||
assert not isinstance(self._device, PydeconzScene)
|
assert isinstance(self._device, PydeconzDevice)
|
||||||
return self._device.unique_id
|
return self._device.unique_id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def serial(self) -> str | None:
|
def serial(self) -> str | None:
|
||||||
"""Return a serial number for this device."""
|
"""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:
|
if not self._device.unique_id or self._device.unique_id.count(":") != 7:
|
||||||
return None
|
return None
|
||||||
return self._device.unique_id.split("-", 1)[0]
|
return self._device.unique_id.split("-", 1)[0]
|
||||||
@ -45,7 +58,7 @@ class DeconzBase:
|
|||||||
@property
|
@property
|
||||||
def device_info(self) -> DeviceInfo | None:
|
def device_info(self) -> DeviceInfo | None:
|
||||||
"""Return a device description for device registry."""
|
"""Return a device description for device registry."""
|
||||||
assert not isinstance(self._device, PydeconzScene)
|
assert isinstance(self._device, PydeconzDevice)
|
||||||
if self.serial is None:
|
if self.serial is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -60,7 +73,7 @@ class DeconzBase:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class DeconzDevice(DeconzBase, Entity):
|
class DeconzDevice(DeconzBase[_DeviceT], Entity):
|
||||||
"""Representation of a deCONZ device."""
|
"""Representation of a deCONZ device."""
|
||||||
|
|
||||||
_attr_should_poll = False
|
_attr_should_poll = False
|
||||||
@ -69,7 +82,7 @@ class DeconzDevice(DeconzBase, Entity):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
device: DeconzGroup | DeconzLight | DeconzSensor | PydeconzScene,
|
device: _DeviceT,
|
||||||
gateway: DeconzGateway,
|
gateway: DeconzGateway,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up device and add update callback to get data from websocket."""
|
"""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."""
|
"""Return True if device is available."""
|
||||||
if isinstance(self._device, PydeconzScene):
|
if isinstance(self._device, PydeconzScene):
|
||||||
return self.gateway.available
|
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."""
|
"""Representation of a deCONZ scene."""
|
||||||
|
|
||||||
_attr_has_entity_name = True
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
_device: PydeconzScene
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
device: PydeconzScene,
|
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."""
|
"""Representation of a deCONZ fan."""
|
||||||
|
|
||||||
TYPE = DOMAIN
|
TYPE = DOMAIN
|
||||||
_device: Light
|
|
||||||
_default_on_speed = LightFanSpeed.PERCENT_50
|
_default_on_speed = LightFanSpeed.PERCENT_50
|
||||||
|
|
||||||
_attr_supported_features = FanEntityFeature.SET_SPEED
|
_attr_supported_features = FanEntityFeature.SET_SPEED
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Support for deCONZ lights."""
|
"""Support for deCONZ lights."""
|
||||||
from __future__ import annotations
|
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.groups import GroupHandler
|
||||||
from pydeconz.interfaces.lights import LightHandler
|
from pydeconz.interfaces.lights import LightHandler
|
||||||
@ -47,7 +47,7 @@ DECONZ_TO_COLOR_MODE = {
|
|||||||
LightColorMode.XY: ColorMode.XY,
|
LightColorMode.XY: ColorMode.XY,
|
||||||
}
|
}
|
||||||
|
|
||||||
_L = TypeVar("_L", Group, Light)
|
_LightDeviceT = TypeVar("_LightDeviceT", bound=Union[Group, Light])
|
||||||
|
|
||||||
|
|
||||||
class SetStateAttributes(TypedDict, total=False):
|
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."""
|
"""Representation of a deCONZ light."""
|
||||||
|
|
||||||
TYPE = DOMAIN
|
TYPE = DOMAIN
|
||||||
|
|
||||||
_device: _L
|
def __init__(self, device: _LightDeviceT, gateway: DeconzGateway) -> None:
|
||||||
|
|
||||||
def __init__(self, device: _L, gateway: DeconzGateway) -> None:
|
|
||||||
"""Set up light."""
|
"""Set up light."""
|
||||||
super().__init__(device, gateway)
|
super().__init__(device, gateway)
|
||||||
|
|
||||||
@ -261,8 +259,6 @@ class DeconzBaseLight(Generic[_L], DeconzDevice, LightEntity):
|
|||||||
class DeconzLight(DeconzBaseLight[Light]):
|
class DeconzLight(DeconzBaseLight[Light]):
|
||||||
"""Representation of a deCONZ light."""
|
"""Representation of a deCONZ light."""
|
||||||
|
|
||||||
_device: Light
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_mireds(self) -> int:
|
def max_mireds(self) -> int:
|
||||||
"""Return the warmest color_temp that this light supports."""
|
"""Return the warmest color_temp that this light supports."""
|
||||||
@ -289,8 +285,6 @@ class DeconzGroup(DeconzBaseLight[Group]):
|
|||||||
|
|
||||||
_attr_has_entity_name = True
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
_device: Group
|
|
||||||
|
|
||||||
def __init__(self, device: Group, gateway: DeconzGateway) -> None:
|
def __init__(self, device: Group, gateway: DeconzGateway) -> None:
|
||||||
"""Set up group and create an unique id."""
|
"""Set up group and create an unique id."""
|
||||||
self._unique_id = f"{gateway.bridgeid}-{device.deconz_id}"
|
self._unique_id = f"{gateway.bridgeid}-{device.deconz_id}"
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any, Union
|
||||||
|
|
||||||
from pydeconz.models.event import EventType
|
from pydeconz.models.event import EventType
|
||||||
from pydeconz.models.light.lock import Lock
|
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."""
|
"""Representation of a deCONZ lock."""
|
||||||
|
|
||||||
TYPE = DOMAIN
|
TYPE = DOMAIN
|
||||||
_device: DoorLock | Lock
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_locked(self) -> bool:
|
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."""
|
"""Representation of a deCONZ number entity."""
|
||||||
|
|
||||||
TYPE = DOMAIN
|
TYPE = DOMAIN
|
||||||
_device: Presence
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@ -273,11 +273,10 @@ async def async_setup_entry(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class DeconzSensor(DeconzDevice, SensorEntity):
|
class DeconzSensor(DeconzDevice[SensorResources], SensorEntity):
|
||||||
"""Representation of a deCONZ sensor."""
|
"""Representation of a deCONZ sensor."""
|
||||||
|
|
||||||
TYPE = DOMAIN
|
TYPE = DOMAIN
|
||||||
_device: SensorResources
|
|
||||||
entity_description: DeconzSensorDescription
|
entity_description: DeconzSensorDescription
|
||||||
|
|
||||||
def __init__(
|
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."""
|
"""Representation of a deCONZ siren."""
|
||||||
|
|
||||||
TYPE = DOMAIN
|
TYPE = DOMAIN
|
||||||
@ -50,7 +50,6 @@ class DeconzSiren(DeconzDevice, SirenEntity):
|
|||||||
| SirenEntityFeature.TURN_OFF
|
| SirenEntityFeature.TURN_OFF
|
||||||
| SirenEntityFeature.DURATION
|
| SirenEntityFeature.DURATION
|
||||||
)
|
)
|
||||||
_device: Siren
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
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."""
|
"""Representation of a deCONZ power plug."""
|
||||||
|
|
||||||
TYPE = DOMAIN
|
TYPE = DOMAIN
|
||||||
_device: Light
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
def is_on(self) -> bool:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user