You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
API budget counter drifted below real usage under failure load.api_budget.increment() used to run only after a successful API call, so polls that raised GardenaConnectionError, GardenaRateLimitError, or server-side 5xx were never counted locally — yet Husqvarna counts every attempt against the monthly quota. With the counter under-reporting, the 5 %-auto-stop safety net introduced in 1.10.2 would trigger too late (or never) during a failure storm. Increment now happens before the outbound call in all call sites: REST polls, WebSocket URL fetches, MQTT inbound commands, and entity commands (valve, switch, lawn_mower, automower_switch, automower_select, automower_button, automower_number, automower_lawn_mower). Pessimistic accounting matches server-side reality and makes auto-stop protective rather than decorative.
Double token refresh under concurrent load.GardenaAuth.async_ensure_valid_token had no mutex, so a simultaneous REST call and WebSocket connect (or watchdog reconnect + poll cycle) could both observe is_token_valid == False, fire two parallel POSTs to the auth endpoint, consume two quota units, and leave the old refresh_token invalidated by Husqvarna's server. Added an asyncio.Lock with double-checked locking: the fast path still returns the cached token without acquiring the lock, and the slow path serializes refreshes so only one HTTP round-trip happens per expiry cycle.
Secrets leaked to debug logs.GardenaClient._async_request logged the full request body at DEBUG level and on 4xx warnings, which exposed JSON command payloads (service IDs, schedule data) in home-assistant.log whenever users enabled debug logging — a common request in GitHub issue triage. Replaced with body-size-only logs; credentials continue to be redacted in diagnostics via async_redact_data.
Added
Auto-stop now also gates WebSocket connects. When the monthly budget is exhausted, _async_start_websocket returns immediately before fetching a fresh WS URL. Previously the REST-poll gate (added in 1.10.2) was the only checkpoint, leaving _async_get_ws_url as a quota leak path during exhaustion.
4 new tests: test_poll_increments_budget_even_on_connection_error, test_poll_increments_budget_on_rate_limit, test_start_websocket_aborts_when_exhausted, and test_parallel_callers_share_single_refresh. Total 725 tests passing.