Created At

Sep 27, 2025

Last Update

Sep 29, 2025

Platforms

HC 3 Lite, HC Lite, Yubii Home, HC 3

Views

387

Download

16

Type Quick App

Licence

Plugin is free to download and has a 5 day expiry runout. After any support coming to my account using the link below (even a coffee), i will provide the license key version in PM.

Buy me a coffe

HC3 QuickApp — Husqvarna Automower (WS-first, REST fallback)

 

A lightweight QuickApp for Husqvarna Automower that prefers WebSocket live updates and falls back to REST polling if the socket isn’t available. Uses OAuth2 client_credentials (no redirect uri needed) with your developer APP_KEY and APP_SECRET.


✨ At a glance

  • Auth: client_credentials; no redirect, no user login.

  • Tokens: auto-renewed 1 minute before expiry; renewal is logged to the QA log label.

  • Transport: WebSocket live events → if it closes, automatically falls back to polling and (if WS reconnect loop is enabled) opportunistically reconnects while polling.

  • Controls: Start for N hours, Park for N hours / until next schedule / until further notice, Pause/Resume.

  • Status: Exposes device properties and maintains global variables for status/activity/error.

  • UI: Optional WS Debug and WS Ping toggles.


✅ Requirements

  • Fibaro HC3 / Yubii with QA support.

  • Husqvarna developer credentials: APP_KEY and APP_SECRET with scopes:
    iam:read amc:read amc:control amc:api


⚙️ Install & Setup

  1. Import the QuickApp (QA) into your HC3.

  2. Open the QA → Variables tab and fill at minimum:

    • APP_KEY — your Husqvarna app key

    • APP_SECRET — your Husqvarna app secret

  3. Optional variables (sensible defaults exist):

    • AUTH_SCOPE = iam:read amc:read amc:control amc:api

    • MOWER_NAME — exact mower name to bind to (if you have more than one)

    • POLL_SEC — REST polling interval (default 360)

    • WS_URLwss://ws.openapi.husqvarna.dev/v1

    • WS_MAX_ATTEMPTS — socket connect retries before falling back (default 2)

    • WS_RETRY_DELAY_S — delay between WS retries (default 5)

    • WS_ENABLE_PING0/1 keepalive ping (default 0)

    • WS_PING_SEC — ping period seconds (default 60)

    • LABEL_COLOR — hex color for labels (default #1e90ff)

  4. Start the QA. It will:

    • fetch an access token using APP_KEY/APP_SECRET,

    • discover your mower ID,

    • open WebSocket and begin live updates (else start polling).


🔐 Authentication & Token Handling

  • Flow: OAuth2 client_credentials (APP_KEY + APP_SECRET in a Basic header) → /oauth2/token.

  • The QA saves:

    • self.token — bearer token,

    • self.tokenExpearly renewal timestamp (now + expires_in − 60s),

    • self.tokenExpActualactual expiry (now + expires_in).

  • It auto-renews ~1 minute before the old token expires.

  • You’ll see in the QA logs (and lbl_qa_logs label):

    • [Auth] New access token received (client_credentials).

    • [Auth] Expires at 2025-… (in 1 h 59 m …)


🔌 Transport Strategy (WS-first)

  • On start the QA opens the WebSocket.

  • If WS connectslive events; REST polling stops.

  • If WS fails/closes after WS_MAX_ATTEMPTS:

    • QA switches to REST polling every POLL_SEC seconds.

  • WS reconnect loop (recommended):

    • If you enabled the reconnect loop version, the QA periodically attempts a WS reconnect while it continues polling, returning to WS automatically once it succeeds.

  • WS ping (optional): enable via UI or WS_ENABLE_PING=1 to send a ping every WS_PING_SEC seconds (helps keep the connection alive).


🖱️ Available Actions (buttons & scenes)

Button equivalents (built-in):

  • pause — Pause mowing

  • resume — Resume schedule

  • start3h / start6h / start12h — Start for N hours

  • park3h / park6h / park12h — Park for N hours

  • parkUntilFurtherNotice — Park indefinitely

  • parkUntilNextSchedule — Park until next schedule

Generic actions (with duration in hours):

 
local qaId = <YOUR_MOWER_QA_ID> -- Pause / Resume fibaro.call(qaId, "pause") fibaro.call(qaId, "resume") -- Start mowing for N hours fibaro.call(qaId, "start", { tonumber(3) }) -- 3 hours fibaro.call(qaId, "start", { tonumber(6) }) -- 6 hours -- Park for N hours fibaro.call(qaId, "park", { tonumber(2) }) -- 2 hours -- Park indefinitely or until next schedule fibaro.call(qaId, "parkUntilFurtherNotice") fibaro.call(qaId, "parkUntilNextSchedule")

Internally the QA maps:

  • START {duration = hours} → JSON:API Start with minutes

  • PARK {duration = hours} → JSON:API Park with minutes

  • RESUMEResumeSchedule

  • PARK_UNTIL_FURTHERParkUntilFurtherNotice

  • PARK_UNTIL_NEXTParkUntilNextSchedule

Husqvarna API note (for Park action):

  • Park with duration (minutes)

  • ParkUntilFurtherNotice (no body attributes)

  • ParkUntilNextSchedule (no body attributes)


📡 Built-in Device Properties

These are device properties exposed by the QuickApp. Read them with:

 
local qaId = <YOUR_MOWER_QA_ID> local state = fibaro.getValue(qaId, "mowerState") local activity = fibaro.getValue(qaId, "mowerActivity") local mode = fibaro.getValue(qaId, "mowerMode") local errCode = fibaro.getValue(qaId, "mowerErrorCode") local mowerId = fibaro.getValue(qaId, "mowerId") local battery = fibaro.getValue(qaId, "batteryLevel") -- 0..100

🌐 Global Variables (auto-created & updated)

The QA creates and maintains three global variables based on the mower name:

  • <SanitizedMowerName>_status — enum of current state (e.g., IN_OPERATION, PARKED, CHARGING, …)

  • <SanitizedMowerName>_activity — enum of current activity (e.g., MOWING, GOING_HOME, PARKED_TIMER, …)

  • <SanitizedMowerName>_error — enum of current error code (auto-extends when new codes appear)

Notes

  • The base is the mower’s name sanitized to [A-Z0-9_].

  • Enums are created once, then values are set as events arrive.

  • Error enum can auto-extend to include new error codes reported by the API.

Example usage in scenes:

 
local base = "My_Mower" -- your sanitized mower name local status = fibaro.getGlobalVariable(base .. "_status") local activity = fibaro.getGlobalVariable(base .. "_activity") local err = fibaro.getGlobalVariable(base .. "_error") if status == "ERROR" or err ~= "NONE" then -- Notify or automate here end

🧪 Troubleshooting

  • 401 / 403 on inventory or actions → your app is missing scopes. Ensure amc:read (inventory) and amc:control (actions).

  • 404 on actions → almost always missing amc:control on your app.

  • Socket keeps closing → enable WS Ping, and ensure outbound wss is allowed by your network.

  • Multiple mowers → set MOWER_NAME to pick the right one.


📝 Change Highlights (this edition)

  • Removed old Auth-Code/redirect flow; client_credentials only.

  • Auto token renewal with early refresh; logs expiry time.

  • Clean WS pipeline + graceful fallback to polling.

  • Optional WS reconnect loop (opportunistic reconnect while polling).

  • Device properties + global variables for status, activity, error.


📚 Scene Snippets

Start at sunset for 2h if battery > 60%

 
local qaId = <YOUR_MOWER_QA_ID> local battery = tonumber(fibaro.getValue(qaId, "batteryLevel")) or 0 if battery > 60 then fibaro.call(qaId, "start", { tonumber(2) }) end

Park until next schedule if it’s raining

 
local qaId = <YOUR_MOWER_QA_ID> -- (replace with your rain detection logic) local raining = fibaro.getGlobalVariable("IsRaining") == "true" if raining then fibaro.call(qaId, "parkUntilNextSchedule") end

📌 UI Toggles (bottom of QA)

 

  • WS debug: Prints raw WS events to logs.

  • WS ping: Sends periodic ping frames to keep connection alive.

 

Licence

Plugin is free to download and has a 5 day expiry runout. After any support coming to my account using the link below (even a coffee), i will provide the license key version in PM.

Buy me a coffe

0 Comments,  Want to add comment please login
Load more comments
© 2024. Nice-Polska Sp. z o.o.Privacy policyTerms & ConditionsFeedback