-
-
Notifications
You must be signed in to change notification settings - Fork 38.4k
Warm the ViCare service cache on refresh instead of bypassing it #180344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c9d7c77
e380550
5f0ee61
715972c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| """DataUpdateCoordinator for the ViCare integration.""" | ||
|
|
||
| from contextlib import suppress | ||
| from datetime import timedelta | ||
| import logging | ||
| from typing import override | ||
|
|
@@ -9,6 +10,8 @@ | |
| PyViCareDeviceCommunicationError, | ||
| PyViCareInternalServerError, | ||
| PyViCareInvalidCredentialsError, | ||
| PyViCareInvalidDataError, | ||
| PyViCareNotSupportedFeatureError, | ||
| PyViCareRateLimitError, | ||
| ) | ||
| import requests | ||
|
|
@@ -46,7 +49,7 @@ def __init__( | |
| hass, | ||
| _LOGGER, | ||
| config_entry=config_entry, | ||
| name=f"{DOMAIN}_{device.service.accessor.id}", | ||
| name=f"{DOMAIN}_{device.accessor.serial}_{device.accessor.device_id}", | ||
| update_interval=timedelta(seconds=DEFAULT_CACHE_DURATION * device_count), | ||
| ) | ||
| self._device = device | ||
|
|
@@ -60,13 +63,18 @@ def _refresh(self) -> None: | |
| """Force a fresh fetch from the Viessmann API.""" | ||
| try: | ||
| self._device.service.clear_cache() | ||
| self._device.service.fetch_all_features() | ||
| # Read one property instead of calling fetch_all_features(): on the | ||
| # cached service the latter bypasses the cache, so every entity read | ||
| # would hit the API again, from the event loop. | ||
| with suppress(PyViCareNotSupportedFeatureError): | ||
| self._device.getProperty("device.serial") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Still better than the old behaviour, where the same payload detonated at the entity read inside the event loop — it just wants adding to the |
||
| except PyViCareInvalidCredentialsError as err: | ||
| raise ConfigEntryAuthFailed from err | ||
| except ( | ||
| PyViCareDeviceCommunicationError, | ||
| PyViCareRateLimitError, | ||
| PyViCareInternalServerError, | ||
| PyViCareInvalidDataError, | ||
| PyViCareRateLimitError, | ||
| requests.RequestException, | ||
| ) as err: | ||
| raise UpdateFailed(str(err)) from err | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This suppress is broader than the
device.serial-is-optional case it is aimed at. Afterclear_cache(),_get_or_update_cacheconvertsPyViCareNotPaidForErrorintoPyViCareNotSupportedFeatureError("PACKAGE_NOT_PAID_FOR"), which this swallows — so a wholly unpaid account gets a refresh that reports success with an empty cache:Two consequences. The condition becomes undiagnosable — entities stay available reading
unknown, with nothing logged, where before they went unavailable. And because the cache never populates,_stringify_statedoes readself.state, so every entity read re-enters_get_or_update_cacheand hits the API from the event loop — the blocking-call problem this PR fixes, reappearing on the unpaid path.Checking that the cache actually warmed after the suppressed probe distinguishes the benign case from this one.