De ATAG One app (voor iPhone en Android) benadert rechtstreeks via het wifi netwerk de ATAG One thermostaat. Atag stelt helaas geen technische documentatie beschikbaar hoe de thermostaat aan te sturen is. De enige manier om uit te vissen hoe de app “praat” met de thermostaat, is door de app te hacken 😀 😈
In deel 1 beschrijf ik hoe de app de ATAG One thermostaat in het netwerk vindt.
In deel 2 probeer ik te achterhalen hoe de app de thermostaat aanstuurt.
Communicatie met de thermostaat
In deel 1 is te lezen hoe de Android app uitgepakt kan worden. De meeste code is goed leesbaar. De naamgeving van de methodes spreken voor zich. De manier om de werking te achterhalen is om door de applicatie te bladeren en de code te begrijpen.
In het bestand ControlDeviceIndicatorC bevindt zich een functie met de naam switchToDeviceIp
. Deze functie stelt op basis van het IP adres van de thermostaat de URL voor communicatie samen. In onderstaande code fragment zie je dat de thermostaat HTTP verbinding accepteert op poort 10.000.
switchToDeviceIp = function (broadcastingDevice) { isLocal = true; this.updateIcon(); var deviceIp = broadcastingDevice.deviceIp; deviceUrl = "http://" + deviceIp + ":10000/"; ultraLight.serverConnection.homeURL = deviceUrl; }
In index.html
staat een commentaar over pairing. Blijkbaar moet er eerst pairing tussen de thermostaat en het aansturende apparaat plaatsvinden. Handig dat de betekenis van de response codes er bij staat.
/* WIFI SETUP & PAIRING */ // If the devicequery was for pair_message, // and the response was not 2 for the status(1 = waiting, 2 = success, 3 = failed) // then ask the device again if (this.queryURL == 'pair_message') { var pairReply = getModelValue('m:pairReply.acc_status');
De inhoud van het pair bericht zier er als volgt uit:
<div id="skipselectYourOneSkippedLogInButton" data-query-url="pair_message" data-post='{"pair_message":{"seqnr":0,"accounts":{"entries":[{"user_account":"","mac_address":"m:deviceIdentifier","device_name":"m:deviceName","account_type":0}]}}}' data-target='{"m:pairReply":"pair_reply"}' data-set-showpage="confirmOnePage" data-set-failpage="selectYourOnePage" data-wifi-lastStep="searchForOnePage" data-pair-success="confirmedPairSuccess" data-transition="slide" data-no-error="true" data-show-overlay="true"> </div>
In de generieke Controller.sendRequest()
staat nog de volgende code. Aan elk bericht dat de app verzendt, wordt blijkbaar de inlognaam en het MAC-adres van de afzender geplakt:
// Insert the account_auth message for the device, since it needs it // Insert a different string depending if the device is coupled if ($model("lastUsedAccount").get()!=null) { authMessage = ',"account_auth":"user_account":"m:lastUsedAccount","mac_address":"m:deviceIdentifier"}'; } else { authMessage = ',"account_auth":{"user_account":"","mac_address":"m:deviceIdentifier"}'; } // Insert the string into post var postInsertPosition = postString.indexOf(','); var newPost = [postString.slice(0, postInsertPosition), authMessage, postString.slice(postInsertPosition)].join('');
Verzonden JSON:
{ "pair_message": { "seqnr": 0, "accounts": { "entries": [ { "user_account": "", "mac_address": "72:00:06:c0:78:e3", "device_name": "Test2!", "account_type": 0 } ] } } }
Response in JSON (Na succes):
{ "pair_reply": { "seqnr": 0, "acc_status": 2 } }
HTTP netwerk verkeer
Zoals hierboven getoond, gebruikt de App plain HTTP met JSON content om met de app te communiceren. De verbinding is lokaal niet versleuteld. Door nu een proxy tussen de app en de thermostaat te plaatsen, ga ik al het verkeer afluisteren.
Om verkeer af te luisteren, installeer ik een proxy met de naam Charles.
Charles is a web proxy (HTTP Proxy / HTTP Monitor) that runs on your own computer. Your web browser (or any other Internet application) is then configured to access the Internet through Charles, and Charles is then able to record and display for you all of the data that is sent and received.
HTTP Request onderscheppen via Proxy
Op de telefoon stel ik mijn computer’s IP adres in als Proxy met poort 8888. Via de app stel ik daarna de temperatuur in op 21 graden en kijk welk bericht de app verstuurt naar de thermostaat. Zie het resultaat hieronder.
{ "update_message": { "seqnr": 0, "account_auth": { "user_account": "email@gmail.com", "mac_address": "3AA90444-401E-8978-B35A43809XXX" }, "device": null, "status": null, "report": null, "configuration": null, "schedules": null, "control": { "ch_mode_temp": 21 } } }
Samengevat moeten we authentication gegevens account_auth
en een control object control
waarin de gewenste temperatuur staat als een POST request versturen naar de thermostaat.
Samenvatting
Eenmalig moet er een pair_request uitgevoerd worden om met de thermostaat te kunnen praten. Op basis van een unieke code mac_address
onthoudt de thermostaat welke app toegang tot de thermostaat heeft.
Daarna kan de temperatuur ingesteld worden door een POST request te sturen naar het adres van de thermostaat op poort 10.000.
het ATAG One API project maakt gebruik van deze kennis om de thermostaat rechtstreeks uit te lezen aan aan te sturen. Zie ook de project wiki voor een technische beschrijving van de berichten (in het Engels).
Hoi,
Ik ben bezig geweest om hetgeen jij in Java hebt geschreven te reproduceren in Perl. Nu loop ik tegen het probleem aan dat wanneer ik een retrieve_request stuur, ik altijd hetzelfde antwoord krijg en dit is niet het antwoord waar ik op hoopte 😉
Mijn JSON post naar http://172.20.41.160:10000/retrieve ziet er als volgt uit:
{ “retrieve_message”: { “seqnr”: 0, “device_id”: “6808-1401-3108_15-12-001-005”, “info”: 18 } }
De response die ik altijd krijg is:
{ “retrieve_reply”:{ “seqnr”:0,”acc_status”:0} }
Het apparaat is gepaired.
Ik heb ook de volgende post geprobeerd:
{“seqnr”:1,”account_auth”:{“user_account”:””,”mac_address”:”6808-1401-3108_15-12-001-005″},”info”:15}}
Maar dan krijg ik:
{ “retrieve_reply”:{ “seqnr”:1,”acc_status”:3} }
Deze response krijg ik ook wanneer ik als het mac_address daadwerkelijk het mac adres van de computer die gepaird is gebruik:
{“retrieve_message”:{“seqnr”:1,”account_auth”:{“user_account”:”atagone@nerdnieuws.net”,”mac_address”:”52:54:00:A9:72:D7″},”info”:15}}
Heb jij enig idee wat hier fout gaat? Wellicht ben jij hier ook tegenaan gelopen en kan je me een stuk verder helpen. Ik zou dat zeer op prijs stellen 🙂
Met vriendelijke groet,
Gert-Jan Aalderink
Hi Geert-Jan,
Misschien ben je er inmiddels zelf uitgekomen, maar ik liep tegen hetzelfde aan, met een beetje trial-en-error ben ik erachter gekomen dat je de account_auth {…} mee moet sturen. De API documentatie klopt niet helemaal blijkbaar. 🙁
{
“update_message”: {
“seqnr”: 1,
“account_auth”: {
“user_account”: “”,
“mac_address”: “ab:cd:ef:01:23:45”
},
“control”: {
“ch_mode_temp”: 21.5
}
}
}
Zelf heb ik nooit geleerd te programmeren, anders had ik me er zeker zelf toe gezet maar: is het denkbaar met bovenstaande kennis een plugin voor homebridge te schrijven zodat er homekit (en met name Siri-)ondersteuning voor de Atag One mogelijk is?
Ik heb sinds eind januari 2019 een ATAG One thermostaat en het lukte niet om de app met het apparaat te laten praten na de wifi-configuratie. De hier gegeven informatie heeft me op weg geholpen om uiteindelijk via Node-Red de thermostaat te kunnen bedienen. Hartelijk dank voor deze blog.
Martin
Hallo Martin, Ik probeer ook de Atagone node te gebruiken in home assistant maar krijg deze niet werkend. Kun je laten zien hoe je dit in node red hebt gedaan?
Alvast bedankt
Ola,
Wat super dit uitzoekwerk. Ik heb zo’n jaar een atag-one en ben sinds 3 maanden bezig om via een raspberry-Pi Domoticz aan het werk te krijgen. De Pi zit op ethernet en de atag-one natuurlijk op wifi.
Het direct uitlezen en aansturen van de atag via Domoticz gaat als een zonnetje. Met de uitleg in verschillende fora wat dat een eitje.
Nu wil ik alleen ook de fireplace mode gebruiken. Ik heb namelijk een pellet-kachel in de woonkamer, maar als een van de sensoren detecteert dat het in een andere kamer te koud wordt, moet de CV wel aanslaan. De lelijke optie is om het setpoint een graag boven de temperatuur in de woonkamer te zetten, maar dat vind ik niet sjiek.
Met een packetsniffer heb ik geprobeerd de pakketjes te onderscheppen die gestuurd worden voor het aan en uitzetten van de fireplace mode. Dit lukt alleen niet, omdat de PI op ethernet zit en ik mijn router niet zo ver krijg om via port-mirroring alle pakketjes voor de atag-one ook naar mijn PI te sturen :-S (klote router, als het budget het to laat wordt alles in huis vervangen door een
Ubiquiti Unifi systeem, maar dat duurt nog even)
Kan jij kijken welk commando je moet geven bij –set om de fireplace mode aan te zetten?
thx
Zou het ook mogelijk zijn om met een arduino met ethernet shield de gegevens in te lezen?