1
mirror of https://github.com/home-assistant/core synced 2024-10-13 14:52:10 +02:00
ha-core/homeassistant/components/lookin/coordinator.py
J. Nick Koston 50b2e9d794
Prevent lookin polling when push updates are coming in (#64687)
Co-authored-by: Chris Talkington <chris@talkingtontech.com>
2022-01-22 21:19:34 -10:00

86 lines
2.8 KiB
Python

"""Coordinator for lookin devices."""
from __future__ import annotations
from collections.abc import Awaitable, Callable
from datetime import timedelta
import logging
import time
from typing import cast
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
NEVER_TIME = -120.0 # Time that will never match time.monotonic()
ACTIVE_UPDATES_INTERVAL = 3 # Consider active for 3x the update interval
class LookinPushCoordinator:
"""Keep track of when the last push update was."""
def __init__(self, name: str) -> None:
"""Init the push coordininator."""
self.last_update = NEVER_TIME
self.name = name
def update(self) -> None:
"""Remember the last push time."""
self.last_update = time.monotonic()
def active(self, interval: timedelta) -> bool:
"""Check if the last push update was recently."""
time_since_last_update = time.monotonic() - self.last_update
is_active = (
time_since_last_update < interval.total_seconds() * ACTIVE_UPDATES_INTERVAL
)
_LOGGER.debug(
"%s: push updates active: %s (time_since_last_update=%s)",
self.name,
is_active,
time_since_last_update,
)
return is_active
class LookinDataUpdateCoordinator(DataUpdateCoordinator):
"""DataUpdateCoordinator to gather data for a specific lookin devices."""
def __init__(
self,
hass: HomeAssistant,
push_coordinator: LookinPushCoordinator,
name: str,
update_interval: timedelta | None = None,
update_method: Callable[[], Awaitable[dict]] | None = None,
) -> None:
"""Initialize DataUpdateCoordinator to gather data for specific device."""
self.push_coordinator = push_coordinator
super().__init__(
hass,
_LOGGER,
name=name,
update_interval=update_interval,
update_method=update_method,
)
@callback
def async_set_updated_data(self, data: dict) -> None:
"""Manually update data, notify listeners and reset refresh interval, and remember."""
self.push_coordinator.update()
super().async_set_updated_data(data)
async def _async_update_data(self) -> dict:
"""Fetch data only if we have not received a push inside the interval."""
interval = self.update_interval
if (
interval is not None
and self.last_update_success
and self.data
and self.push_coordinator.active(interval)
):
data = self.data
else:
data = await super()._async_update_data()
return cast(dict, data)