Nest Thermostat, APIs and RRDTool

A week or so ago we had a Nest Thermostat installed.
It’s quite clever – learning when you are in, out and awake, and estimating a heating profile for those times. It needed some tweaking, sure, but it did a very good job overall.

I then realised – what use is a smart device, which has an API, if you’re not looking at the data?

Right – what do we need?

  • A way to talk to the API
  • A way to parse that data
  • A way to log that Data

I’m not going through the API documentation and cadging something together to talk to the API – sod that, someone’s already done it. It might not give me all the data I need in easy chunks, but most of the hard work is done.
These requirements can be solved by:

so nest_thermostat, once installed with pip install nest_thermostat can be used with the following commands:

    temp <temperature>         ... set target temperature
    fan [auto|on]              ... set fan state
    mode [cool|heat|range|off] ... set fan state
    away                       ... toggle away
    show                       ... show everything
    curtemp                    ... print current temperature
    curhumid                   ... print current humidity
    curmode                    ... print current mode

Now the first four we don’t need to do anything with, as we only want to read data, not start writing a copy of the nest website where we can start setting temperatures and things.
curmode is useless to me as my nest is only configured to heat, not to cool, as I’m in the UK and we don’t typically have Air Conditioning window boxes, much less a fully installed system.

Initially, I set up a small script to look at curtemp, log it to rrdtool and let my current monitoring graphing scripts graph it along with temp measured by my currentcost. This was fine until I hit the API limit of the Nest API, and the query returned HTTP 429: Too Many Requests. Oops. This gave me a reading of Zero and resulted in lots of vertical lines on the graph.
Secondarily, I set up a script to look at curtemp, and if that resulted in a successful retrieval, log it to rrdtool. This was much better, and gave me much more consistent rrdtool entries.

#!/bin/bash
#get the current temperature from nest_thermostat

var=$(/usr/local/bin/nest.py --user <username> --password <password> --celsius curtemp)

#check to see if the value is a valid set of numbers only - weeding out the HTTP429 errors

if [[ $var = *[[:digit:]]* ]]; then
#push it into rrdtool
rrdtool update /mnt/bigdisk/cc/nesttemp.rrd N:$var
fi

Next, I had the itch for more data. current temperature wasn’t enough – wouldn’t it be nice to see when the wife turned the thermostat up? And When/How long the heating had been on?

Looking at the source for nest_thermostat, I was going to have to modify that pretty heavily to give me some extra commands to use – this might have resulted in too many API requests again though, making 3 calls to the API for the 3 peices of data I needed. A much better idea was to use the show command, and parse that for the data I wanted.

But what was it I wanted? I needed to know which variables represented heating on/off and the temperature  the thermostat was set to.

I pushed $ nest.py --user <username> --password <password> --celsius show >> heating.txt when the heating was on (I manually set the target temp to 24C to get it to come on) and pushed it to notheating2.txt when it was off.
I then ran a diff on the files:

$ diff heating.txt notheating2.txt -y --suppress-common-lines
hvac_heater_state...............: True | hvac_heater_state...............: False
target_temperature..............: 24 | target_temperature..............: 20

Right, some awful (and I mean awful) hacking with pipes and sed and I had my three pieces of data:

  • Current Temperature (|grep target_temperature|grep -v target_temperature_ | sed 's/.*://' | sed -r 's/^.{1}//'| sed 's/[[:blank:]]//g' )
  • Target Temperature (|grep current_temperature| sed 's/.*\(.....\)/\1/'| sed 's/[[:blank:]]//g')
  • Heating True/False (|grep hvac_heater_state|sed 's/.*://' | sed -r 's/^.{1}//' | sed 's/[[:blank:]]//g')

(the last sed commands in each are to deal with an issue I encountered this morning where extra white space was screwing up the data going in to rrdtool – hacky, but it works. I’d be glad to hear of any improvements though!)

So, we need to run the script like this – send the full output from nest_thermostat into a bash variable, do the tasks above on it to get the individual pieces of data, and then if they are valid values (using the same check as before) then we’ll let them through to rrdtool to update the nesttemp.rrd.
I’ve set a thing in there to make the heating variable numeric, so it appears nicely on the graphs with the rest of the figures.

#!/bin/bash
var=$(/usr/local/bin/nest.py --user  --password  --celsius show)
targ_temp=$(echo "$var" |grep target_temperature|grep -v target_temperature_  |sed 's/.*://' | sed -r 's/^.{1}//'|sed 's/[[:blank:]]//g' );
cur_temp=$(echo "$var" |grep current_temperature| sed 's/.*\(.....\)/\1/'|sed 's/[[:blank:]]//g');
heating=$(echo "$var" |grep hvac_heater_state|sed 's/.*://' | sed -r 's/^.{1}//' |sed 's/[[:blank:]]//g');
if [[ "$heating" == True ]]; then
		heating='10'
	else
		heating='0'
fi

if [[ $cur_temp = *[[:digit:]]* ]]; then
rrdtool update /mnt/bigdisk/cc/nesttemp.rrd N:$cur_temp:$targ_temp:$heating;
fi

This results in some nice little graphs like this:Temperature Screenshot

Share This!

Leave a Reply

Your email address will not be published. Required fields are marked *