Project in progress
Access Your Ecobee Thermostat Using Ecobee API

Access Your Ecobee Thermostat Using Ecobee API © GPL3+

Use Arduino Uno WiFi to access your home Ecobee thermostat and more, this is a good introduction to see APIs in action using OAuth keys.

  • 191 views
  • 0 comments
  • 3 respects

Components and supplies

About this project

In this project I discovered a world of APIs which my Ardunio WiFi can directly access without a middle application. What I wanted to do was get my living room temperature. My first shot was to explore using existing Arduino projects with a temperature sensor. This would mean I would need one Arduino to measure the temperature and use WiFi to connect it to my second Arduino wood stove controller. This seemed like the more complex path. I already have an Ecobee WiFi thermostat that is updating a remote Ecobee server. some how I should be able to get this information. My first try was using Wireshark to sniff the IP address. Here I could capture data being sent out, however I could not figure out how to get the temperature. for the second try, I learned Ecobee has an Application Programing Interface (API). This led me on a long road of learning how to use Arduino Uno WiFi to get this information. This project will the code development and setting up the Ecobee API.

Secret file:

Disclaimer:

This is my first project in Arduino, with the focus on making it work. I see many areas to improve the use of C, but settled for simple statements, due to my lack of C understanding. Many hours were spent banging my head against the wall. If you get stuck, I would be happy to try and assist. Next step I will use this knowledge to use the API for Gmail.

Code

EcoBee_API_Application.inoArduino
This code will log into your local WiFi, then access https:\\api.ecobee.com to get Ecobee thermostat actual temperature and desired temperature. Information is displayed on the debug communications port stating the code progress.
/*
Edited by ChuggingAlong 02/13/2020


*/
#include <EEPROM.h>
#include <ArduinoJson.h>
#include <SPI.h>
#include <ArduinoHttpClient.h>
#include <WiFiNINA.h>
#include "arduino_secrets.h"

//===== please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;        // your network password (use for WPA)

//===== EEProm addresses =========
// A token refresh immediately expires the previously issued access and refresh tokens and issues brand new tokens.
// EEProm is used to alway store the latest tokens
//addr 0-31 refresh_token
const int address_refresh_token = 0;
//addr 32 '\0' null termination char
const int address_null_termination = 32;        // used to check if EEProm is initialized

String access_token = "";
String refresh_token = "";
String ecobeePin = "";
String code = "";
int LivingRoomTemp = 0;
int DesiredRoomTemp = 0;

int status = WL_IDLE_STATUS;
const size_t MAX_CONTENT_SIZE = 1600;

int statuscode = 0;
String response = "";

char server[] = "api.ecobee.com";

WiFiSSLClient wifiClient;
HttpClient client = HttpClient(wifiClient, server, 443);

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < "1.0.0") {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {                        // Connect to WPA/WPA2 network:
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);
    delay(10000);                                         // wait 10 seconds for connection:
  }

  Serial.println("You're connected to the network");
  //printCurrentNet();    Leave for Debug
  //printWifiData();

  Serial.println("Starting connection to server...");     // if you get a connection, report back via serial:
  client.beginRequest();

  //======= get latest refresh code from EEProm to use for refresh tokens ===================
  refresh_token = readEEstring(address_refresh_token);
  client.post("https://api.ecobee.com/token?grant_type=refresh_token&refresh_token=" + refresh_token + "&client_id=" + SECRET_Client_ID);
  client.endRequest();
  // read the status code and body of the response
  int statusCode = client.responseStatusCode();
  if (statusCode == 200)
  {
    String response = client.responseBody();
    Serial.print("Refresh Status code: ");
    Serial.println(statusCode);
    Serial.print("Refresh Response: ");
    Serial.println(response);

    Extract_Json_Strings(response, access_token, "access_token", refresh_token, "refresh_token");
    writeEEstring (address_refresh_token, refresh_token);       // Save for next running of Setup/Refresh

    Serial.print ("refresh_token: ");
    Serial.println (refresh_token );
    Serial.print ("access_token: ");
    Serial.println (access_token );
  } else {
    Serial.println ("Error in obtaining access code, need to run create_new_refresh_keys ()");
    create_new_refresh_keys (refresh_token, access_token);
  }
 

  //======= Send Request for Ecobee rooom temperature & Desired temperature ===================
  String postData = "{\"selection\":{\"selectionType\":\"registered\",\"selectionMatch\":\"\",\"includeRuntime\":true}}";
  client.beginRequest();
  client.get("https://api.ecobee.com/1/thermostat?format=json&body=" + postData);   //moved postData here & changed to a GET
  client.sendHeader("Authorization", ("Bearer " + access_token));
  Serial.println("Bearer " + access_token);
  client.sendHeader("Content-Type", "text/json");
  client.endRequest();
  // ========  read the status code and body of the response  ===========
  statusCode = client.responseStatusCode();
  response = client.responseBody();
  Serial.print("StatusCode: ");
  Serial.println(statusCode);
  Serial.print("Response: ");
  Serial.println(response);

  // ======= Extract temperature and desired temperature ========= Using String functions, easier than ArduinoJSON calls.
  int StartOf = response.indexOf ("actualTemperature");
  String actual_Temperature_Str (response.substring((StartOf + 20), StartOf + 23));
  LivingRoomTemp = actual_Temperature_Str.toInt();
  float x = LivingRoomTemp;
  x = x / 10;
  Serial.print("LivingRoomTemp: ");
  Serial.println (x, 1);
  StartOf = response.indexOf ("desiredHeat");
  String Disired_Heat_Str = (response.substring((StartOf + 14), StartOf + 17));
  DesiredRoomTemp = Disired_Heat_Str.toInt();
  x = DesiredRoomTemp;
  x = x / 10;
  Serial.print("Disired Temp: ");
  Serial.println (x, 1);

}

void loop() {

  while (true);

}

void printWifiData() {
  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
  Serial.println(ip);

  // print your MAC address:
  byte mac[6];
  WiFi.macAddress(mac);
  Serial.print("MAC address: ");
  printMacAddress(mac);
}

void printCurrentNet() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print the MAC address of the router you're attached to:
  byte bssid[6];
  WiFi.BSSID(bssid);
  Serial.print("BSSID: ");
  printMacAddress(bssid);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.println(rssi);

  // print the encryption type:
  byte encryption = WiFi.encryptionType();
  Serial.print("Encryption Type:");
  Serial.println(encryption, HEX);
  Serial.println();
}

void printMacAddress(byte mac[]) {
  for (int i = 5; i >= 0; i--) {
    if (mac[i] < 16) {
      Serial.print("0");
    }
    Serial.print(mac[i], HEX);
    if (i > 0) {
      Serial.print(":");
    }
  }
  Serial.println();
}

void writeEEstring(char add, String data) {
  int _size = data.length();
  int i;
  for (i = 0; i < _size; i++)
  {
    EEPROM.write(add + i, data[i]);
  }
  EEPROM.write(add + _size, '\0'); //Add termination null character for String Data
  //  EEPROM.commit();
}


String readEEstring(char add) {
  int i;
  char data[100]; //Max 100 Bytes
  int len = 0;
  unsigned char k;
  k = EEPROM.read(add);
  while (k != '\0' && len < 500) //Read until null character
  {
    k = EEPROM.read(add + len);
    data[len] = k;
    len++;
  }
  data[len] = '\0';
  return String(data);
}

void Extract_Json_Strings (String data, String & Var_1, String Var_1_json, String & Var_2, String Var_2_json) { // use of ampersand passes pointers
  StaticJsonDocument <500> jsonDoc;
  auto error = deserializeJson(jsonDoc, data);
  if (error) {
    Serial.print(F("deserializeJson() failed with code "));
    Serial.println(error.c_str());
  }
  else {
    String tmp1 = jsonDoc[Var_1_json];
    Var_1 = tmp1 ;                            // this is the only way I could get this access_token updated
    String tmp2 = jsonDoc[Var_2_json];
    Var_2 = tmp2 ;                            // this is the only way I could get this access_token updated
    /*
      Serial.print (Var_1_json);
      Serial.print (": ");
      Serial.println (Var_1);
      Serial.print (Var_2_json);
      Serial.print (": ");
      Serial.println (Var_2);
    */
  }
}

void create_new_refresh_keys (String & refresh_token_loc, String & access_token_loc) {
  client.beginRequest();

  //======= get ecobeePin ===================
  // converted from JavaScript: https://www.ecobee.com/home/developer/api/examples/ex1.shtml
  client.get("https://api.ecobee.com/authorize?response_type=ecobeePin&client_id=dRc7CqSwIxKI7pNp3ZMDqJGPY7aT9akm&scope=smartWrite");
  client.endRequest();
  // read the status code and body of the response
  int statusCode = client.responseStatusCode();
  String response = client.responseBody();

  Serial.print("ecobeePin Status code: ");
  Serial.println(statusCode);
  Serial.print("Refresh Response: ");
  Serial.println(response);

  Extract_Json_Strings(response, ecobeePin, "ecobeePin", code, "code");
  writeEEstring (address_refresh_token, refresh_token);       // Save for next running of Setup/Refresh

  Serial.print ("Aurthorization code: ");
  Serial.println (code );
  Serial.print ("ecobeePin: ");
  Serial.println (ecobeePin );
  Serial.println ("go to ecobee.com MY APPS");
  Serial.println ("click add appliaction & paste ecobeePin into autorization code");
  Serial.println ("click add app in lower right corner");

  //======= get ecobee Aurthorization code, final step to get Access and Refresh codes ===================
  // converted from JavaScript: https://www.ecobee.com/home/developer/api/examples/ex1.shtml
  refresh_token = "null";
  delay (20000);
  int i = 0;
  while (refresh_token == "null" || i == 6) {
    client.post("https://api.ecobee.com/token?grant_type=ecobeePin&code=" + code + "&client_id=" + SECRET_Client_ID);
    client.endRequest();
    // read the status code and body of the response
    statusCode = client.responseStatusCode();
    response = client.responseBody();

    Serial.print("Aurthorization Status code: ");
    Serial.println(statusCode);
    Serial.print("Refresh Response: ");
    Serial.println(response);

    Extract_Json_Strings(response, access_token_loc, "access_token", refresh_token_loc, "refresh_token");
    writeEEstring (address_refresh_token, refresh_token_loc);       // Save for next running of Setup/Refresh

    Serial.print ("refresh_token: ");
    Serial.println (refresh_token_loc );
    Serial.print ("access_token: ");
    Serial.println (access_token_loc );
    delay (10000);                          //10 Second Delay
    if (i == 6) {
      Serial.println("Time out error > 1 minute");
      Serial.println("press reset to retry");
      while (true);
    }
  }

}
Arduino_secrets.hArduino
#define SECRET_SSID "add your wifi network name"
#define SECRET_PASS "add you wifi network pasword"
#define SECRET_Client_ID "add client ID from Ecobee developer"
Arduino_secrets.hArduino
#define SECRET_SSID "add your wifi network name"
#define SECRET_PASS "add you wifi network pasword"
#define SECRET_Client_ID "add client ID from Ecobee developer"

Schematics

Arduino Uno Wifi Rev2, no changes
arduino_uno_ref_R4q5MkUyxt.sch

Comments

Similar projects you might like

The smart thermostat

Project in progress by Daniel Roman

  • 10,302 views
  • 2 comments
  • 15 respects

Arduino LCD Thermostat

Project tutorial by Arduino “having11” Guy

  • 23,519 views
  • 29 comments
  • 47 respects

A PM2.5 and PM 10 Detector design for Windows 10 UWP App

Project tutorial by Jiong Shi

  • 10,639 views
  • 6 comments
  • 24 respects

Weather Station v1.3 with RF Transmission

Project showcase by derapados

  • 8,097 views
  • 2 comments
  • 27 respects

LED Matrix + Motion Sensor Door Display [Arduino Holiday]

Project tutorial by HeathenHacks

  • 6,191 views
  • 5 comments
  • 22 respects

Tweeting Thermostat with Arduino!

Project tutorial by Arduino “having11” Guy

  • 4,482 views
  • 0 comments
  • 9 respects
Add projectSign up / Login