Making your own smart ‘machine learning’ thermostat using Arduino, AWS, HBase, Spark, Raspberry PI and XBee

Previous part:
5. Turning the boiler on and off at the right time (Arduino)

6. Using outside temperature and scenarios to control an Arduino from a Raspberry PI

6.1 Temperature scenarios

After completing part 5, the Arduino was a successful normal thermostat. From that moment I removed my old thermostat and let the Arduino control the temperature of our house. Luckily it was a cold spring, so we still needed the house to be heated up through April.

The next step of course was to make the thermostat ‘smart’. In the Arduino thermostat code described in part 5, you see my final result for how long the boiler should be turned on and the difference between the set and actual temperature. This is actually the result of different iterations where previous settings resulted in the rooms not getting warm at all or overshooting the desired temperature so much that you would have to open all the windows to let it cool again. Because this was mainly a trial and error effort I thought that an easy way to turn this project into a ‘learning’ thermostat was to automate adjusting the amount of boiler on time.

To be able to turn the thermostat into a smart thermostat I introduced the concept of temperature scenarios. After each time the boiler turns on, the temperature in the room increases and the difference between the set and actual temperature decreases. As a result the time the boiler goes on at each interval decreases towards the set temperature. Looking at the minutes the boiler goes on after increasing the set temperature in the morning a general pattern for each 10 minute interval in first hour was 6 5 5 4 3 2 (figure 13). In the first 10-minute interval the boiler is on for 6 minutes, the second and third interval 5 minutes, the fourth 4 minutes etc.. For the second hour the patern was mostly 2 2 2 2 2 2 (figure 14). Every 10 minute interval the boiler is on for two minutes.

The downside of these patterns is that in the first hour the house does not get warm as quickly as possible, causing discomfort, and in the second hour the boiler is unnecessarily turned on every interval. Understanding that boiler efficiency increases when the amount of on-off cycles is reduced my Arduino thermostat was not very efficient.

Both comfort and energy efficiency could be improved when the thermostat could learn when to apply a better boiler on-off scenario. For example 6 6 6 2 2 2 (figure 13) to heat-up the house and 3 0 3 0 3 0 (figure 14) to keep the house warm. A regular thermostat does this by checking the ‘request for heat’. This is an abstract term and I do not completely understand how a thermostat determines the ‘request for heat’, but I am assuming that it checks how much the temperature has increased after each 10 minute interval.

Figure 13: Increase room temperature – regular and alternative scenario

Figure 14: Maintain room temperature – regular and alternative scenario

To determine the ‘request for heat; I took a different route and used the combination of the difference between the inside temperature and the set temperature and the difference between the outside temperature and the set temperature. This required more complex calculations so the first step was the let the Raspberry PI control the boiler state instead of the Arduino.

6.2 Controlling the boiler from the Rapsberry PI through the Arduino

To turn the boiler on and off, the Raspberry PI sends a message to the Arduino every second. This message contains the boiler state, current room temperature, current time and a checksum of all the previous fields. The message is composed of fixed length integer fields <hour><minute><boiler state><temperature in hundreds degrees of Celsius><checksum>. For example: 1204117231740. The serial port on the Raspberry PI can only be used by on thread. So for sending the message to the XBee of the Arduino I modified the XBee receiving thread at the Raspberry PI, xinsert(), to also send message from the message queue every second. The message queue is implemented as an SQLite table.

The messages are inserted into to the message queue table by a boiler control thread, fcontroll(), on the Raspberry PI. This thread is almost an exact copy of the Arduino thermostat loop and functions. The difference between the Raspberry PI and the Arduino, is that the Raspberry PI gets its current and set temperature from the sensor value database instead of the sensors directly.

For safety reasons a mechanism is built in that it will only create a message to send to the Arduino if the record sensor values are not older than 5 seconds, preventing it from turning the boiler on or off based on too old information. Because older messages are deleted after receiving no data for more than 5 seconds the Rapberry Pi will stop sending information to the Arduino.

addition to xinsert() function

main boiler control function

boiler functions

6.3 Arduino code for receiving instructions form the Raspberry PI

To have the Arduino receive the message from the Raspberry PI through the XBee was a lot harder than expected. I am using the version 2 also called Zigbee XBee’s. Most examples I found are on using version 1 (DigiMesh) of these devices. The Arduino code to use version 2 differs significantly from version 1. The next struggle was to split the message payload generated by the PI into the different fields and convert them to integers. As mentioned in the introduction of this blog post, I am not an experienced programmer, so writing C code was not easy. In my initial attempts I had a lot of stability issues and values from one variable unexplainably flowing over to another variable. I got it all working using the code shown below.

The Arduino splits the XBee message payload in different character arrays as soon as possible and adds 0 to the array to end the array. Every character array is then converted to an integer using the C atoi() function. Surprisingly I only have to give the first position the character array to the atoi function. For example: vhour = atoi(&chour[0]);. This converts the entire array to an integer.

The Arduino then uses a timer to decide if should stay in ‘remote’ mode or fall back to ‘local’ mode. In remote mode the Raspberry PI controls the boiler. In local mode the Arduino ignores the PI and does everything itself. Every time a message is received, it uses the checksum to make sure the content was correct. If the payload was correct it resets the time to 0. In every cycle of 10 milliseconds it adds 1 to the timer. If the timer has reached 3,000 (+/- 30 seconds) it falls back to local mode. After 3,000 the timer always stays at 3,000 to prevent overflowing the timer integer. I opted to use cycles here instead of the more common millis() to more safely handle the Arduino millis() overflow after 49 days. I am not entirely sure this is necessary, but thought it was better to play it safe, especially because you do not want to accidently start heating you house. If the Arduino is in local mode and heating up the boiler it always finishes the cycle of 10 minutes when the connection between the Arduino and Raspberry PI is restored. This is to prevent the boiler from continously getting turned on and off when the Arduino and PI do not agree on whether the boiler should be on ore off.

modified boiler control loop

6.4 Using temperature scenarios to turn the Rapsberry PI into a smart thermostat

The setup so far allows the Rapsberry PI to remotely control the boiler. That however, does not make it a smart thermostat. Several modifications were made to the Rapsberry PI Python code to make it more intelligent.

The first modification was to download the outside temperature to the Raspberry PI. A simple python script on the Amazon Cloud server runs every hour as a cron job and obtains the most recent outside temperature of Amsterdam using an online weather service and inserts the temperature in a HBase table. A current temp thread, fcurtemp(), on the Raspberry PI checks every 10 minutes for a new outside temperature and downloads it to a SQLite table if one is available. In this function you might see my current job coming through in that it first inserts the new value and then deletes the old ones instead of simply updating a value. This is to prevent any form of deadlocking, which is a continuous frustration in my work. Here I delete all values but the current one. In other functions, like the function used in the get scenario thread, I save the three most recent versions just to be safe.

The second modification is to download the different temperature scenarios from the Cloud server. Every scenario contains the difference between inside temperature and the set temperature (tempdif), the difference between the outside temperature and the set temperature (outtempdif), the number of minutes the boiler should be on for six cycles of 10 minutes and the score of the scenario. The score determines how well a particular scenario of on-off cycles performed given the tempdif and outtempdif. How this score is calculated is explained in the next and last part of this blog post.

The third and most important modification is the modifcicatin of the control thread, fcontroll(). The control thread is modified to select the best scenario given the current tempdif and outtempdif. When selecting the temperature scenario, at 50% of the time it takes the scenario with the best score for the current tempdif and outtempdif. The other 50% of the time it chooses a scenario with a lower score. This is to say, half the time it selects an ‘alternative scenario’ .

Finally the ‘used scenario’ and the ‘parameters used to select this scenario’ are uploaded to the ‘husedscenario’ HBase table the Amazon Cloud server. Uploading the used scenarios follows the same mechanism for uploading sensor information explained in part 3 of this blog post.

retrieve outside temperature

download temperature scenarios

select temperature scenario to use

modified boiler control function

Next part:
7. Learning and adapting temperature scenarios in the Amazon cloud (SPARK)

2 thoughts on “Making your own smart ‘machine learning’ thermostat using Arduino, AWS, HBase, Spark, Raspberry PI and XBee

  1. Pingback: Enabling technologies: how to build your own NEST | SmartDomus

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s