Add strict typing to ring integration (#115276)
This commit is contained in:
parent
3546ca386f
commit
6954fcc8ad
16 changed files with 384 additions and 359 deletions
|
@ -2,10 +2,13 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable, Mapping
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from ring_doorbell import Ring, RingEvent, RingGeneric
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
BinarySensorDeviceClass,
|
||||
BinarySensorEntity,
|
||||
|
@ -15,29 +18,32 @@ from homeassistant.config_entries import ConfigEntry
|
|||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN, RING_API, RING_DEVICES, RING_NOTIFICATIONS_COORDINATOR
|
||||
from . import RingData
|
||||
from .const import DOMAIN
|
||||
from .coordinator import RingNotificationsCoordinator
|
||||
from .entity import RingEntity
|
||||
from .entity import RingBaseEntity
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class RingBinarySensorEntityDescription(BinarySensorEntityDescription):
|
||||
"""Describes Ring binary sensor entity."""
|
||||
|
||||
category: list[str]
|
||||
exists_fn: Callable[[RingGeneric], bool]
|
||||
|
||||
|
||||
BINARY_SENSOR_TYPES: tuple[RingBinarySensorEntityDescription, ...] = (
|
||||
RingBinarySensorEntityDescription(
|
||||
key="ding",
|
||||
translation_key="ding",
|
||||
category=["doorbots", "authorized_doorbots", "other"],
|
||||
device_class=BinarySensorDeviceClass.OCCUPANCY,
|
||||
exists_fn=lambda device: device.family
|
||||
in {"doorbots", "authorized_doorbots", "other"},
|
||||
),
|
||||
RingBinarySensorEntityDescription(
|
||||
key="motion",
|
||||
category=["doorbots", "authorized_doorbots", "stickup_cams"],
|
||||
device_class=BinarySensorDeviceClass.MOTION,
|
||||
exists_fn=lambda device: device.family
|
||||
in {"doorbots", "authorized_doorbots", "stickup_cams"},
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -48,34 +54,36 @@ async def async_setup_entry(
|
|||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Ring binary sensors from a config entry."""
|
||||
ring = hass.data[DOMAIN][config_entry.entry_id][RING_API]
|
||||
devices = hass.data[DOMAIN][config_entry.entry_id][RING_DEVICES]
|
||||
notifications_coordinator: RingNotificationsCoordinator = hass.data[DOMAIN][
|
||||
config_entry.entry_id
|
||||
][RING_NOTIFICATIONS_COORDINATOR]
|
||||
ring_data: RingData = hass.data[DOMAIN][config_entry.entry_id]
|
||||
|
||||
entities = [
|
||||
RingBinarySensor(ring, device, notifications_coordinator, description)
|
||||
for device_type in ("doorbots", "authorized_doorbots", "stickup_cams", "other")
|
||||
RingBinarySensor(
|
||||
ring_data.api,
|
||||
device,
|
||||
ring_data.notifications_coordinator,
|
||||
description,
|
||||
)
|
||||
for description in BINARY_SENSOR_TYPES
|
||||
if device_type in description.category
|
||||
for device in devices[device_type]
|
||||
for device in ring_data.devices.all_devices
|
||||
if description.exists_fn(device)
|
||||
]
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class RingBinarySensor(RingEntity, BinarySensorEntity):
|
||||
class RingBinarySensor(
|
||||
RingBaseEntity[RingNotificationsCoordinator], BinarySensorEntity
|
||||
):
|
||||
"""A binary sensor implementation for Ring device."""
|
||||
|
||||
_active_alert: dict[str, Any] | None = None
|
||||
_active_alert: RingEvent | None = None
|
||||
entity_description: RingBinarySensorEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
ring,
|
||||
device,
|
||||
coordinator,
|
||||
ring: Ring,
|
||||
device: RingGeneric,
|
||||
coordinator: RingNotificationsCoordinator,
|
||||
description: RingBinarySensorEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize a sensor for Ring device."""
|
||||
|
@ -89,13 +97,13 @@ class RingBinarySensor(RingEntity, BinarySensorEntity):
|
|||
self._update_alert()
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self, _=None):
|
||||
def _handle_coordinator_update(self, _: Any = None) -> None:
|
||||
"""Call update method."""
|
||||
self._update_alert()
|
||||
super()._handle_coordinator_update()
|
||||
|
||||
@callback
|
||||
def _update_alert(self):
|
||||
def _update_alert(self) -> None:
|
||||
"""Update active alert."""
|
||||
self._active_alert = next(
|
||||
(
|
||||
|
@ -108,21 +116,23 @@ class RingBinarySensor(RingEntity, BinarySensorEntity):
|
|||
)
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
def is_on(self) -> bool:
|
||||
"""Return True if the binary sensor is on."""
|
||||
return self._active_alert is not None
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
def extra_state_attributes(self) -> Mapping[str, Any] | None:
|
||||
"""Return the state attributes."""
|
||||
attrs = super().extra_state_attributes
|
||||
|
||||
if self._active_alert is None:
|
||||
return attrs
|
||||
|
||||
assert isinstance(attrs, dict)
|
||||
attrs["state"] = self._active_alert["state"]
|
||||
attrs["expires_at"] = datetime.fromtimestamp(
|
||||
self._active_alert.get("now") + self._active_alert.get("expires_in")
|
||||
).isoformat()
|
||||
now = self._active_alert.get("now")
|
||||
expires_in = self._active_alert.get("expires_in")
|
||||
assert now and expires_in
|
||||
attrs["expires_at"] = datetime.fromtimestamp(now + expires_in).isoformat()
|
||||
|
||||
return attrs
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue