Skip to content

API Rate Limits EN

Kay Löhmann edited this page May 30, 2026 · 3 revisions

API Rate Limits

Sprache: English · Deutsch

The Husqvarna APIs (both Gardena Smart System and Automower Connect) have a monthly request quota of approximately 10,000 requests/month per application. This page describes how the integration stays within those limits and what happens when they are exceeded.

Each API has its own independent budget. Using one does not affect the other. Both APIs share the same OAuth token endpoint, but token requests do not count against the per-API quota.

Data Updates — Architecture

Both APIs use the same architecture: real-time WebSocket push with REST polling fallback. Each API maintains its own connection.

Gardena Smart System API

Startup (every HA restart or integration reload):

# API Call Purpose
1 POST /oauth2/token Acquire an OAuth2 access token
2 GET /locations/{id} Fetch all devices and their current state
3 POST /websocket Request a WebSocket URL for real-time updates
4 WebSocket connect Open the persistent connection for push updates

That is 3 REST calls + 1 WebSocket connection per startup.

Normal operation (WebSocket connected):

API Call Frequency Purpose
GET /locations/{id} every 1 hour Health-check poll — verifies device list, detects new devices
POST /oauth2/token every ~55 minutes Token refresh (separate endpoint, doesn't count against quota)
WebSocket messages continuous (push) All device state updates arrive here at zero REST cost

Daily total: ~24 health-check polls/day — roughly 7 % of the monthly budget.

Fallback operation (WebSocket down):

API Call Frequency Purpose
GET /locations/{id} every 5 minutes Poll for device state (matches Gardena sensor hardware update frequency)
POST /oauth2/token every ~55 minutes Token refresh

Daily total: ~288 polls/day — roughly 86 % of the monthly budget.

Automower Connect API

Startup:

# API Call Purpose
1 POST /oauth2/token Acquire an OAuth2 access token (shared auth)
2 GET /mowers Fetch all mowers and their current state
3 WebSocket connect Open the persistent connection for push updates

Normal operation (WebSocket connected):

API Call Frequency Purpose
GET /mowers every 1 hour Health-check poll
POST /oauth2/token every ~55 minutes Token refresh
WebSocket messages continuous (push) All mower state updates

Daily total: ~24 polls/day — roughly 7 % of the monthly budget.

Fallback operation (WebSocket down):

API Call Frequency Purpose
GET /mowers every 5 minutes Poll for mower state
POST /oauth2/token every ~55 minutes Token refresh

Daily total: ~288 polls/day — roughly 86 % of the monthly budget.

User-Triggered Commands

API Call Throttle Purpose
PUT /command/{id} (Gardena) token bucket — 10 tokens, refill 1 / 5 s Valve, switch, mower commands
POST /mowers/{id}/actions (Automower) token bucket — 10 tokens, refill 1 / 5 s Mower actions (start, pause, park)
PATCH /mowers/{id}/settings (Automower) token bucket — 10 tokens, refill 1 / 5 s Cutting height, headlight, stay-out zones

Each button press or automation action is one API call. The token bucket allows small bursts (e.g. opening several valves in a row) while capping the long-term steady-state rate at ≤1 command / 5 s.

How the Integration Stays Within Limits

Strategy Detail
WebSocket-first architecture State updates arrive in real time via persistent WebSocket. REST polling is only a fallback. The outer reconnect loop attempts reconnection 3 times over ~20 minutes (60 s → 5 min → 15 min), each time fetching a fresh signed WS URL. A watchdog timer checks every 60 s that the WebSocket is still receiving data — if silent for 5 min, the connection is forcibly recycled.
Single-use WebSocket URLs Husqvarna's signed WS URLs are single-use — once rejected (e.g. HTTP 410), retrying the same URL is pointless. Any failure is escalated immediately to the coordinator instead of burning bandwidth on the dead URL. A fresh URL is fetched on each new connect attempt.
WebSocket URL caching Within a single connect attempt the freshly fetched URL is cached and reused while the auth token is still valid. The cache is invalidated when the token expires or a connect attempt fails.
Connect guard An async lock prevents parallel WebSocket connect attempts (e.g. watchdog and poll cycle racing), avoiding duplicate API calls.
Circuit breaker After 3 consecutive WebSocket start failures the integration enters a 15-minute cooldown during which no new WebSocket connection is attempted (REST polling continues). The cooldown escalates to 30 min after 5 failures and 60 min after 7+. A successful connection resets the counter. Auth errors bypass the circuit breaker and trigger reauth instead.
WS handshake kill-switch After repeated 4xx handshake rejections (e.g. HTTP 410/403/429 — typical of a server-side blocked Application), the WebSocket subsystem is suspended for 1 hour and REST polling is also paused until a real device update confirms the stream is healthy. Prevents account-block scenarios from burning ~288 REST calls/day for nothing. A repair issue (husqvarna_application_blocked) points the user at rotating the Husqvarna application. The kill-switch state is persisted to disk (since 1.12.8) so it survives HA restarts and config-entry setup retries — the previous in-memory-only counter was reset on every retry, leaving the integration stuck in a 5-minute "fail → fresh coordinator → fail" loop that burned quota confirming the same block over and over.
Persistent application-block detector When the rate-limit ladder fires ≥10 times AND no successful poll has happened in the last 24 hours (or no successful poll has ever happened with the current Application), the same husqvarna_application_blocked repair issue is raised — even without a WebSocket handshake denial. Symptom of a server-side block where REST and WS both keep returning 429/410; the only fix is to rotate the Application. The issue clears automatically after several consecutive successful polls.
WS session timer (since v2.0.5) Husqvarna enforces a server-side 2-hour maximum on WebSocket sessions for load balancing. When the server sends a graceful CLOSE at the 2-hour mark, the library exits normally (no error), so _ws_connected would have silently stayed True. A one-shot timer (WS_MAX_SESSION_SECONDS = 6900 s, 1 h 55 min) is now scheduled each time a session is established. On expiry, _async_ws_session_expired() proactively disconnects and schedules a normal reconnect — no data gap, no stale state. The timer is cancelled on explicit error or shutdown.
Adaptive polling interval When WebSocket is connected: 1-hour health-check only. When WebSocket drops: 5-minute polling (matches sensor hardware update rate).
Graduated rate-limit backoff If any API call returns HTTP 429 — including token refresh and WS-URL requests — polling backs off exponentially (5 min → 10 → 20 → 40 → 60 min max) and resets after several consecutive successful responses.
Command throttling (token bucket) 10 commands, refilling at 1 token per 5 s. Allows small bursts while keeping the long-term rate at ≤1 command / 5 s.
Auto-stop safety net When the monthly API budget drops below 5 % remaining (fewer than 500 of the 10 000 requests), the coordinator pauses REST polls, WebSocket (re)connect attempts, and user-issued commands — the latter return a translated error (api_budget_exhausted). Normal operation resumes at the start of the next calendar month, or earlier if a new Husqvarna application is created.
Independent budgets Both APIs have their own ~10 000 requests/month quota. Using one does not affect the other.

Tips for Avoiding Rate Limits

  • Don't restart Home Assistant frequently. Each restart triggers a full API poll and a new WebSocket connection.
  • Avoid rapid-fire automations. If you have automations that send multiple commands in a loop, add delays between them. The integration enforces a 5-second minimum, but longer pauses are better for the quota.
  • Use a dedicated API key for Home Assistant. The budget tracking sensors assume the full 10 000 requests/month are available exclusively for this integration. Sharing the same Husqvarna application credentials with another smart-home platform invalidates the budget percentage. Create a separate application on the Husqvarna Developer Portal for each system.
  • Use one integration instance per API. Each additional instance adds its own polling and WebSocket overhead.
  • Monitor for rate-limit warnings. Check Home Assistant logs for messages containing "Rate limited". The hub diagnostic sensor API budget remaining is also a good basis for alerting automations.

What Happens When Rate Limited

  1. The integration logs a warning (e.g. Rate limited by Gardena API (hit #1), backing off to 0:05:00).
  2. The polling interval increases with graduated backoff: 5 min → 10 min → 20 min → 40 min → 60 min (max).
  3. Existing entity states remain available (cached from the last successful update and WebSocket messages).
  4. Commands may fail until the rate limit resets.
  5. After several consecutive successful API responses the backoff counter resets and the normal polling interval is restored.
  6. If the monthly budget has been almost fully consumed (< 5 % remaining), the auto-stop safety net takes over: polls, WS reconnects, and commands are refused until the calendar month rolls over.

See also: Troubleshooting

Clone this wiki locally