Posts: 120
Threads: 24
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
local https =
require (
'ssl.https' )
local json =
require (
'json' )
local authEndpoint =
'https://api.authentication.husqvarnagroup.dev/v1/oauth2/token'
local clientId =
'XXX'
local clientSecret =
'XXX
local mowersEndpoint =
'https://api.amc.husqvarna.dev/v1/mowers'
local accessToken
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
print (
'Fehler beim Abrufen des Zugriffstokens:' ,
code )
end
end
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
print (
'Mower-ID:' ,
mowerId )
log (
mowerId )
end
else
print (
'Fehler beim Abrufen der Mower-IDs:' ,
code )
end
end
getAccessToken ()
getMowerIds ()
In the second step I tried to write a script to start and stop the robot:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
local https =
require (
'ssl.https' )
local json =
require (
'json' )
local authEndpoint =
'https://api.authentication.husqvarnagroup.dev/v1/oauth2/token'
local clientId =
'xxx
local clientSecret =
'xxx'
local moverID =
'xxx'
local connectEndpoint =
'https://api.amc.husqvarna.dev/v1/mowers/ba15739b-0449-411a-9eb9-9ad866362075/actions'
local accessToken
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
log (
'Fehler beim Abrufen des Zugriffstokens:' ,
code )
end
end
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
log (
'Automower wurde gestartet.' )
else
log (
'Fehler beim Starten des Automowers:' ,
code )
end
end
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
log (
'Automower wurde gestoppt.' )
else
log (
'Fehler beim Stoppen des Automowers:' ,
code )
end
end
getAccessToken ()
sendStartCommand ()
If I call the script to start the robot I getting the following failures:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
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: 8211
Threads: 43
Joined: Jun 2015
Reputation:
473
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: 120
Threads: 24
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
local https =
require (
'ssl.https' )
local json =
require (
'json' )
local authEndpoint =
'https://api.authentication.husqvarnagroup.dev/v1/oauth2/token'
local clientId =
'xxx'
local clientSecret =
'xxx'
local connectEndpoint =
'https://api.amc.husqvarna.dev/v1/mowers/ba15739b-0449-411a-9eb9-9ad866362075/actions'
local accessToken
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
log (
'Fehler beim Abrufen des Zugriffstokens:' ,
code )
end
end
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
log (
'Automower wurde gestartet.' )
else
log (
'Fehler beim Starten des Automowers:' ,
code )
end
end
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
log (
'Automower wurde gestoppt.' )
else
log (
'Fehler beim Stoppen des Automowers:' ,
code )
end
end
getAccessToken ()
sendStartCommand ()
Unfortunately I getting the following failure:
Code:
1
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:
1
local requestBody =
'{"type: ' Start ', attributes: { duration: 24 // minutes}'
Any ideas how to improve?
Many thanks for your help!
Best Regards
Steffen
Posts: 1807
Threads: 7
Joined: Jul 2015
Reputation:
121
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: 8211
Threads: 43
Joined: Jun 2015
Reputation:
473
Try this:
Code:
1 2 3 4 5 6 7 8
local requestBody =
json.encode ({
data = {
type =
'Start' ,
attributes = {
duration =
24
}
}
})
Posts: 120
Threads: 24
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
local https =
require (
'ssl.https' )
local json =
require (
'json' )
local authEndpoint =
'https://api.authentication.husqvarnagroup.dev/v1/oauth2/token'
local clientId =
'xxx
local clientSecret =
'xxx'
local mowersEndpoint =
'https://api.amc.husqvarna.dev/v1/mowers'
local accessToken
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
print (
'Fehler beim Abrufen des Zugriffstokens:' ,
code )
end
end
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
print (
'Mower-ID:' ,
mowerId )
log (
mowerId )
end
else
print (
'Fehler beim Abrufen der Mower-IDs:' ,
code )
end
end
getAccessToken ()
getMowerIds ()
Generate an scheduled script every 5 minutes (due to 10000 requests per month restriction) to request the status of the robot:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
local https =
require (
'ssl.https' )
local json =
require (
'json' )
local authEndpoint =
'https://api.authentication.husqvarnagroup.dev/v1/oauth2/token'
local clientId =
'xxx'
local clientSecret =
'xxx
local moverID =
'xxx
local connectEndpoint =
'https://api.amc.husqvarna.dev/v1/mowers/' ..
moverID.. '/actions'
local connectEndpointstatus =
'https://api.amc.husqvarna.dev/v1/mowers/' ..
moverID
local accessToken
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
end
end
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
else
end
end
getAccessToken ()
statusrequest ()
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
local https =
require (
'ssl.https' )
local json =
require (
'json' )
local authEndpoint =
'https://api.authentication.husqvarnagroup.dev/v1/oauth2/token'
local clientId =
'xxx'
local clientSecret =
'xxx
local moverID =
'xxx
local connectEndpoint =
'https://api.amc.husqvarna.dev/v1/mowers/' ..
moverID.. '/actions'
local connectEndpointstatus =
'https://api.amc.husqvarna.dev/v1/mowers/' ..
moverID
local accessToken
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
end
end
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
grp.checkwrite (
'12/4/1' ,
true )
else
end
end
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
grp.checkwrite (
'12/4/1' ,
false )
else
end
end
mover_command =
grp.getvalue (
'12/4/0' )
if mover_command ==
true then
getAccessToken ()
sendStartCommand ()
end
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: 120
Threads: 24
Joined: Sep 2021
Reputation:
2
Hi @all,
during testing I found an issue with this string compare:
Code:
1 2 3
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: 8211
Threads: 43
Joined: Jun 2015
Reputation:
473
You have two different variables there - status_mow er and status_mov er. 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: 120
Threads: 24
Joined: Sep 2021
Reputation:
2
(19.06.2023, 08:00) admin Wrote: You have two different variables there - status_mow er and status_mov er. 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: 119
Threads: 15
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
local https =
require (
'ssl.https' )
local json =
require (
'json' )
local authEndpoint =
'https://api.authentication.husqvarnagroup.dev/v1/oauth2/token'
local clientId =
'xxx
local clientSecret =
'xxx'
local mowersEndpoint =
'https://api.amc.husqvarna.dev/v1/mowers'
local accessToken
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
print (
'Fehler beim Abrufen des Zugriffstokens:' ,
code )
end
end
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
print (
'Mower-ID:' ,
mowerId )
log (
mowerId )
end
else
print (
'Fehler beim Abrufen der Mower-IDs:' ,
code )
end
end
getAccessToken ()
getMowerIds ()
Generate an scheduled script every 5 minutes (due to 10000 requests per month restriction) to request the status of the robot:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
local https =
require (
'ssl.https' )
local json =
require (
'json' )
local authEndpoint =
'https://api.authentication.husqvarnagroup.dev/v1/oauth2/token'
local clientId =
'xxx'
local clientSecret =
'xxx
local moverID =
'xxx
local connectEndpoint =
'https://api.amc.husqvarna.dev/v1/mowers/' ..
moverID.. '/actions'
local connectEndpointstatus =
'https://api.amc.husqvarna.dev/v1/mowers/' ..
moverID
local accessToken
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
end
end
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
else
end
end
getAccessToken ()
statusrequest ()
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
local https =
require (
'ssl.https' )
local json =
require (
'json' )
local authEndpoint =
'https://api.authentication.husqvarnagroup.dev/v1/oauth2/token'
local clientId =
'xxx'
local clientSecret =
'xxx
local moverID =
'xxx
local connectEndpoint =
'https://api.amc.husqvarna.dev/v1/mowers/' ..
moverID.. '/actions'
local connectEndpointstatus =
'https://api.amc.husqvarna.dev/v1/mowers/' ..
moverID
local accessToken
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
end
end
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
grp.checkwrite (
'12/4/1' ,
true )
else
end
end
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
grp.checkwrite (
'12/4/1' ,
false )
else
end
end
mover_command =
grp.getvalue (
'12/4/0' )
if mover_command ==
true then
getAccessToken ()
sendStartCommand ()
end
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: 119
Threads: 15
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