Skip to content

Commit

Permalink
Update to use event platform
Browse files Browse the repository at this point in the history
  • Loading branch information
sdb9696 committed Aug 29, 2024
1 parent 58b22eb commit 5526975
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 221 deletions.
46 changes: 24 additions & 22 deletions homeassistant/components/ring/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@
from ring_doorbell import Auth, Ring, RingDevices

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import APPLICATION_NAME, CONF_TOKEN, __version__
from homeassistant.const import APPLICATION_NAME, CONF_TOKEN
from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers import (
device_registry as dr,
entity_registry as er,
instance_id,
)
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue

from .const import DOMAIN, PLATFORMS
from .coordinator import (
RingDataCoordinator,
RingListenCoordinator,
RingNotificationsCoordinator,
)
from .const import CONF_LISTEN_CREDENTIALS, DOMAIN, PLATFORMS
from .coordinator import RingDataCoordinator, RingListenCoordinator

_LOGGER = logging.getLogger(__name__)

Expand All @@ -32,7 +32,6 @@ class RingData:
api: Ring
devices: RingDevices
devices_coordinator: RingDataCoordinator
notifications_coordinator: RingNotificationsCoordinator
listen_coordinator: RingListenCoordinator


Expand All @@ -49,28 +48,38 @@ def token_updater(token: dict[str, Any]) -> None:
data={**entry.data, CONF_TOKEN: token},
)

def listen_credentials_updater(token: dict[str, Any]) -> None:
"""Handle from async context when token is updated."""
hass.config_entries.async_update_entry(
entry,
data={**entry.data, CONF_LISTEN_CREDENTIALS: token},
)

hardware_id = await instance_id.async_get(hass)
client_session = async_get_clientsession(hass)
auth = Auth(
f"{APPLICATION_NAME}/{__version__}",
f"{APPLICATION_NAME}/{DOMAIN}-integration",
entry.data[CONF_TOKEN],
token_updater,
http_client_session=async_get_clientsession(hass),
hardware_id=hardware_id,
http_client_session=client_session,
)
ring = Ring(auth)

await _migrate_old_unique_ids(hass, entry.entry_id)

devices_coordinator = RingDataCoordinator(hass, ring)
notifications_coordinator = RingNotificationsCoordinator(hass, ring)
listen_coordinator = RingListenCoordinator(hass, ring)
listen_credentials = entry.data.get(CONF_LISTEN_CREDENTIALS)
listen_coordinator = RingListenCoordinator(
hass, ring, listen_credentials, listen_credentials_updater
)

await devices_coordinator.async_config_entry_first_refresh()
await notifications_coordinator.async_config_entry_first_refresh()

entry.runtime_data = RingData(
api=ring,
devices=ring.devices(),
devices_coordinator=devices_coordinator,
notifications_coordinator=notifications_coordinator,
listen_coordinator=listen_coordinator,
)

Expand Down Expand Up @@ -100,7 +109,6 @@ async def async_refresh_all(_: ServiceCall) -> None:

ring_data = entry.runtime_data
await ring_data.devices_coordinator.async_refresh()
await ring_data.notifications_coordinator.async_refresh()

# register service
hass.services.async_register(DOMAIN, "update", async_refresh_all)
Expand All @@ -113,12 +121,6 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if not await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
return False

hass.data[DOMAIN].pop(entry.entry_id)

if len(hass.data[DOMAIN]) != 0:
return True

# Last entry unloaded, clean up service
hass.services.async_remove(DOMAIN, "update")

return True
Expand Down
139 changes: 0 additions & 139 deletions homeassistant/components/ring/binary_sensor.py

This file was deleted.

4 changes: 2 additions & 2 deletions homeassistant/components/ring/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
DEFAULT_ENTITY_NAMESPACE = "ring"

PLATFORMS = [
Platform.BINARY_SENSOR,
Platform.BUTTON,
Platform.CAMERA,
Platform.EVENT,
Expand All @@ -27,6 +26,7 @@


SCAN_INTERVAL = timedelta(minutes=1)
NOTIFICATIONS_SCAN_INTERVAL = timedelta(seconds=5)
SESSION_REFRESH_INTERVAL = timedelta(minutes=10)

CONF_2FA = "2fa"
CONF_LISTEN_CREDENTIALS = "listen_token"
58 changes: 24 additions & 34 deletions homeassistant/components/ring/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
RingEvent,
RingTimeout,
)
from ring_doorbell.listen import RingEventListener, RingEventListenerConfig
from ring_doorbell.listen import RingEventListener

from homeassistant import config_entries
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
Expand All @@ -24,7 +24,7 @@
UpdateFailed,
)

from .const import NOTIFICATIONS_SCAN_INTERVAL, SCAN_INTERVAL
from .const import SCAN_INTERVAL

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -104,36 +104,25 @@ async def _async_update_data(self) -> RingDevices:
return devices


class RingNotificationsCoordinator(DataUpdateCoordinator[None]):
"""Global notifications coordinator."""

def __init__(self, hass: HomeAssistant, ring_api: Ring) -> None:
"""Initialize my coordinator."""
super().__init__(
hass,
logger=_LOGGER,
name="active dings",
update_interval=NOTIFICATIONS_SCAN_INTERVAL,
)
self.ring_api: Ring = ring_api

async def _async_update_data(self) -> None:
"""Fetch data from API endpoint."""
await _call_api(self.hass, self.ring_api.async_update_dings)


class RingListenCoordinator(BaseDataUpdateCoordinatorProtocol):
"""Global notifications coordinator."""

config_entry: config_entries.ConfigEntry

def __init__(self, hass: HomeAssistant, ring_api: Ring) -> None:
def __init__(
self,
hass: HomeAssistant,
ring_api: Ring,
listen_credentials: dict[str, Any] | None,
listen_credentials_updater: Callable[[dict[str, Any]], None],
) -> None:
"""Initialize my coordinator."""
self.hass = hass
self.logger = _LOGGER
self.ring_api: Ring = ring_api
self.config = RingEventListenerConfig.default_config()
self.event_listener = RingEventListener(ring_api, config=self.config)
self.event_listener = RingEventListener(
ring_api, listen_credentials, listen_credentials_updater
)
self._listeners: dict[CALLBACK_TYPE, tuple[CALLBACK_TYPE, object | None]] = {}
self._listen_callback_id: int | None = None

Expand All @@ -143,6 +132,7 @@ def __init__(self, hass: HomeAssistant, ring_api: Ring) -> None:
self.config_entry = config_entry
self.start_timeout = 10
self.config_entry.async_on_unload(self.async_shutdown)
self.alerts = ring_api.active_alerts()

async def async_shutdown(self) -> None:
"""Cancel any scheduled call, and ignore new runs."""
Expand All @@ -151,15 +141,13 @@ async def async_shutdown(self) -> None:

async def _async_stop_listen(self) -> None:
self.logger.debug("Stopped ring listener")
self.event_listener.stop()
await self.event_listener.stop()
self.logger.debug("Stopped ring listener")

async def _async_start_listen(self) -> None:
"""Start listening for realtime events."""
self.logger.debug("Starting ring listener with config: %s", self.config)
await self.event_listener.async_start(
listen_loop=self.hass.loop,
callback_loop=self.hass.loop,
self.logger.debug("Starting ring listener.")
await self.event_listener.start(
timeout=self.start_timeout,
)
if self.event_listener.started is True:
Expand All @@ -172,19 +160,21 @@ async def _async_start_listen(self) -> None:
self._listen_callback_id = self.event_listener.add_notification_callback(
self._on_event
)
await _call_api(self.hass, self.ring_api.update_dings)
self.alerts = self.ring_api.active_alerts()
# Update the listeners so they switch from Unavailable to Unknown
self._async_update_listeners()

def _on_event(self, event: RingEvent) -> None:
self.logger.debug("Ring event received: %s", event)
self._async_update_listeners()
self.hass.loop.call_later(event.expires_in, self._async_update_listeners)
self.alerts = self.ring_api.active_alerts()
self._async_update_listeners(event.doorbot_id)

@callback
def _async_update_listeners(self) -> None:
def _async_update_listeners(self, doorbot_id: int | None = None) -> None:
"""Update all registered listeners."""
for update_callback, _ in list(self._listeners.values()):
update_callback()
for update_callback, device_api_id in list(self._listeners.values()):
if not doorbot_id or device_api_id == doorbot_id:
update_callback()

@callback
def async_add_listener(
Expand Down
8 changes: 2 additions & 6 deletions homeassistant/components/ring/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,13 @@
)

from .const import ATTRIBUTION, DOMAIN
from .coordinator import (
RingDataCoordinator,
RingListenCoordinator,
RingNotificationsCoordinator,
)
from .coordinator import RingDataCoordinator, RingListenCoordinator

RingDeviceT = TypeVar("RingDeviceT", bound=RingGeneric, default=RingGeneric)

_RingCoordinatorT = TypeVar(
"_RingCoordinatorT",
bound=(RingDataCoordinator | RingNotificationsCoordinator | RingListenCoordinator),
bound=(RingDataCoordinator | RingListenCoordinator),
)


Expand Down
Loading

0 comments on commit 5526975

Please sign in to comment.