Make ring device generic in RingEntity (#115406)

Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
This commit is contained in:
Steven B 2024-04-11 10:31:37 +01:00 committed by GitHub
parent 5308e02c99
commit df5d818c08
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 27 additions and 34 deletions

View file

@ -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,

View file

@ -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,

View file

@ -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()

View file

@ -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:

View file

@ -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
) )

View file

@ -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)

View file

@ -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: