I have now managed to make it work on my OpenHAB 2.5 (openhabian), using python scripts and executeCommandLine
. Here is my setup, currently for one room (since I only have one oven) … sorry for the weird mix of English and Norwegian:
items:
Number AdaxHillevis_Id "Adax room id [%d]"
Switch AdaxHillevis_Heating "Status av ovnen [%s]" <heating>
Number AdaxHillevis_RoomTemp "Romtemperatur [%.1f °C]" <temperature>
Number AdaxHillevis_Setpoint "Ønsket temp. [%.0f °C]" <temperature>
Number AdaxHillevis_AdaxSetPt "Setpoint Adax cloud [%.0f °C]" <temperature>
AdaxHillevis_Id
includes the Adax API id of the room (temperature control is per room not per device). I set it in a “System started” rule.
adax_get_room_status.py
:
#!/usr/bin/python3
import requests
import sanction
import sys
import json
if len(sys.argv) < 2:
print("Error: needs the room ID as an argument")
quit()
ROOM_ID = int(sys.argv[1])
# for values, see Adax WiFi app, Account Section
CLIENT_ID = "xxxxxx"
CLIENT_SECRET = "123456789abcd"
API_URL = "https://api-1.adax.no/client-api"
def get_token():
# Authenticate and obtain JWT token
oauthClient = sanction.Client(token_endpoint = API_URL + '/auth/token')
oauthClient.request_token(grant_type = 'password', username = CLIENT_ID, password = CLIENT_SECRET)
return oauthClient.access_token
def get_room_status(roomId, token):
headers = { "Authorization": "Bearer " + token }
response = requests.get(API_URL + "/rest/v1/content/", headers = headers)
status = response.json()
for room in status['rooms']:
if room['id'] == roomId:
return room
return {} # room not found
token = get_token()
status = get_room_status(ROOM_ID, token)
print(status)
adax_set_room_tg_temp.py
#!/usr/bin/python3
import requests
import sanction
import sys
if len(sys.argv) < 3:
print("Error: needs 2 arguments: room ID and the target temperature")
quit()
ROOM_ID = int(sys.argv[1])
TG_TEMP = round(float(sys.argv[2]), 2)
# for values, see Adax WiFi app, Account Section
CLIENT_ID = "xxxxxx"
CLIENT_SECRET = "123456789abcd"
API_URL = "https://api-1.adax.no/client-api"
def get_token():
# Authenticate and obtain JWT token
oauthClient = sanction.Client(token_endpoint = API_URL + '/auth/token')
oauthClient.request_token(grant_type = 'password', username = CLIENT_ID, password = CLIENT_SECRET)
return oauthClient.access_token
def set_room_target_temperature(roomId, temperature, token):
# Sets target temperature of the room
headers = { "Authorization": "Bearer " + token }
json = { 'rooms': [{ 'id': roomId, 'targetTemperature': round(100 * temperature) }] }
requests.post(API_URL + '/rest/v1/control/', json = json, headers = headers)
token = get_token()
set_room_target_temperature(ROOM_ID, TG_TEMP, token)
Note that one needs to install the sanction
package for user openhab
, which I solved by installing it system-wide using sudo pip3 install sanction
.
rules:
rule "Update Adax status for Hillevi's room from Adax cloud"
when
Time cron "0 0/10 * * * ?" // every 10 minutes
then
val String roomStatus = executeCommandLine("/etc/openhab2/misc/adax_get_room_status.py " + AdaxHillevis_Id.state.toString, 5000)
logDebug("Adax", "roomStatus = " + roomStatus)
val roomTemp = Double::parseDouble(transform("JSONPATH", "$.temperature", roomStatus)) / 100
val Number tgTemp = Double::parseDouble(transform("JSONPATH", "$.targetTemperature", roomStatus)) / 100
val Boolean enabled = Boolean::parseBoolean(transform("JSONPATH", "$.heatingEnabled", roomStatus))
val roomName = transform("JSONPATH", "$.name", roomStatus)
logInfo("Adax", "update for " + roomName + ": temp = " + roomTemp.toString + "°C, set point = " + tgTemp.toString + "°C, heater enabled = " + enabled.toString)
AdaxHillevis_AdaxSetPt.postUpdate(tgTemp)
AdaxHillevis_RoomTemp.postUpdate(roomTemp)
if (enabled) {
AdaxHillevis_Heating.postUpdate(ON)
} else {
AdaxHillevis_Heating.postUpdate(OFF)
}
// wait a bit, so _AdaxSetPt is set, to avoid calling adax_set_room_tg_temp.py
Thread::sleep(200)
AdaxHillevis_Setpoint.postUpdate(tgTemp)
end
rule "Send new setpoint for Hillevis room to Adax cloud"
when
Item AdaxHillevis_Setpoint changed
then
if (newState != AdaxHillevis_AdaxSetPt.state) {
// send the new setpoint to the Adax cloud and update AdaxHillevis_AdaxSetPt
logInfo("Adax", "sending updated setpoint " + newState.toString + " to Adax cloud")
executeCommandLine("/etc/openhab2/misc/adax_set_room_tg_temp.py " + AdaxHillevis_Id.state.toString + " " + newState.toString)
AdaxHillevis_AdaxSetPt.postUpdate(newState)
}
end
Note that executeCommandLine()
changed syntax in OH3.
This setup needs the _AdaxSetPt to be set before updating _Setpoint, otherwise the second rule triggers a needless update to the Adax cloud. It is not very elegant, but the best I managed…
This should be all…
One question for Rich: this works for one room, but with several rooms, I would have to duplicate the rules - but I am pretty sure there is a way to write rules that can work for more things, provided they have the same naming scheme for items - can you help here?
Moreover, if I had more rooms, I would probably rewrite the ‘get’-script so that i returns the json for all rooms and then try to write a rule that updates all items by parsing the json - but again, this requires better knowledge of the rules language than I have…