Ecobee3 API

Intro

One of my newest projects entails introducing my home to the IoT (Internet of Things). My
first venture into this, was installing an Ecobee3 system into my home. For those that dont
know, the Ecobee3 is a wifi enabled thermostat similar to the Nest product.
One of the cooler things about this product is the open API that allows you to develop your
own software to manage your thermostat. Suddenly an idea sparked in my head, I decided to write
a quick script that I can use to grab information from my thermostate to output into my local
installation of Nagios (more on that later).
For this tutorial, I will be developing a Perl application on a Linux based system.

How Does The API Work?

Ecobee describes its API as an http-based interface for control and access to the ecobee thermostats. Integrators will be allowed to read, update and poll information about their thermostat(s). ecobee aims to be backward compatible with previous versions of the API and to protect implementations from breaking when new features or changes are implemented. The API also strives to be self-documenting, easy to understand and use.
Once I started digging into the API, I soon started to realize that the integration is somewhat
complex. The API requires two keys to be stored, the first, known as the access-token is used to
communicate with the thermostat. The second key is called the refresh-token, this is used to refresh
the access-token which is only available for one hour.
This makes coding a bit more complex, as you will need to make the decision of how to manage tokens.
More advanced code can take the access-token and keep track of the expiry, and only refresh the token
once the token has expired. For our use case, we will refresh the token every time we run the script.

Let's Get Started

The first thing that we need to do before we can do any sort of application development, is to grab some
API keys and authenticate our application. The first thing you will need to do is get a developer account
at Ecobee.com. You can grab one from the following link: https://www.ecobee.com/developers/
Next, Ecobee provides a nifty little tool to get you started with your API key and initial tokens. Go ahead
and follow the steps here to get started: https://www.ecobee.com/home/developer/api/examples/ex1.shtml. Follow
the tutorial and grab your access_token and refresh_token from Step 3.

Perl and Curl

Because the API is web based, we will be using Curl quite a bit to make our requests and consume our responses.
Remember, that this application is linux based so tweaks will need to be made for Windows based applications.
The first thing that we will do, is set up our core application information.

$silent - This will define if we are running in silent mode (no printing to console)

$apiKey - This is your application's ApiKey which you should have obtained through the ecobee tutorial. Make sure to keep this secret and encrypt if you plan on distributing your app

$accessToken - We will store our access token locally here

$refreshToken - We will store our refresh token locally here

$readToken - This is the entire token we read from our temp file

$refresh_filename - Our temp file to hold our access/refresh tokens

$ecobee_filename - Our temp file to hold our ecobee data

# Allow the user to provide an argument. At this time we accept any
# argument to symbolize that we are going to put this app in silent
# mode.
if($#ARGV + 1 > 0) {
$silent = 1;
} else {
print "Please Add An 's' to the command line to silence";
}

This part of our code is used to easily read any additional parameter to signify that we want to run the application
in a silent mode. We can eventually expand on this if we want to do more complex things like pass in the data
object that we want to retrieve instead of what we will perform in this example.

# Read our current tokens from our temporary storage file. This
# file is expected to contain a single line with two tokens separated
# by a space. The first token is the access token, the second is the
# refresh token.
if(-e "/tmp/refresh_token") {
open my $fh, ';
close $fh;
}
# Hopefully we read a token, this is really ony expected to fail the first
# time we run the application. After that, we need our token from the
# file. Else this defaults to the tokens above, which wont work
if(defined $readToken) {
print "I Read Token From File: $readToken\n" if !$silent;
($accessToken, $refreshToken) = split(/ /, $readToken);
}

This part of our code will read our tokens from our temp files. Remember we need to store our tokens locally
so that we can constantly refresh and ensure that we have non expired tokens. We will create these initial temp files
at the end of this tutorial, but for now, anticipate that they will be there and contain data. Our refresh_token
file will contain two strings separated by a space on a single line.

# Next, we are going to call the ecobee3 api, and perform a refresh. If we
# were a smarter application, we would keep track of when the token actually
# expires and only run this whenever we actually expired.
my $token_curl = `curl -s --data "grant_type=refresh_token&&code=$refreshToken&client_id=$apiKey" "https://api.ecobee.com/token"`;
print "My Curl Output: $token_curl\n" if !$silent;
# We need to extract two values, the access_token, and the refresh_token
print "Extracting Token\n" if !$silent;
my ($token,$refresh) = $token_curl =~ /\"access_token\": \"(.*?)\"[.\S\s]*\"refresh_token\": \"(.*?)\"/;
print "Token: $token, Refresh Token: $refresh\n" if !$silent;

The next thing we are doing, is actually calling the ecobee API to do a refresh of our token. The curl request
in this block is doing a POST as defined by our --data parameter. We are using our refresh_token and
our APIKey here to perform our refresh. The expected response here is a JSON response that contains our tokens
and expiry time:

# Assuming we got the token (we should have, else something bad happened)...
if(defined $token) {
# Let's write the two new tokens to our temporary file so that we can
# use them for the next iteration of our application
print "Writing Response To File\n" if !$silent;
open my $fh, ">", $refresh_filename or die("Could not open file. $!");
print $fh "$token $refresh";
close $fh;
# Now lets ask the Ecobee3 for some information. This call will return
# all runtime information from the Ecobee portal
print "Now Getting Thermostat Data Using $token\n" if !$silent;
my $thermostat_curl = `curl -s -H 'Content-Type: text/json' -H 'Authorization: Bearer ${token}' 'https://api.ecobee.com/1/thermostat?format=json&body=\\{\"selection\":\\{\"selectionType\":\"registered\",\"selectionMatch\":\"\",\"includeRuntime\":true\\}\\}'`;
print $thermostat_curl . "\n" if !$silent;
# Make sure that we actually got a response
if(defined $thermostat_curl) {
# Write that information to a file so that we can read outside the app
print "Writing Thermostat Data To File\n" if !$silent;
open my $fh, ">", $ecobee_filename or die("Could not open file. $!");
print $fh $thermostat_curl;
close $fh;
}
}

Now that we have refreshed our tokens, we need to store them so we can use them again. The first thing
we do in the above block, is save the tokens to our temporary file. This is the file we read from earlier so
take note that this is how we are closing the loop.
Next, we will use our access_token (which we have defined as $token from our curl request), to communicate
to the ecobee web portal to get our runtime information. The data that is returned we store in our temporary
ecobee_data file.

At this point, we expect a result that gives us all of our thermostat runtime data. The data that returns should
look similar to the following data:

Creating Our Temporary Files

Before you get ready to run the application and see your results, we need to make sure we create our
two temporary files. The first one is easy and will be a blank file called '/tmp/ecobee_data'. The
second file will actually contain data which will simply be our initial access_token and refresh_token.