Im Nodered Forum hat jemand einen Flow gepostet mit dem es anscheinend auch funktionieren sollte die Daten der Zodiac Exo IQ auszulesen:
Hier ist der Flow:
e49a802f-ffad-441d-a4a6-6d7ad4547cb0-image.png
[
{
"id": "6c519c18faf10a1e",
"type": "tab",
"label": "Zodiac Exo",
"disabled": false,
"info": "",
"env": []
},
{
"id": "1e47a52e3f1755e1",
"type": "inject",
"z": "6c519c18faf10a1e",
"name": "Every hour",
"repeat": "3540",
"crontab": "",
"once": true,
"onceDelay": "60",
"topic": "",
"payload": "",
"payloadType": "date",
"x": 130,
"y": 60,
"wires": [
[
"6808aab954fc8b01"
]
]
},
{
"id": "7849f0c750568181",
"type": "http request",
"z": "6c519c18faf10a1e",
"name": "",
"method": "use",
"ret": "obj",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"authType": "",
"senderr": false,
"x": 610,
"y": 60,
"wires": [
[
"18bf3f43ad2e6aa4"
]
]
},
{
"id": "18bf3f43ad2e6aa4",
"type": "change",
"z": "6c519c18faf10a1e",
"name": "IDToken",
"rules": [
{
"t": "move",
"p": "payload.userPoolOAuth.IdToken",
"pt": "msg",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 840,
"y": 60,
"wires": [
[
"ea244732498b9412"
]
]
},
{
"id": "6808aab954fc8b01",
"type": "function",
"z": "6c519c18faf10a1e",
"name": "Format Post Request",
"func": "msg.method = 'POST';\nmsg.headers = {};\nmsg.headers['Host'] = 'prod.zodiac-io.com';\nmsg.headers['accept'] = 'application/json';\nmsg.headers['content-type'] = 'application/json';\nmsg.headers['accept-encoding'] = '*';\nmsg.headers['user-agent'] = 'okhttp/3.12.0';\nmsg.url = 'https://prod.zodiac-io.com/users/v1/login';\nmsg.payload = '{\"api_key\":\"yourapikeyhere\", \"email\":\"youremail@address.com\", \"password\":\"youriAqualinkpassword\"}';\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 380,
"y": 60,
"wires": [
[
"7849f0c750568181"
]
]
},
{
"id": "ea244732498b9412",
"type": "function",
"z": "6c519c18faf10a1e",
"name": "Set variable IDToken",
"func": "global.set(\"IDToken\",msg.payload);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1080,
"y": 60,
"wires": [
[]
]
},
{
"id": "dcd9bc84914a71f6",
"type": "http request",
"z": "6c519c18faf10a1e",
"name": "Chlorinator",
"method": "use",
"ret": "obj",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"authType": "",
"senderr": false,
"x": 610,
"y": 380,
"wires": [
[
"02b59259a14e8461",
"b8075e9783a1eb4f",
"f0bb9145a81ce74a",
"eba07f6046f035d6",
"4ac01fee0ba334b1",
"018a8ddf5da0b1f2",
"9c4298d655076b55"
]
]
},
{
"id": "9df6c312e595c863",
"type": "function",
"z": "6c519c18faf10a1e",
"name": "Format Get Request",
"func": "let bearer = global.get(\"IDToken\");\nmsg.method = 'GET';\nmsg.headers = {};\nmsg.headers['Host'] = 'prod.zodiac-io.com';\nmsg.headers['accept'] = 'application/json';\nmsg.headers['authorization'] = bearer;\nmsg.headers['accept-encoding'] = '*';\nmsg.headers['user-agent'] = 'okhttp/3.12.0';\nmsg.url = 'https://prod.zodiac-io.com/devices/v1/yourDeviceIDhere/shadow';\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 380,
"y": 380,
"wires": [
[
"dcd9bc84914a71f6"
]
]
},
{
"id": "a56824124abf6deb",
"type": "inject",
"z": "6c519c18faf10a1e",
"name": "Every 10 mins",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "600",
"crontab": "",
"once": true,
"onceDelay": "300",
"topic": "",
"payloadType": "date",
"x": 140,
"y": 380,
"wires": [
[
"9df6c312e595c863"
]
]
},
{
"id": "02b59259a14e8461",
"type": "change",
"z": "6c519c18faf10a1e",
"name": "ORP",
"rules": [
{
"t": "move",
"p": "payload.state.reported.equipment.swc_0.sns_2.value",
"pt": "msg",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 830,
"y": 300,
"wires": [
[]
]
},
{
"id": "b8075e9783a1eb4f",
"type": "change",
"z": "6c519c18faf10a1e",
"name": "pH",
"rules": [
{
"t": "move",
"p": "payload.state.reported.equipment.swc_0.sns_1.value",
"pt": "msg",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 830,
"y": 140,
"wires": [
[
"0e3f2e3e62511c3a"
]
]
},
{
"id": "f0bb9145a81ce74a",
"type": "change",
"z": "6c519c18faf10a1e",
"name": "Filter Temp",
"rules": [
{
"t": "move",
"p": "payload.state.reported.equipment.swc_0.sns_3.value",
"pt": "msg",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 850,
"y": 460,
"wires": [
[]
]
},
{
"id": "0e3f2e3e62511c3a",
"type": "range",
"z": "6c519c18faf10a1e",
"minin": "0",
"maxin": "10",
"minout": "0",
"maxout": "1",
"action": "scale",
"round": false,
"property": "payload",
"name": "Divide by 10",
"x": 1050,
"y": 140,
"wires": [
[]
]
},
{
"id": "eba07f6046f035d6",
"type": "change",
"z": "6c519c18faf10a1e",
"name": "ORP Setpoint",
"rules": [
{
"t": "move",
"p": "payload.state.reported.equipment.swc_0.orp_sp",
"pt": "msg",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 860,
"y": 380,
"wires": [
[]
]
},
{
"id": "4ac01fee0ba334b1",
"type": "change",
"z": "6c519c18faf10a1e",
"name": "pH Setpoint",
"rules": [
{
"t": "move",
"p": "payload.state.reported.equipment.swc_0.ph_sp",
"pt": "msg",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 850,
"y": 220,
"wires": [
[
"874e523fa6c7da37"
]
]
},
{
"id": "874e523fa6c7da37",
"type": "range",
"z": "6c519c18faf10a1e",
"minin": "0",
"maxin": "10",
"minout": "0",
"maxout": "1",
"action": "scale",
"round": false,
"property": "payload",
"name": "Divide by 10",
"x": 1050,
"y": 220,
"wires": [
[]
]
},
{
"id": "018a8ddf5da0b1f2",
"type": "change",
"z": "6c519c18faf10a1e",
"name": "Zodiac Error Code",
"rules": [
{
"t": "move",
"p": "payload.state.reported.equipment.swc_0.error_code",
"pt": "msg",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 870,
"y": 540,
"wires": [
[]
]
},
{
"id": "9c4298d655076b55",
"type": "change",
"z": "6c519c18faf10a1e",
"name": "Low Setting",
"rules": [
{
"t": "move",
"p": "payload.state.reported.equipment.swc_0.low",
"pt": "msg",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 850,
"y": 620,
"wires": [
[]
]
}
]
und hier die Anleitung dazu:
Note that in the Function node (Format Post Request) preceeding the first HTTP Request , you will require three bits of info -
API Key (generic for all users) - EOOEMOW4YR6QNB11
Email
Password
In the Function node (Format Get Request) preceeding the Device, you will need 'yourDeviceIDhere' where specified. It's the serial number of the device and looks something like -
JT19000123
or
JX19100123
The post you originally linked to has the curl commands necessary to pull the DeviceID. They might also be physically printed on the device somewhere but I haven't looked.
PULL DEVICE ID:
The steps required to login to iAqualink are as follows (note the api_key is the same for all users)
curl -X POST -H "Host:prod.zodiac-io.com" -H "accept:application/json" -H "content-type:application/json" -H "accept-encoding:gzip" -H "user-agent:okhttp/3.12.0" -d '{"api_key":"EOOEMOW4YR6QNB11", "email":"XXXX@XXXX", "password":"XXXXXX"}' "https://prod.zodiac-io.com/users/v1/login"
The iAqualink server returns a page of data (X's blank out personal data) -
{
"username": "XXXXXXXXXXXXXXXXXX",
"email": "XXXXXXXXXXX@gmail.com",
"first_name": "XXX",
"last_name": "XXXXXX",
"address": "XXX\n, XXX, XX, au, XXX",
"address_1": "XXXXXXXXXXX",
"address_2": null,
"city": "XXXXXXXXXXX",
"state": "XX",
"country": "au",
"postal_code": "XXXX",
"id": "XXXXXX",
"authentication_token": "XXXXXXXXXXXXXXXXXXXX",
"session_id": "XXXXXXXXXXXXXXXXXXXX",
"created_at": "2019-12-09T03:12:57.000Z",
"updated_at": "2019-12-09T03:12:57.000Z",
"time_zone": "Australia/XXXXXX",
"phone": "XXXXXXXXXX",
"opt_in_1": "1",
"opt_in_2": "0",
"role": "customer",
"cognitoPool": {
"appClientId": "XXXXXXXXXXXXXXXXXXXXX",
"poolId": "us-east-1_XXXXXXXXX",
"region": "us-east-1"
},
"credentials": {
"AccessKeyId": "XXXXXXXXXXXXXXXXXXXX",
"SecretKey": "XXXXXXXXXXXXXXXXXXXXXX",
"SessionToken": "XXXXXX.............XXXXXXXX",
"Expiration": "2020-04-26T05:24:59.000Z",
"IdentityId": "us-east-1:XXXXXXXXXXXXXXXX"
},
"userPoolOAuth": {
"AccessToken": "XXXXXXX...............XXXXXXX",
"ExpiresIn": 3600,
"TokenType": "Bearer",
"RefreshToken": "XXXXXX..........XXXXXXXXX",
"IdToken": "XXXXXXXXXX.........XXXXXXXXXXX"
}
The important fields in the preceeding data block are -
"id": (a 6 digit number that remains the same across logins),
"authentication_token": (a 20 character field that remains the same across logins),
"IdToken": (a 1740 character field that expires in 3600 seconds).
Armed with this data, a second command will elicit the device serial numbers registered to the user's account (user_id = id from block above) -
curl 'https://support.iaqualink.com/devices.json?api_key=EOOEMOW4YR6QNB07&authentication_token=XXXXXXXXXXXXXXXXXXXX&user_id=XXXXXX' -H "Host:support.iaqualink.com" -H "accept:application/json" -H "user-agent:okhttp/3.12.0" -H "content-type:application/json"
This is the returned data block for the two devices I have (a chlorinator and a heat pump) -
[
{
"id":"XXXXXX",
"serial_number":"XXXXXXXXXX",
"created_at":"2020-01-07T09:41:41.000Z",
"updated_at":"2020-01-07T09:41:41.000Z",
"name":"Z400 iQ TD7",
"device_type":"hpm",
"owner_id":null,
"updating":false,
"firmware_version":null,
"target_firmware_version":null,
"update_firmware_start_at":null,
"last_activity_at":null
},
{
"id":"XXXXXX",
"serial_number":"XXXXXXXXXX",
"created_at":"2019-12-09T03:18:18.000Z",
"updated_at":"2019-12-09T03:18:18.000Z",
"name":"eXO-Pro iQ",
"device_type":"exo",
"owner_id":null,
"updating":false,
"firmware_version":null,
"target_firmware_version":null,
"update_firmware_start_at":null,
"last_activity_at":null
}
]
INFORMATION RETRIEVAL AND CONTROL
With the DEVICE_SERIAL_NUMBER ("serial_number" in the block above), and ID_TOKEN ("IdToken" from the first block of data) the next GET command can be populated to retrieve the pH and ORP values for the chlorinator -
curl -X GET -H "Host:prod.zodiac-io.com" -H "accept:application/json" -H "authorization:ID_TOKEN" -H "accept-encoding:gzip" -H "user-agent:okhttp/3.12.0" "https://prod.zodiac-io.com/devices/v1/DEVICE_SERIAL_NUMBER/shadow"
Control of the chlorinator production (On/Off) can done using a POST command ("production" to be set to 0 or 1) -
curl -X POST -H "Host:prod.zodiac-io.com" -H "accept:application/json" -H "authorization:ID_TOKEN" -H "content-type:application/json; charset=UTF-8" -H "content-length:62" -H "accept-encoding:gzip" -H "user-agent:okhttp/3.12.0" -d '{"state":{"desired":{"equipment":{"swc_0":{"production":0}}}}}' "https://prod.zodiac-io.com/devices/v1/DEVICE_SERIAL_NUMBER/shadow"
I have the DEVICE_SERIAL_NUMBER for the components in my system (this value is fixed).
I now need a mechanism to record the variable ID_TOKEN and subsequently plug this into the commands above.
Kann das eventuell mal jemand testen, der eine Zodiac Exo im Einsatz hat ?