diff --git a/homeassistant/components/ring/button.py b/homeassistant/components/ring/button.py index a14853a0881..15d56a8b7cf 100644 --- a/homeassistant/components/ring/button.py +++ b/homeassistant/components/ring/button.py @@ -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.""" - _device: RingOther - def __init__( self, device: RingOther, diff --git a/homeassistant/components/ring/camera.py b/homeassistant/components/ring/camera.py index 297e5f47627..282f9816c4c 100644 --- a/homeassistant/components/ring/camera.py +++ b/homeassistant/components/ring/camera.py @@ -48,11 +48,10 @@ async def async_setup_entry( async_add_entities(cams) -class RingCam(RingEntity, Camera): +class RingCam(RingEntity[RingDoorBell], Camera): """An implementation of a Ring Door Bell camera.""" _attr_name = None - _device: RingDoorBell def __init__( self, diff --git a/homeassistant/components/ring/entity.py b/homeassistant/components/ring/entity.py index 54f76a19c5d..65ccbb8ece4 100644 --- a/homeassistant/components/ring/entity.py +++ b/homeassistant/components/ring/entity.py @@ -1,7 +1,7 @@ """Base class for Ring entity.""" from collections.abc import Callable -from typing import Any, Concatenate, ParamSpec, TypeVar +from typing import Any, Concatenate, Generic, ParamSpec, cast from ring_doorbell import ( AuthenticationError, @@ -10,6 +10,7 @@ from ring_doorbell import ( RingGeneric, RingTimeout, ) +from typing_extensions import TypeVar from homeassistant.core import callback from homeassistant.exceptions import HomeAssistantError @@ -19,11 +20,13 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import ATTRIBUTION, DOMAIN from .coordinator import RingDataCoordinator, RingNotificationsCoordinator +RingDeviceT = TypeVar("RingDeviceT", bound=RingGeneric, default=RingGeneric) + _RingCoordinatorT = TypeVar( "_RingCoordinatorT", bound=(RingDataCoordinator | RingNotificationsCoordinator), ) -_RingBaseEntityT = TypeVar("_RingBaseEntityT", bound="RingBaseEntity[Any]") +_RingBaseEntityT = TypeVar("_RingBaseEntityT", bound="RingBaseEntity[Any, Any]") _R = TypeVar("_R") _P = ParamSpec("_P") @@ -53,7 +56,9 @@ def exception_wrap( return _wrap -class RingBaseEntity(CoordinatorEntity[_RingCoordinatorT]): +class RingBaseEntity( + CoordinatorEntity[_RingCoordinatorT], Generic[_RingCoordinatorT, RingDeviceT] +): """Base implementation for Ring device.""" _attr_attribution = ATTRIBUTION @@ -62,7 +67,7 @@ class RingBaseEntity(CoordinatorEntity[_RingCoordinatorT]): def __init__( self, - device: RingGeneric, + device: RingDeviceT, coordinator: _RingCoordinatorT, ) -> None: """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.""" def _get_coordinator_data(self) -> RingDevices: @@ -85,7 +90,8 @@ class RingEntity(RingBaseEntity[RingDataCoordinator]): @callback def _handle_coordinator_update(self) -> None: - self._device = self._get_coordinator_data().get_device( - self._device.device_api_id + self._device = cast( + RingDeviceT, + self._get_coordinator_data().get_device(self._device.device_api_id), ) super()._handle_coordinator_update() diff --git a/homeassistant/components/ring/light.py b/homeassistant/components/ring/light.py index a4eb8df5b46..5747c9e77f7 100644 --- a/homeassistant/components/ring/light.py +++ b/homeassistant/components/ring/light.py @@ -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.""" _attr_color_mode = ColorMode.ONOFF _attr_supported_color_modes = {ColorMode.ONOFF} _attr_translation_key = "light" - _device: RingStickUpCam - def __init__( self, device: RingStickUpCam, coordinator: RingDataCoordinator ) -> None: diff --git a/homeassistant/components/ring/sensor.py b/homeassistant/components/ring/sensor.py index 0c4d1f4fdf5..b6849e37d96 100644 --- a/homeassistant/components/ring/sensor.py +++ b/homeassistant/components/ring/sensor.py @@ -14,7 +14,6 @@ from ring_doorbell import ( RingGeneric, RingOther, ) -from typing_extensions import TypeVar from homeassistant.components.sensor import ( SensorDeviceClass, @@ -35,9 +34,7 @@ from homeassistant.helpers.typing import StateType from . import RingData from .const import DOMAIN from .coordinator import RingDataCoordinator -from .entity import RingEntity - -_RingDeviceT = TypeVar("_RingDeviceT", bound=RingGeneric, default=RingGeneric) +from .entity import RingDeviceT, RingEntity async def async_setup_entry( @@ -59,17 +56,16 @@ async def async_setup_entry( async_add_entities(entities) -class RingSensor(RingEntity, SensorEntity, Generic[_RingDeviceT]): +class RingSensor(RingEntity[RingDeviceT], SensorEntity): """A sensor implementation for Ring device.""" - entity_description: RingSensorEntityDescription[_RingDeviceT] - _device: _RingDeviceT + entity_description: RingSensorEntityDescription[RingDeviceT] def __init__( self, - device: RingGeneric, + device: RingDeviceT, coordinator: RingDataCoordinator, - description: RingSensorEntityDescription[_RingDeviceT], + description: RingSensorEntityDescription[RingDeviceT], ) -> None: """Initialize a sensor for Ring device.""" super().__init__(device, coordinator) @@ -85,7 +81,7 @@ class RingSensor(RingEntity, SensorEntity, Generic[_RingDeviceT]): """Call update method.""" self._device = cast( - _RingDeviceT, + RingDeviceT, self._get_coordinator_data().get_device(self._device.device_api_id), ) # 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) -class RingSensorEntityDescription(SensorEntityDescription, Generic[_RingDeviceT]): +class RingSensorEntityDescription(SensorEntityDescription, Generic[RingDeviceT]): """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 - extra_state_attributes_fn: Callable[[_RingDeviceT], dict[str, Any] | None] = ( + extra_state_attributes_fn: Callable[[RingDeviceT], dict[str, Any] | None] = ( lambda _: None ) diff --git a/homeassistant/components/ring/siren.py b/homeassistant/components/ring/siren.py index 27f68258bad..f63f9d33182 100644 --- a/homeassistant/components/ring/siren.py +++ b/homeassistant/components/ring/siren.py @@ -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.""" _attr_available_tones = [RingEventKind.DING.value, RingEventKind.MOTION.value] _attr_supported_features = SirenEntityFeature.TURN_ON | SirenEntityFeature.TONES _attr_translation_key = "siren" - _device: RingChime - def __init__(self, device: RingChime, coordinator: RingDataCoordinator) -> None: """Initialize a Ring Chime siren.""" super().__init__(device, coordinator) diff --git a/homeassistant/components/ring/switch.py b/homeassistant/components/ring/switch.py index b5cd59ac2fb..0e032907bae 100644 --- a/homeassistant/components/ring/switch.py +++ b/homeassistant/components/ring/switch.py @@ -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.""" - _device: RingStickUpCam - def __init__( self, device: RingStickUpCam, coordinator: RingDataCoordinator, device_type: str ) -> None: