Andrewjohnsen31
Published © GPL3+

Access Your Ecobee Thermostat Using Ecobee API

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.

IntermediateWork in progress4,775
Access Your Ecobee Thermostat Using Ecobee API

Things used in this project

Hardware components

Arduino UNO Wifi Rev.2
Arduino UNO Wifi Rev.2
×1
ecobee3 lite
×1

Story

Read more

Schematics

Arduino Uno Wifi Rev2, no changes

Code

EcoBee_API_Application.ino

Arduino
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.h

Arduino
#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.h

Arduino
#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"

Credits

Andrewjohnsen31

Andrewjohnsen31

0 projects • 1 follower

Comments