Make ring device generic in RingEntity (#115406)
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
This commit is contained in:
parent
5308e02c99
commit
df5d818c08
7 changed files with 27 additions and 34 deletions
|
@ -35,11 +35,9 @@ async def async_setup_entry(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RingDoorButton(RingEntity, ButtonEntity):
|
class RingDoorButton(RingEntity[RingOther], ButtonEntity):
|
||||||
"""Creates a button to open the ring intercom door."""
|
"""Creates a button to open the ring intercom door."""
|
||||||
|
|
||||||
_device: RingOther
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
device: RingOther,
|
device: RingOther,
|
||||||
|
|
|
@ -48,11 +48,10 @@ async def async_setup_entry(
|
||||||
async_add_entities(cams)
|
async_add_entities(cams)
|
||||||
|
|
||||||
|
|
||||||
class RingCam(RingEntity, Camera):
|
class RingCam(RingEntity[RingDoorBell], Camera):
|
||||||
"""An implementation of a Ring Door Bell camera."""
|
"""An implementation of a Ring Door Bell camera."""
|
||||||
|
|
||||||
_attr_name = None
|
_attr_name = None
|
||||||
_device: RingDoorBell
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Base class for Ring entity."""
|
"""Base class for Ring entity."""
|
||||||
|
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from typing import Any, Concatenate, ParamSpec, TypeVar
|
from typing import Any, Concatenate, Generic, ParamSpec, cast
|
||||||
|
|
||||||
from ring_doorbell import (
|
from ring_doorbell import (
|
||||||
AuthenticationError,
|
AuthenticationError,
|
||||||
|
@ -10,6 +10,7 @@ from ring_doorbell import (
|
||||||
RingGeneric,
|
RingGeneric,
|
||||||
RingTimeout,
|
RingTimeout,
|
||||||
)
|
)
|
||||||
|
from typing_extensions import TypeVar
|
||||||
|
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
@ -19,11 +20,13 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
from .const import ATTRIBUTION, DOMAIN
|
from .const import ATTRIBUTION, DOMAIN
|
||||||
from .coordinator import RingDataCoordinator, RingNotificationsCoordinator
|
from .coordinator import RingDataCoordinator, RingNotificationsCoordinator
|
||||||
|
|
||||||
|
RingDeviceT = TypeVar("RingDeviceT", bound=RingGeneric, default=RingGeneric)
|
||||||
|
|
||||||
_RingCoordinatorT = TypeVar(
|
_RingCoordinatorT = TypeVar(
|
||||||
"_RingCoordinatorT",
|
"_RingCoordinatorT",
|
||||||
bound=(RingDataCoordinator | RingNotificationsCoordinator),
|
bound=(RingDataCoordinator | RingNotificationsCoordinator),
|
||||||
)
|
)
|
||||||
_RingBaseEntityT = TypeVar("_RingBaseEntityT", bound="RingBaseEntity[Any]")
|
_RingBaseEntityT = TypeVar("_RingBaseEntityT", bound="RingBaseEntity[Any, Any]")
|
||||||
_R = TypeVar("_R")
|
_R = TypeVar("_R")
|
||||||
_P = ParamSpec("_P")
|
_P = ParamSpec("_P")
|
||||||
|
|
||||||
|
@ -53,7 +56,9 @@ def exception_wrap(
|
||||||
return _wrap
|
return _wrap
|
||||||
|
|
||||||
|
|
||||||
class RingBaseEntity(CoordinatorEntity[_RingCoordinatorT]):
|
class RingBaseEntity(
|
||||||
|
CoordinatorEntity[_RingCoordinatorT], Generic[_RingCoordinatorT, RingDeviceT]
|
||||||
|
):
|
||||||
"""Base implementation for Ring device."""
|
"""Base implementation for Ring device."""
|
||||||
|
|
||||||
_attr_attribution = ATTRIBUTION
|
_attr_attribution = ATTRIBUTION
|
||||||
|
@ -62,7 +67,7 @@ class RingBaseEntity(CoordinatorEntity[_RingCoordinatorT]):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
device: RingGeneric,
|
device: RingDeviceT,
|
||||||
coordinator: _RingCoordinatorT,
|
coordinator: _RingCoordinatorT,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize a sensor for Ring device."""
|
"""Initialize a sensor for Ring device."""
|
||||||
|
@ -77,7 +82,7 @@ class RingBaseEntity(CoordinatorEntity[_RingCoordinatorT]):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RingEntity(RingBaseEntity[RingDataCoordinator]):
|
class RingEntity(RingBaseEntity[RingDataCoordinator, RingDeviceT]):
|
||||||
"""Implementation for Ring devices."""
|
"""Implementation for Ring devices."""
|
||||||
|
|
||||||
def _get_coordinator_data(self) -> RingDevices:
|
def _get_coordinator_data(self) -> RingDevices:
|
||||||
|
@ -85,7 +90,8 @@ class RingEntity(RingBaseEntity[RingDataCoordinator]):
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _handle_coordinator_update(self) -> None:
|
def _handle_coordinator_update(self) -> None:
|
||||||
self._device = self._get_coordinator_data().get_device(
|
self._device = cast(
|
||||||
self._device.device_api_id
|
RingDeviceT,
|
||||||
|
self._get_coordinator_data().get_device(self._device.device_api_id),
|
||||||
)
|
)
|
||||||
super()._handle_coordinator_update()
|
super()._handle_coordinator_update()
|
||||||
|
|
|
@ -52,15 +52,13 @@ async def async_setup_entry(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RingLight(RingEntity, LightEntity):
|
class RingLight(RingEntity[RingStickUpCam], LightEntity):
|
||||||
"""Creates a switch to turn the ring cameras light on and off."""
|
"""Creates a switch to turn the ring cameras light on and off."""
|
||||||
|
|
||||||
_attr_color_mode = ColorMode.ONOFF
|
_attr_color_mode = ColorMode.ONOFF
|
||||||
_attr_supported_color_modes = {ColorMode.ONOFF}
|
_attr_supported_color_modes = {ColorMode.ONOFF}
|
||||||
_attr_translation_key = "light"
|
_attr_translation_key = "light"
|
||||||
|
|
||||||
_device: RingStickUpCam
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, device: RingStickUpCam, coordinator: RingDataCoordinator
|
self, device: RingStickUpCam, coordinator: RingDataCoordinator
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
|
@ -14,7 +14,6 @@ from ring_doorbell import (
|
||||||
RingGeneric,
|
RingGeneric,
|
||||||
RingOther,
|
RingOther,
|
||||||
)
|
)
|
||||||
from typing_extensions import TypeVar
|
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
SensorDeviceClass,
|
SensorDeviceClass,
|
||||||
|
@ -35,9 +34,7 @@ from homeassistant.helpers.typing import StateType
|
||||||
from . import RingData
|
from . import RingData
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .coordinator import RingDataCoordinator
|
from .coordinator import RingDataCoordinator
|
||||||
from .entity import RingEntity
|
from .entity import RingDeviceT, RingEntity
|
||||||
|
|
||||||
_RingDeviceT = TypeVar("_RingDeviceT", bound=RingGeneric, default=RingGeneric)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
|
@ -59,17 +56,16 @@ async def async_setup_entry(
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
class RingSensor(RingEntity, SensorEntity, Generic[_RingDeviceT]):
|
class RingSensor(RingEntity[RingDeviceT], SensorEntity):
|
||||||
"""A sensor implementation for Ring device."""
|
"""A sensor implementation for Ring device."""
|
||||||
|
|
||||||
entity_description: RingSensorEntityDescription[_RingDeviceT]
|
entity_description: RingSensorEntityDescription[RingDeviceT]
|
||||||
_device: _RingDeviceT
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
device: RingGeneric,
|
device: RingDeviceT,
|
||||||
coordinator: RingDataCoordinator,
|
coordinator: RingDataCoordinator,
|
||||||
description: RingSensorEntityDescription[_RingDeviceT],
|
description: RingSensorEntityDescription[RingDeviceT],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize a sensor for Ring device."""
|
"""Initialize a sensor for Ring device."""
|
||||||
super().__init__(device, coordinator)
|
super().__init__(device, coordinator)
|
||||||
|
@ -85,7 +81,7 @@ class RingSensor(RingEntity, SensorEntity, Generic[_RingDeviceT]):
|
||||||
"""Call update method."""
|
"""Call update method."""
|
||||||
|
|
||||||
self._device = cast(
|
self._device = cast(
|
||||||
_RingDeviceT,
|
RingDeviceT,
|
||||||
self._get_coordinator_data().get_device(self._device.device_api_id),
|
self._get_coordinator_data().get_device(self._device.device_api_id),
|
||||||
)
|
)
|
||||||
# History values can drop off the last 10 events so only update
|
# History values can drop off the last 10 events so only update
|
||||||
|
@ -126,12 +122,12 @@ def _get_last_event_attrs(
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True, kw_only=True)
|
@dataclass(frozen=True, kw_only=True)
|
||||||
class RingSensorEntityDescription(SensorEntityDescription, Generic[_RingDeviceT]):
|
class RingSensorEntityDescription(SensorEntityDescription, Generic[RingDeviceT]):
|
||||||
"""Describes Ring sensor entity."""
|
"""Describes Ring sensor entity."""
|
||||||
|
|
||||||
value_fn: Callable[[_RingDeviceT], StateType] = lambda _: True
|
value_fn: Callable[[RingDeviceT], StateType] = lambda _: True
|
||||||
exists_fn: Callable[[RingGeneric], bool] = lambda _: True
|
exists_fn: Callable[[RingGeneric], bool] = lambda _: True
|
||||||
extra_state_attributes_fn: Callable[[_RingDeviceT], dict[str, Any] | None] = (
|
extra_state_attributes_fn: Callable[[RingDeviceT], dict[str, Any] | None] = (
|
||||||
lambda _: None
|
lambda _: None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -33,15 +33,13 @@ async def async_setup_entry(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RingChimeSiren(RingEntity, SirenEntity):
|
class RingChimeSiren(RingEntity[RingChime], SirenEntity):
|
||||||
"""Creates a siren to play the test chimes of a Chime device."""
|
"""Creates a siren to play the test chimes of a Chime device."""
|
||||||
|
|
||||||
_attr_available_tones = [RingEventKind.DING.value, RingEventKind.MOTION.value]
|
_attr_available_tones = [RingEventKind.DING.value, RingEventKind.MOTION.value]
|
||||||
_attr_supported_features = SirenEntityFeature.TURN_ON | SirenEntityFeature.TONES
|
_attr_supported_features = SirenEntityFeature.TURN_ON | SirenEntityFeature.TONES
|
||||||
_attr_translation_key = "siren"
|
_attr_translation_key = "siren"
|
||||||
|
|
||||||
_device: RingChime
|
|
||||||
|
|
||||||
def __init__(self, device: RingChime, coordinator: RingDataCoordinator) -> None:
|
def __init__(self, device: RingChime, coordinator: RingDataCoordinator) -> None:
|
||||||
"""Initialize a Ring Chime siren."""
|
"""Initialize a Ring Chime siren."""
|
||||||
super().__init__(device, coordinator)
|
super().__init__(device, coordinator)
|
||||||
|
|
|
@ -44,11 +44,9 @@ async def async_setup_entry(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BaseRingSwitch(RingEntity, SwitchEntity):
|
class BaseRingSwitch(RingEntity[RingStickUpCam], SwitchEntity):
|
||||||
"""Represents a switch for controlling an aspect of a ring device."""
|
"""Represents a switch for controlling an aspect of a ring device."""
|
||||||
|
|
||||||
_device: RingStickUpCam
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, device: RingStickUpCam, coordinator: RingDataCoordinator, device_type: str
|
self, device: RingStickUpCam, coordinator: RingDataCoordinator, device_type: str
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue