Posts: 115
Threads: 23
Joined: Sep 2021
Reputation:
2
10.06.2023, 13:15
(This post was last modified: 11.06.2023, 07:20 by pioneersteffen.)
Hi @all,
I want to connect my Husqvarna lawn robot to LM.
There is an existing API which is documented here: https://developer.husqvarnagroup.cloud/a...onnect-api
I think I'm not fare away from the goal to start and stop the robot via LM but I struggling with the payload.
After I registrated to Husqvarna development portal I created a script to find out the mover-id:
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()
In the second step I tried to write a script to start and stop 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/ba15739b-0449-411a-9eb9-9ad866362075/actions'
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 = '{"action":"start"}'
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/json',
['Content-Length'] = #requestBody
},
source = ltn12.source.string(requestBody),
sink = ltn12.sink.table(response_body)
}
log (code, status, headers, response_body)
if code == 200 then
-- Erfolgreich gestartet
log('Automower wurde gestartet.')
else
-- Fehlerbehandlung
log('Fehler beim Starten des Automowers:', code)
end
end
-- Funktion zum Senden des Stopbefehls
function sendStopCommand()
local requestBody = '{"name": "stop"}'
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/json',
['Content-Length'] = #requestBody
},
source = ltn12.source.string(requestBody),
sink = ltn12.sink.table(response_body)
}
log (code, status, headers, response_body)
if code == 200 then
-- Erfolgreich gestoppt
log('Automower wurde gestoppt.')
else
-- Fehlerbehandlung
log('Fehler beim Stoppen des Automowers:', code)
end
end
-- Beispielaufrufe
getAccessToken()
sendStartCommand()
If I call the script to start the robot I getting the following failures:
Code: Automover 10.06.2023 15:12:33
* arg: 1
* number: 400
* arg: 2
* nil
* arg: 3
* nil
* arg: 4
* table:
[1]
* string: {"errors":[{"id":"f211fb25-ae93-44e7-820f-ccb35adb2484","status":"400","code":"illegal.argument","title":"Illegal argument","detail":"Unsupported Media Type. Likely an invalid Content-Type header value. Use 'application/vnd.api+json' or 'application/json' depending on endpoint."}]}
Automover 10.06.2023 15:12:33
* arg: 1
* string: Fehler beim Starten des Automowers:
* arg: 2
* number: 400
Do you have any idea what I making wrong and need to change?
Many thanks for your help!
Best Regards
Steffen
Posts: 7769
Threads: 42
Joined: Jun 2015
Reputation:
447
Have you tried doing what the error message suggests - set application/vnd.api+json content-type header? Also check request data format: https://developer.husqvarnagroup.cloud/a...api#readme
Use json.encode instead of raw JSON string or you will run into syntax errors.
Posts: 115
Threads: 23
Joined: Sep 2021
Reputation:
2
15.06.2023, 18:02
(This post was last modified: 15.06.2023, 18:06 by pioneersteffen.)
Hi Admin,
many thanks for your help and feedback.
I tried to implement your hints:
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 connectEndpoint = 'https://api.amc.husqvarna.dev/v1/mowers/ba15739b-0449-411a-9eb9-9ad866362075/actions'
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 = '{"type: 'Start', attributes: { duration: 24 // minutes}'
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 == 200 then
-- Erfolgreich gestartet
log('Automower wurde gestartet.')
else
-- Fehlerbehandlung
log('Fehler beim Starten des Automowers:', code)
end
end
-- Funktion zum Senden des Stopbefehls
function sendStopCommand()
local requestBody = '{"name": "stop"}'
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/json',
['Content-Length'] = #requestBody
},
source = ltn12.source.string(requestBody),
sink = ltn12.sink.table(response_body)
}
log (code, status, headers, response_body)
if code == 200 then
-- Erfolgreich gestoppt
log('Automower wurde gestoppt.')
else
-- Fehlerbehandlung
log('Fehler beim Stoppen des Automowers:', code)
end
end
-- Beispielaufrufe
getAccessToken()
sendStartCommand()
Unfortunately I getting the following failure:
Code: string: {"errors":[{"id":"e9f44309-1dfb-48bf-a0b3-dcab8111951d","status":"500","code":"internal.error","title":"Internal error","detail":""}]}
I think the body might be in the wrong format?!
Code: local requestBody = '{"type: 'Start', attributes: { duration: 24 // minutes}'
Any ideas how to improve?
Many thanks for your help!
Best Regards
Steffen
Posts: 1764
Threads: 6
Joined: Jul 2015
Reputation:
117
16.06.2023, 06:06
(This post was last modified: 16.06.2023, 06:27 by Erwin van der Zwart.)
Your payload is not a valid JSON, try : {"type": "Start", "attributes":[{"duration":"24 // minutes"}]}
You can test your payload at https://jsoneditoronline.org/
Are you sure the duration is like "24 // minutes" and not just the value 24 like {"type": "Start", "attributes":[{"duration":24}]}?
Posts: 7769
Threads: 42
Joined: Jun 2015
Reputation:
447
Try this:
Code: local requestBody = json.encode({
data = {
type = 'Start',
attributes = {
duration = 24
}
}
})
Posts: 115
Threads: 23
Joined: Sep 2021
Reputation:
2
18.06.2023, 19:34
(This post was last modified: 21.06.2023, 17:39 by pioneersteffen.)
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
Posts: 115
Threads: 23
Joined: Sep 2021
Reputation:
2
Hi @all,
during testing I found an issue with this string compare:
Code: if status_mower == "STOPPED" or status_mover == "RESTRICTED" then
grp.checkwrite('12/4/1', false)
end
Can you please help me and give me a hint how to improve it?
Many thanks!
Best Regards
Steffen
Posts: 7769
Threads: 42
Joined: Jun 2015
Reputation:
447
You have two different variables there - status_mower and status_mover. The docs state that there's a 10000 request limit per month. This means that you should retrieve the status not more often than once in 5 minutes.
Posts: 115
Threads: 23
Joined: Sep 2021
Reputation:
2
(19.06.2023, 08:00)admin Wrote: You have two different variables there - status_mower and status_mover. The docs state that there's a 10000 request limit per month. This means that you should retrieve the status not more often than once in 5 minutes.
Many thanks, it is working now. I corrected the script and the description in post #6.
Posts: 111
Threads: 14
Joined: Nov 2019
Reputation:
6
(18.06.2023, 19:34)pioneersteffen Wrote: 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
Hi Steffen,
When i try to get the Mower ID i got nothing back as you can see below. Do you know if i need to take some extra steps or something?
* arg: 1
* number: 200
* arg: 2
* nil
* arg: 3
* nil
* arg: 4
* table:
[1]
* string: {"data":[]}
the access token part is working fine for me.
Best regards and thanks in advance,
Joep
Posts: 111
Threads: 14
Joined: Nov 2019
Reputation:
6
I tried a lot so far but without luck. I hope someone can tell me what i do wrong as it seems to be a pairing issue but i have no idea how to solve it. The mower is registered from my account and i have created an application. I can also receive the Accesstoken so that part works.
["errors"]
* table:
[1]
* table:
["detail"]
* string: No pairing between the user and the mower product.
["title"]
* string: No mower pairing
["id"]
* string: 20c27a49-29be-4dd5-b055-b5bc8f5ef82f
["status"]
* string: 404
["code"]
* string: no.mower.pairing
|