Getting a bearer token

Getting an Athom Homey bearer token is not straight forward

The following guide, describes a setup that automatically fetches an updated bearer token for usage with your homey API. It consists of two main parts:

  • A homeyscript that returns an updated bearer token as a return tag value

  • An example flow that runs the homeyscript regularly and stores an updated bearer token in a logic variable

The homeyscript

First you need to update the configuration section to your homey.

// -------- o - Configure these parameters -------- o -------- o
let email = 'xxxxx@gmail.com'
let password = 'skdjhf987s8d76fsd'
let client_id = 's8d67chdg36d8d6f6d'
let client_secret = 'dsdfghjkdfjghkdfjhgkdfjhgkdfjhgkdfjhgkfd'
let redirect_url = 'http://localhost'
let cloudid = '8sd76f87sd6f876sd8f76sd'
// -------- o -------- o -------- o -------- o -------- o
const between = function(str, strf, strt) {
return str.split(strf).pop().split(strt)[0].trim();
}
const authurl = 'https://accounts.athom.com/login'
console.log("POST authentication " + authurl)
const response2 = await fetch(authurl, {
"headers": {
"accept": "application/json, text/javascript, */*; q=0.01",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
},
"referrerPolicy": "no-referrer-when-downgrade",
"body": 'email=' +encodeURIComponent(email) + '&password=' + encodeURIComponent(password) + '&otptoken=',
"method": "POST",
"mode": "cors",
"credentials": "omit"
})
const body2 = await response2.text()
const token = JSON.parse(body2)
const authorizeurl = 'https://accounts.athom.com/oauth2/authorise?client_id=' + client_id +
'&redirect_uri=' + encodeURIComponent(redirect_url) + '&response_type=code&user_token=' + token.token
console.log(" Response from accounts.athom.com/login ", body2)
console.log("GET Authorization " + authorizeurl)
const response3 = await fetch(authorizeurl, {
"headers": {
},
"method": "GET",
"mode": "cors",
"credentials": "include"
})
const body3 = await response3.text()
let csrf = between(body3, 'name="_csrf" value="', '">')
let raw = response3.headers.raw()['set-cookie']
let rawd = raw[0].split(';')
let cookiecsrf = null
rawd.forEach(el => {
let dc = el.split('=')
if (dc[0] === '_csrf') {
cookiecsrf = dc[1]
}
})
let cookie4 = '_csrf=' + cookiecsrf
// console.log("Cookie4", cookie4)
console.log(" CSRF input parameter", csrf)
console.log(" CSRF cookie", cookiecsrf)
let authorizeurl2 = 'https://accounts.athom.com/authorise?client_id=' + client_id + '&redirect_uri=' + encodeURIComponent(redirect_url) + '&response_type=code&user_token=' + token.token
console.log("GET Authorization", authorizeurl2)
const response4 = await fetch(authorizeurl2, {
"headers": {
"content-type": "application/x-www-form-urlencoded",
"cookie": cookie4
},
"redirect": "manual",
"body": "resource=resource.homey." + cloudid + "&_csrf=" + csrf + "&allow=Allow",
"method": "POST",
"mode": "cors",
"credentials": "include"
});
const body4 = await response4.text()
let code = response4.headers['_headers'].location[0].split('=')[1]
console.log(" Response from authorization. Redirect to ", response4.headers['_headers'].location[0])
console.log(" Response content ", body4)
console.log(" Parsed the following code ", code)
let tokenendpoint = 'https://api.athom.com/oauth2/token'
console.log("POST token (resolve code to token) " + tokenendpoint)
const response5 = await fetch(tokenendpoint, {
"headers": {
"content-type": "application/x-www-form-urlencoded",
},
"body": 'client_id=' + encodeURIComponent(client_id) + '&client_secret=' + encodeURIComponent(client_secret) +
'&grant_type=authorization_code&code=' + encodeURIComponent(code),
"method": "POST",
"mode": "cors",
"credentials": "include"
});
//console.log("Response5", response5)
const body5 = await response5.text()
let accesstoken = JSON.parse(body5)
let delegationEndpoint = 'https://api.athom.com/delegation/token?audience=homey'
const response6 = await fetch(delegationEndpoint, {
"headers": {
"content-type": "application/x-www-form-urlencoded",
"authorization": "Bearer " + accesstoken.access_token
},
"referrerPolicy": "no-referrer-when-downgrade",
"body": "client_id=" + client_id + " &client_secret=" + client_secret + "&grant_type=refresh_token&refresh_token=" + accesstoken.refresh_token,
"method": "POST",
"mode": "cors",
"credentials": "include"
});
const body6 = await response6.json()
console.log(" JWT token is " + body6)
let endpoint7 = 'https://' + cloudid + '.connect.athom.com/api/manager/users/login'
console.log("POST login endpoint " + endpoint7)
const response7 = await fetch(endpoint7, {
"headers": {
"content-type": "application/json",
//"authorization": "Bearer " + accesstoken.access_token
},
"body": JSON.stringify({"token": body6}),
"method": "POST"
});
const body7 = await response7.json()
console.log(" Response status " + response7.status)
console.log(" Response: " + body7)
await setTagValue("accesstoken", {type: 'string', title:'Access token'}, body7)
return true

Updating a logic variable

Run the homeyscript above regularly to update an logic variable using the flow below.

Using the bearer token with the API

Here is an example using the Homey API with the bearer token:

// -------- o - Configure these parameters -------- o -------- o
let cloudid = 'sd87f68ds76f87sd6f8sd76f'
// -------- o -------- o -------- o -------- o -------- o
let variables = await Homey.logic.getVariables()
let getVar = (name) => {
let x = _.find(variables, (val, key) => {return (val.name === name) })
if (typeof x === 'undefined') throw new Error("Could not find variable [" + name + "]")
return x
}
let accesstoken = getVar('accesstoken').value
console.log("Access token is " + accesstoken)
let baseapi = 'https://' + cloudid + '.connect.athom.com/api/'
let apiendpoint = baseapi + 'manager/devices/device/'
console.log("GET " + apiendpoint)
const response = await fetch(apiendpoint, {
"headers": {
"accept": "application/json",
"Authorization": "Bearer " + accesstoken
},
"method": "GET"
});
console.log(" Response status " + response.status + " " + response.statusText)
const responseBody = await response.text()
const data = JSON.parse(responseBody)
console.log(" Result ", data)

Homey API reference

Thanks to Johan Bendz for providing a list of API endpoints: https://github.com/JohanBendz/Homey-Endpoints/blob/master/Homey-REST-endpoints

The base URL is:

https://<cloudid>.connect.athom.com/api/

https://apps.developer.athom.com/tutorial-Web Api.html

Use the bearer token to make an authorized call:

GET /api/manager/sessions/session/ HTTP/1.1
Host: <cloudid>.connect.athom.com
Authorization: Bearer <ACCESS TOKEN>
# Alarms
GET /api/manager/alarms/alarm/
# Apps
GET /api/manager/apps/app/
GET /api/manager/apps/app/<APP_ID>/ (eg. com.fibaro)
# Cloud state
GET /api/manager/cloud/state/
# Devices
GET /api/manager/devices/device/
GET /api/manager/devices/device/<DEVICE_ID>/
# Drivers
GET /api/manager/devices/drivers/
GET /api/manager/drivers/pairsession/
# Experiments
GET /api/manager/experiments/experiment/
# Flow
GET /api/manager/flow/flow/
GET /api/manager/flow/flow/<FLOW_ID>/
# Flow folders
GET /api/manager/flow/flowfolder/
# Flow tokens
GET /api/manager/flowtoken/flowtoken/
# Images
GET /api/manager/images/image/
# Insights
GET /api/manager/insights/log/
# Language and unit settings
GET /api/manager/i18n/
# LED ring
GET /api/manager/ledring/screensaver/
GET /api/manager/ledring/state/
# Location
GET /api/manager/geolocation/
# Logic
GET /api/logic/variable/
GET /api/logic/variable/<VARIABLE_ID>/
PUT { "value": value } TO /api/manager/logic/variable/<VARIABLE_ID>/
# Mobile
GET /api/manager/mobile/
# Notifications
GET /api/manager/notifications/notification/
GET /api/manager/notifications/owner/
# Presence
GET /api/manager/presence/
# Reminders
GET /api/manager/reminder/reminder/
# Sessions
GET /api/manager/sessions/session/
# Switch on:
PUT { "value": true } TO /api/manager/devices/device/<DEVICE_ID>/capability/onoff/
# Switch off:
PUT { "value": false } TO /api/manager/devices/device/<DEVICE_ID>/capability/onoff/
# System
GET https://<HOMEY_IP>/api/manager/system/
# System Reboot // Use with caution!
POST https://<HOMEY_IP>/api/manager/system/reboot/
# Users
GET /api/manager/users/user/
GET /api/manager/users/user/<USER_ID>/
GET /api/manager/users/state/
# Weather
GET /api/manager/weather/weather/
# Zigbee
GET /api/manager/zigbee/state/
# Z-Wave
GET /api/manager/zwave/state/
GET /api/manager/zwave/log/
POST /api/manager/zwave/command/
- heal: payload {command: "heal", opts: {nodeId: <NODE_ID>}}
- test: payload {command: "sendData", opts: "<NODE_ID>,0x20,0x00"}
# Zones
GET /api/manager/zones/
GET /api/manager/zones/<ZONE_ID>/