Skip to content

Commit 209c30e

Browse files
marq24marq24
authored andcommitted
rate-limit-handling
1 parent b83849b commit 209c30e

File tree

2 files changed

+25
-6
lines changed

2 files changed

+25
-6
lines changed

custom_components/fordconnect_query/__init__.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ def __init__(self, hass: HomeAssistant, session: OAuth2Session, config_entry: Co
226226
self.last_update_success = False
227227
self._vin = config_entry.data["vin"]
228228
self._last_update_time = 0
229+
self._rate_limit_hit = False
229230

230231
# just copied over must check later...
231232
self._config_entry = config_entry
@@ -476,15 +477,23 @@ def _check_if_veh_capability_supported(self, a_capability: str, capabilities: di
476477
async def _async_update_data(self):
477478
_LOGGER.debug(f"{self.vli}_async_update_data(): Updating data for VIN: {self._vin}")
478479
now = time.monotonic()
479-
if now - self._last_update_time < 15:
480+
if self._rate_limit_hit and now - self._last_update_time < 60:
480481
_LOGGER.debug(f"{self.vli}Rate limit: Returning cached data (last update {now - self._last_update_time:.1f}s ago)")
481-
return self.data
482+
if self.data is not None:
483+
return self.data
482484

483485
# IMHO this is not required for an OAuth2Session
484486
await self._session.async_ensure_token_valid()
485487
telemetry_data = await self.request_telemetry()
486-
if telemetry_data is None or telemetry_data == RATE_LIMIT_INDICATOR:
488+
if telemetry_data is None:
487489
raise UpdateFailed("No data received from Ford API (or exception/error)")
490+
elif RATE_LIMIT_INDICATOR in telemetry_data:
491+
if self.data is None:
492+
# we are in the initial startup phase of the integration... since we have no self.data yet (that
493+
# we could return)
494+
raise UpdateFailed("API not ready yet - please retry later", retry_after=float(telemetry_data.get(RATE_LIMIT_INDICATOR, 62)))
495+
else:
496+
return self.data
488497
else:
489498
pass
490499
# health_data = await self.request_health()
@@ -499,6 +508,7 @@ async def _async_update_data(self):
499508

500509
if telemetry_data is not None:
501510
self._last_update_time = time.monotonic()
511+
self._rate_limit_hit = False
502512
return telemetry_data
503513
# result = {}
504514
# if ROOT_METRICS in telemetry_data:
@@ -542,9 +552,18 @@ async def __request_data(self, url_template:str, logging_type:str):
542552

543553
except BaseException as exc:
544554
if res.status == 429:
545-
_LOGGER.debug(f"{self.vli}request_{logging_type}():{url} caused {res.status} - rate limit exceeded - sleeping for 15 seconds")
555+
try:
556+
val = res.headers.get("Retry-After")
557+
if val is not None and val.isdigit():
558+
retry_after = int(val)
559+
else:
560+
retry_after = 62
561+
except (ValueError, TypeError):
562+
retry_after = 62
563+
_LOGGER.debug(f"{self.vli}request_{logging_type}():{url} caused {res.status} - rate limit exceeded - sleeping for {retry_after} seconds")
546564
self._last_update_time = time.monotonic()
547-
return RATE_LIMIT_INDICATOR
565+
self._rate_limit_hit = True
566+
return {RATE_LIMIT_INDICATOR: retry_after}
548567
else:
549568
_LOGGER.info(f"{self.vli}request_{logging_type}():{url} caused {type(exc).__name__} {exc}")
550569
stack_trace = traceback.format_stack()

custom_components/fordconnect_query/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
"iot_class": "cloud_polling",
99
"issue_tracker": "https://github.com/marq24/ha-fordconnect-query/issues",
1010
"requirements": [],
11-
"version": "2026.2.2"
11+
"version": "2026.2.3"
1212
}

0 commit comments

Comments
 (0)