diff --git a/homeassistant/helpers/update_coordinator.py b/homeassistant/helpers/update_coordinator.py index 606b90e60056692f5d5b93ec4d3f34f575264bef..d8631398db76dee4c63419f04e06a4940cbbdaaf 100644 --- a/homeassistant/helpers/update_coordinator.py +++ b/homeassistant/helpers/update_coordinator.py @@ -84,6 +84,7 @@ class DataUpdateCoordinator(BaseDataUpdateCoordinatorProtocol, Generic[_DataT]): self.logger = logger self.name = name self.update_method = update_method + self._update_interval_seconds: float | None = None self.update_interval = update_interval self._shutdown_requested = False self.config_entry = config_entries.current_entry.get() @@ -212,10 +213,21 @@ class DataUpdateCoordinator(BaseDataUpdateCoordinatorProtocol, Generic[_DataT]): self._unsub_shutdown() self._unsub_shutdown = None + @property + def update_interval(self) -> timedelta | None: + """Interval between updates.""" + return self._update_interval + + @update_interval.setter + def update_interval(self, value: timedelta | None) -> None: + """Set interval between updates.""" + self._update_interval = value + self._update_interval_seconds = value.total_seconds() if value else None + @callback def _schedule_refresh(self) -> None: """Schedule a refresh.""" - if self.update_interval is None: + if self._update_interval_seconds is None: return if self.config_entry and self.config_entry.pref_disable_polling: @@ -225,19 +237,20 @@ class DataUpdateCoordinator(BaseDataUpdateCoordinatorProtocol, Generic[_DataT]): # than the debouncer cooldown, this would cause the debounce to never be called self._async_unsub_refresh() - # We use event.async_call_at because DataUpdateCoordinator does - # not need an exact update interval. - now = self.hass.loop.time() + # We use loop.call_at because DataUpdateCoordinator does + # not need an exact update interval which also avoids + # calling dt_util.utcnow() on every update. + hass = self.hass + loop = hass.loop - next_refresh = int(now) + self._microsecond - next_refresh += self.update_interval.total_seconds() - self._unsub_refresh = event.async_call_at( - self.hass, - self._job, - next_refresh, + next_refresh = ( + int(loop.time()) + self._microsecond + self._update_interval_seconds ) + self._unsub_refresh = loop.call_at( + next_refresh, hass.async_run_hass_job, self._job + ).cancel - async def _handle_refresh_interval(self, _now: datetime) -> None: + async def _handle_refresh_interval(self, _now: datetime | None = None) -> None: """Handle a refresh interval occurrence.""" self._unsub_refresh = None await self._async_refresh(log_failures=True, scheduled=True)