This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Husqvarna lawn robot mover API
#6
Hi Erwin,
hi Admin,

many thanks for your help. This lead into a working solution.

For all guys who like to control (start/stop) the Husqvarna Automower via LM/W4K and a KNX button here is the description:
  • Register for Husqvarna Developer account: https://developer.husqvarnagroup.cloud 
  • Generate an application inside the portal to get the client ID and security ID
  • Extract the Mower ID with the following script:

Code:
local https = require('ssl.https')
local json = require('json')

-- Husqvarna Authentication API
local authEndpoint = 'https://api.authentication.husqvarnagroup.dev/v1/oauth2/token'
local clientId = 'xxx
local clientSecret = 'xxx'

-- Husqvarna Automower Connect API
local mowersEndpoint = 'https://api.amc.husqvarna.dev/v1/mowers'

local accessToken

-- Funktion zum Erhalten eines Zugriffstokens
function getAccessToken()
    local requestBody = 'grant_type=client_credentials'
        .. '&client_id=' .. clientId
        .. '&client_secret=' .. clientSecret

    local response_body = {}
    local _, code, _, _ = https.request{
        url = authEndpoint,
        method = 'POST',
        headers = {
            ['Content-Type'] = 'application/x-www-form-urlencoded',
            ['Content-Length'] = #requestBody
        },
        source = ltn12.source.string(requestBody),
        sink = ltn12.sink.table(response_body)
    }
log (code, status, headers, response_body)


    if code == 200 then
        local response = table.concat(response_body)
        local jsonResponse = json.decode(response)
        accessToken = jsonResponse.access_token
    else
        -- Fehlerbehandlung
        print('Fehler beim Abrufen des Zugriffstokens:', code)
    end
end

-- Funktion zum Abrufen der Mower-IDs
function getMowerIds()
    local response_body = {}
    local _, code, _, _ = https.request{
        url = mowersEndpoint,
        method = 'GET',
        headers = {
            ['Authorization'] = 'Bearer ' .. accessToken,
            ['X-Api-Key'] = clientId,
            ['Authorization-Provider'] = 'husqvarna'
        },
        sink = ltn12.sink.table(response_body)
    }
log (code, status, headers, response_body)



    if code == 200 then
        local response = table.concat(response_body)
    log(response)
        local jsonResponse = json.decode(response)
       
        for _, mower in ipairs(jsonResponse.data) do
            local mowerId = mower.id
            -- Verarbeiten Sie die Mower-ID hier nach Bedarf
            print('Mower-ID:', mowerId)
           
        log(mowerId)
        end
    else
        -- Fehlerbehandlung
        print('Fehler beim Abrufen der Mower-IDs:', code)
    end
end

-- Beispielaufrufe
getAccessToken()
getMowerIds()

  • Generate an scheduled script every 5 minutes (due to 10000 requests per month restriction) to request the status of the robot:

Code:
local https = require('ssl.https')
local json = require('json')

-- Husqvarna Authentication API
local authEndpoint = 'https://api.authentication.husqvarnagroup.dev/v1/oauth2/token'
local clientId = 'xxx'
local clientSecret = 'xxx
local moverID = 'xxx

-- Husqvarna Automower Connect API
local connectEndpoint = 'https://api.amc.husqvarna.dev/v1/mowers/'..moverID..'/actions'
local connectEndpointstatus = 'https://api.amc.husqvarna.dev/v1/mowers/'..moverID


local accessToken

-- Funktion zum Erhalten eines Zugriffstokens
function getAccessToken()
    local requestBody = 'grant_type=client_credentials'
        .. '&client_id=' .. clientId
        .. '&client_secret=' .. clientSecret

    local response_body = {}
    local _, code, _, _ = https.request{
        url = authEndpoint,
        method = 'POST',
        headers = {
            ['Content-Type'] = 'application/x-www-form-urlencoded',
            ['Content-Length'] = #requestBody
        },
        source = ltn12.source.string(requestBody),
        sink = ltn12.sink.table(response_body)
    }

    if code == 200 then
        local response = table.concat(response_body)
        local jsonResponse = json.decode(response)
        accessToken = jsonResponse.access_token
    else
        -- Fehlerbehandlung
     --   log('Fehler beim Abrufen des Zugriffstokens:', code)
    end
end

-- Funktion zum Abrufen des Status
function statusrequest()
    local response_body = {}
    local res, code = https.request{
        url = connectEndpointstatus,
        method = 'GET',
        headers = {
            ['Authorization'] = 'Bearer ' .. accessToken,
            ['X-Api-Key'] = clientId,
            ['Authorization-Provider'] = 'husqvarna',
            ['Content-Type'] = 'application/vnd.api+json',
        },
        source = ltn12.source.string(requestBody),
        sink = ltn12.sink.table(response_body)
    }
     local data = json.decode(table.concat(response_body))
   
   status_mower = data.data.attributes.mower.state

 
log (code, status, headers, response_body, data, status_mower)
   
    if code == 200 then
        -- Erfolgreich abgefragt
        --log('Automower Status abgefragt.')
    else
        -- Fehlerbehandlung
        --log('Fehler beim Starten des Automowers:', code)
    end
end


--Aufruf der Befehle
getAccessToken()
statusrequest()

-- Status auswerten und ans KNX senden
if status_mower == "STOPPED" or status_mower == "RESTRICTED" then
     grp.checkwrite('12/4/1', false)
end
   
if status_mower == "IN_OPERATION" then
     grp.checkwrite('12/4/1', true)   
end
  • Generate an event based script corresponding to the buttons group address:

Code:
local https = require('ssl.https')
local json = require('json')

-- Husqvarna Authentication API
local authEndpoint = 'https://api.authentication.husqvarnagroup.dev/v1/oauth2/token'
local clientId = 'xxx'
local clientSecret = 'xxx
local moverID = 'xxx

-- Husqvarna Automower Connect API
local connectEndpoint = 'https://api.amc.husqvarna.dev/v1/mowers/'..moverID..'/actions'
local connectEndpointstatus = 'https://api.amc.husqvarna.dev/v1/mowers/'..moverID


local accessToken

-- Funktion zum Erhalten eines Zugriffstokens
function getAccessToken()
    local requestBody = 'grant_type=client_credentials'
        .. '&client_id=' .. clientId
        .. '&client_secret=' .. clientSecret

    local response_body = {}
    local _, code, _, _ = https.request{
        url = authEndpoint,
        method = 'POST',
        headers = {
            ['Content-Type'] = 'application/x-www-form-urlencoded',
            ['Content-Length'] = #requestBody
        },
        source = ltn12.source.string(requestBody),
        sink = ltn12.sink.table(response_body)
    }

    if code == 200 then
        local response = table.concat(response_body)
        local jsonResponse = json.decode(response)
        accessToken = jsonResponse.access_token
    else
        -- Fehlerbehandlung
        --log('Fehler beim Abrufen des Zugriffstokens:', code)
    end
end


-- Funktion zum Senden des Startbefehls
function sendStartCommand()
    local requestBody = json.encode({
        data = {
           type = 'Start',
           attributes = {
           duration = 400
               }
               }
              })
    local response_body = {}
    local _, code, _, _ = https.request{
        url = connectEndpoint,
        method = 'POST',
        headers = {
            ['Authorization'] = 'Bearer ' .. accessToken,
            ['X-Api-Key'] = clientId,
            ['Authorization-Provider'] = 'husqvarna',
            ['Content-Type'] = 'application/vnd.api+json',
            ['Content-Length'] = #requestBody
        },
        source = ltn12.source.string(requestBody),
        sink = ltn12.sink.table(response_body)
    }
   
log (code, status, headers, response_body)



    if code == 202 then
        -- Erfolgreich gestartet
        --log('Automower wurde gestartet.')
        grp.checkwrite('12/4/1', true)
    else
        -- Fehlerbehandlung
        --log('Fehler beim Starten des Automowers:', code)
    end
end

-- Funktion zum Senden des Stopbefehls
function sendStopCommand()
    local requestBody = json.encode({
      data = {
        type = 'ParkUntilNextSchedule',
      }
    })
    local response_body = {}
    local _, code, _, _ = https.request{
        url = connectEndpoint,
        method = 'POST',
        headers = {
            ['Authorization'] = 'Bearer ' .. accessToken,
            ['X-Api-Key'] = clientId,
            ['Authorization-Provider'] = 'husqvarna',
            ['Content-Type'] = 'application/vnd.api+json',
            ['Content-Length'] = #requestBody
        },
        source = ltn12.source.string(requestBody),
        sink = ltn12.sink.table(response_body)
    }
    log (code, status, headers, response_body)



    if code == 202 then
        -- Erfolgreich gestoppt
        --log('Automower wurde gestoppt.')
        grp.checkwrite('12/4/1', false)
    else
        -- Fehlerbehandlung
        --log('Fehler beim Stoppen des Automowers:', code)
    end
end

--Aufruf Starten des Automover
mover_command = grp.getvalue('12/4/0')

if mover_command == true then
    getAccessToken()
    sendStartCommand()
end
   
--Aufruf Stoppen des Automover
mover_command = grp.getvalue('12/4/0')
   
if mover_command == false then
    getAccessToken()
    sendStopCommand()
end


I hope this is helping somebody. If you have questions please let me know.

Best Regards
Steffen
Reply


Messages In This Thread
RE: Husqvarna lawn robot mover API - by admin - 12.06.2023, 12:27
RE: Husqvarna lawn robot mover API - by admin - 16.06.2023, 07:33
RE: Husqvarna lawn robot mover API - by pioneersteffen - 18.06.2023, 19:34
RE: Husqvarna lawn robot mover API - by Joep - 31.07.2023, 14:40
RE: Husqvarna lawn robot mover API - by admin - 19.06.2023, 08:00
RE: Husqvarna lawn robot mover API - by Joep - 06.09.2023, 15:38

Forum Jump: