Thursday, June 29, 2017

AC Controller: ESP8266 Netatmo Thermostat control

I happen to own a Netatmo thermostat. The company that supplies the gas for my boiler was nice enough to give it to me as a present this winter. The product is an internet controlled thermostat. It is OK, would recommend it to someone looking for that type of product. Personally I hate the fact that I am using a product which will stop working if the company that supplies the cloud service disappears, or if they decide to start charging a monthly fee, but I got it for free, so I am getting to enjoy it without having to think about those issues... hehehe...

Netatmo is also nice enough to give an SDK to be able to access its devices (up to certain limits, of course), but enough for my needs. So, when I started to think about my AC controller, I came up with the idea of using Netatmo thermostat as my remote control and sensor. I first did some investigation of their SDK API using python scripts which I will check in some day (right now they have my personal information hardcoded, so I need to do some clean up). The process to be able to use the SDK goes through creating a new application in your user area in their web page. That gives you some IDs you will need to use later for identification.

Once I manged to get passed the authentication I met my first issue, the temperature is only updated once an hour. That sucks. Not that I was planning on checking the temperature every minute, but at least 4 times an hour. Doing some research on their forum, I found an undocumented API called "syncthermstate" which will force the thermostat to update the cloud with the current sensor values. This API requires "write_thermostat" scope to be enabled during authentication. I also found that once I get an authentication token and a refresh token, I could just use the refresh token to get new authentication tokens at any time, not requiring me to give my username and password again, which simplifies things. So I managed to get a python script with a bunch of https requests talking with the netatmo cloud and getting sensor readings on request from my thermostat.

My ESP8266 board arrived and the time had come to start porting my python script to Arduino. Turns out https is vaguely supported. There is an https example in ESP8266Wifi (does not look like the place for an https client to be for me, but hey, who am I to judge), here: https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WiFi/examples/HTTPSRequest
And that seems to be the best example. Issue with that example is that everything is hardcoded, but I used that as a building block for my work. Basically you need to write the whole headers and parse the results. To do that I enabled debugging in my python script (which was using "requests" for the http client) by adding the following in the imports:


import logging
try:
    import http.client as http_client
except ImportError:
    # Python 2
    import httplib as http_client

And this in the code:

http_client.HTTPConnection.debuglevel = 1
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True

That showed me the headers as being created by the python "requests" and as received from Netatmo, so I recreated the same thing in Arduino.

One thing I noticed when I managed to send the right headers from Arduino to netatmo was that the reply from Netatmo was using chunked encoding. Chunked encoding is a tool from HTTP 1.1 to packetize the responses. Since I had to write the parser for the responses, I decided to force the server not to use chunked encoding by telling it that the ESP8266 is an HTTP 1.0 client instead of 1.1 (chunked transfer encoding is not supported in 1.0).

You may find the code with all of this in here:  https://github.com/desordenado77/esp8266_netatmo_acController

Right now it does not do any control, it is just the building blocks on top of which I will be doing my final application.

Check httpsPostRequest on how am I doing my POST requests. As you can see my parser of the response is very simple and most likely not error proof. I am also not doing any certificate verification for now, which could potentially be susceptible of a man in the middle attack (somebody impersonating Netatmo servers).

In getThermostatData I am synchronizing my thermostat with the cloud and then reading the temperatures. If any of the calls to Netatmo servers fails I attempt to get a new authentication token using my refresh token.

Hope that helps someone... I will continue working on this project, the things to add next are:
- Real temperature check and AC control.
- Add remote logging capabilities
- LED notification
- Physical control with a button (using short press, long press, very long press for different actions)

No comments:

Post a Comment