Avoid useless time fetch in DataUpdateCoordinator (#107999)

* Avoid useless time fetch in DataUpdateCoordinator

Since we used the async_call_at helper, it would always call dt_util.utcnow()
to feed the _handle_refresh_interval which threw it away. This meant we had
to fetch time twice as much as needed for each update

* tweak

* compat

* adjust comment
This commit is contained in:
J. Nick Koston 2024-01-13 18:40:07 -10:00 committed by GitHub
parent 9033f1f3e8
commit 8d3f693907
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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)