I love it when a plan comes together

After spending a lot of effort and encountering difficulties in creating pieces, I am often pleasantly surprised when the pieces come together quickly and easily.  This was the case for my latest home improvement tech project.  In my home, it seems like some areas are warmer than others–I realized that some variance will exist, but I wanted to reduce the overall difference between upstairs and downstairs.

The first step was to be able to measure the temperature or each area.  Thanks to my ESP8266 development boards, I am able to publish the upstairs temperature and publish it to a database and Bakboard.  With the new Nest thermostat and a little playing with the REST API, I was able to do something similar and publish the downstairs temperature to the BakBoard.  There are now four temperatures published on the Bakboard.

temps

I then wrote a simple Java program with that basically does the following:

  1. Get the temperature of the [Downstairs] thermostat
  2. Get the temperature of the [Upstairs] temperature sensor
  3. If the difference between the two temperatures is greater than 2 degrees, turn on the furnace fan

I had a little trouble figuring out how to turn on the fan, but this is the way I implemented it in Java:

public void runFan(String thermostatId, String authToken) throws Exception {
    final String rootUrl = "https://developer-api.nest.com";
    HttpPut httpPut = new HttpPut(String.format("%s/devices/thermostats/%s/fan_timer_active", rootUrl, thermostatId));

    StringEntity putEntity = new StringEntity("true");
    httpPut.setEntity(putEntity);
    httpPut.addHeader("Content-Type", "application/json");
    httpPut.addHeader("Authorization", "Bearer " + authToken);
        
    CloseableHttpClient httpclient = HttpClients.createDefault();
    try {
        CloseableHttpResponse response = httpclient.execute(httpPut);
            
        // We need to handle redirect
        if (response.getStatusLine().getStatusCode() == 307) {
            String newUrl = response.getHeaders("Location")[0].getValue();
            httpPut.setURI(new URI(newUrl));
            response = httpclient.execute(httpPut);
        }
           
        try {
            HttpEntity entity = response.getEntity();
            EntityUtils.consume(entity);
        } finally {
            response.close();
        }
    } finally {
        httpclient.close();
    }
}

Of course I want my code to run at regular intervals, but fortunately I had already figured out how to go about running a Java program every 15 minutes.  It was easy to toss everything into a Docker container and let it do its thing.

Here are a few notes/design decisions that I made when putting things together:

  • There are no changes to the basic functionality of the Nest thermostat.  It is not aware of the external temperature sensor and heats/cools as normal.  This means, even if something goes wrong in my code (or network connection or custom hardware or somewhere else), things can’t go too crazy.
  • My code does not control the length the fan runs–it starts the fan and lets the Nest take care of turning it off.  There is a default run time that can be set on the thermostat–in my case I set it to 15 minutes to match the run duration of my new program.
  • I have a two stage furnace and when just the fan is run it goes at half speed.  Even at full speed the furnace fan is pretty quiet, and at half speed we don’t even notice.
  • The thermostat only gives me the temperature in degree increments (if I were using Celsius it would be in half degree increments).  My homemade temperature sensor goes to greater precision, but it’s hard to say whether that greater precision provides better accuracy.  I went with a 2 degree variance threshold for enabling the fan to allow for rounding differences as well as accuracy differences between upstairs and downstairs temperatures.

As far as I can tell, everything came together smoothly and “just works” and has been for the past few weeks.  Occasionally I check the log to make sure it’s still running.  Once in awhile when I walk past the Nest I notice the fan icon indicating that the fan is running (and I can verify that by putting my hand near a vent).  The weather is still mild, so it will be interesting to see what happens when it gets colder (especially when I rev up the wood stove), but so far there seems less variance in temperature throughout the house.  I love it when a plan comes together . . .

Playing with the Nest Rest API

I bought the Nest thermostat for fun. I purchased it couple months ago to go with the new furnace and air conditioner. I could have gone with a thermostat provided by the contractor, or any number of cheaper options, but I wanted something with which to play. Even though I don’t consider myself a “gadget person”, I wanted this gadget.  I wanted to play with it’s API and see what I could make it do.

With summer ending and school starting, there was a lot going on in the household.  Also, we went for about a month when neither air conditioning nor heating were required, so internal climate control was not often on my mind.  Now the heat is coming on for a few minutes in the morning and I’ve started playing with the Nest Rest API.

The Nest developer website has documentation that helped get me up and running.  As usual, the trickiest part in getting started is figuring out how to authenticate, but that actually went smoothly (I’m not sure whether I’m getting better at doing that sort of thing, or if the Nest process and/or instructions are better).  I was then able to read information about my Nest thermostat.  It was when I tried to write data that I ran into problems.

I had many failures in trying to perform a write.  At first I tried various incarnations of Java code to perform a REST PUT, but I had a variety of problems and errors.  I simplified things.  I tried a simpler use case.  I removed Java from the picture and just used curl.  Eventually I resorted to the instructions I found to change the target temperature on a thermostat:

curl
-X PUT
-H "Content-Type: application/json"
-H "Authorization: Bearer c.lPg4Z..."
-d "{"target_temperature_f": 72}"
'https://developer-api.nest.com/devices/thermostats/DEVICE_ID'

I plugged in my own authorization token and device ID, but still it wouldn’t work.  After a lot of kicking and swearing and reading various websites and forums, I came up with:

curl
-L 
-X PUT 
-H "Content-Type: application/json"
-H "Authorization: Bearer c.lPg4Z..." 
-d '72' 
https://developer-api.nest.com/devices/thermostats/DEVICE_ID/target_temperature_f

The key differences are:  1) The “-L” flag tells curl to follow the 307 redirect that is returned, 2) Passing just the desired value instead of a JSON snippet, and 3) Specifying the variable name as part of the URL.

When I plugged in my authorization token and device id, things worked–by the time I had taken the seven steps from my disheveled desk to the thermostat, the new value had taken affect and the Nest was turning on the heat.

Although there was some frustration along the way, I had fun playing with the Nest Rest API and am glad I was able to get some basic use cases to work.  Now that I know how to read and write data, I can make make something interesting.