98 lines
3.1 KiB
Python
98 lines
3.1 KiB
Python
"""Base class for Ring entity."""
|
|
|
|
from collections.abc import Callable
|
|
from typing import Any, Concatenate, Generic, ParamSpec, cast
|
|
|
|
from ring_doorbell import (
|
|
AuthenticationError,
|
|
RingDevices,
|
|
RingError,
|
|
RingGeneric,
|
|
RingTimeout,
|
|
)
|
|
from typing_extensions import TypeVar
|
|
|
|
from homeassistant.core import callback
|
|
from homeassistant.exceptions import HomeAssistantError
|
|
from homeassistant.helpers.device_registry import DeviceInfo
|
|
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, Any]")
|
|
_R = TypeVar("_R")
|
|
_P = ParamSpec("_P")
|
|
|
|
|
|
def exception_wrap(
|
|
func: Callable[Concatenate[_RingBaseEntityT, _P], _R],
|
|
) -> Callable[Concatenate[_RingBaseEntityT, _P], _R]:
|
|
"""Define a wrapper to catch exceptions and raise HomeAssistant errors."""
|
|
|
|
def _wrap(self: _RingBaseEntityT, *args: _P.args, **kwargs: _P.kwargs) -> _R:
|
|
try:
|
|
return func(self, *args, **kwargs)
|
|
except AuthenticationError as err:
|
|
self.hass.loop.call_soon_threadsafe(
|
|
self.coordinator.config_entry.async_start_reauth, self.hass
|
|
)
|
|
raise HomeAssistantError(err) from err
|
|
except RingTimeout as err:
|
|
raise HomeAssistantError(
|
|
f"Timeout communicating with API {func}: {err}"
|
|
) from err
|
|
except RingError as err:
|
|
raise HomeAssistantError(
|
|
f"Error communicating with API{func}: {err}"
|
|
) from err
|
|
|
|
return _wrap
|
|
|
|
|
|
class RingBaseEntity(
|
|
CoordinatorEntity[_RingCoordinatorT], Generic[_RingCoordinatorT, RingDeviceT]
|
|
):
|
|
"""Base implementation for Ring device."""
|
|
|
|
_attr_attribution = ATTRIBUTION
|
|
_attr_should_poll = False
|
|
_attr_has_entity_name = True
|
|
|
|
def __init__(
|
|
self,
|
|
device: RingDeviceT,
|
|
coordinator: _RingCoordinatorT,
|
|
) -> None:
|
|
"""Initialize a sensor for Ring device."""
|
|
super().__init__(coordinator, context=device.id)
|
|
self._device = device
|
|
self._attr_extra_state_attributes = {}
|
|
self._attr_device_info = DeviceInfo(
|
|
identifiers={(DOMAIN, device.device_id)}, # device_id is the mac
|
|
manufacturer="Ring",
|
|
model=device.model,
|
|
name=device.name,
|
|
)
|
|
|
|
|
|
class RingEntity(RingBaseEntity[RingDataCoordinator, RingDeviceT]):
|
|
"""Implementation for Ring devices."""
|
|
|
|
def _get_coordinator_data(self) -> RingDevices:
|
|
return self.coordinator.data
|
|
|
|
@callback
|
|
def _handle_coordinator_update(self) -> None:
|
|
self._device = cast(
|
|
RingDeviceT,
|
|
self._get_coordinator_data().get_device(self._device.device_api_id),
|
|
)
|
|
super()._handle_coordinator_update()
|