Alexa, turn on the fireplace.

Warning: Try this at your own risk.

I had a need to be able to use home automation to turn on the gas fireplace and since Alexa was used quite a bit already in the home I wanted to figure out how, and I succeeded.

I started out by taking a look at how the fireplace was wired up to discover the light switch to turn it on wasn’t actually switching 110v, but was using 18 gauge wire running directly to the fireplace. I figured a relay to close that circuit would be sufficient to turn it on, and I figured correctly in this particular case.

So I went to amazon to find an ESP8266 controlled relay, and was ecstatic to find multiple different ones. The one I went with was the IZOKEE ESP8266 Relay with ESP8266 ESP-01S. I paid a whopping $6.99 for the relay and the ESP01.

The hardest part was getting the code right. The first result for ESP8266 Alexa was to an adafruit post, that was rather dated. Unfortunately following their guide didn’t work well for me because of changes to the libraries.

First problem was an error with the command fauxmo.onMessage(callback); which lead down the rabbit hole of people having issues with FauxMoESP. After messing with that for a bit and getting past that and to the point of searching for it in the Alexa app, it just wasn’t able to be found by Alexa.

Then I saw a reference somewhere to a site called https://sinric.com/ so I decided to check that out and have to say it worked with great success.

So on the ESP01 with the board I bought, Pin 0 is my relay, also the code example I found was setting the pin to HIGH when turned on which didn’t work for me because I wanted it to fail off and used the NO (Normally Open) terminal on the relay for the simple reason, I didn’t want a power failure to turn the fireplace on. So I changed the turnOn command to LOW and turnOff to HIGH.

So Sinric.com gives some example code on their Github for switches, and I used the switch_example.ino with the tweaks for LOW and HIGH I mentioned above.

Once you register in the website, you generate an API key which you past into the sketch, as well as your wifi name and password, and a device id by adding a smart home device.  The name of the device is what Alexa will recognize, so I named mine Fireplace to be able to tell Alexa to turn on the fireplace.

I will post the code at the bottom here, with my changes from the original marked in bold.

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WebSocketsClient.h> //  https://github.com/kakopappa/sinric/wiki/How-to-add-dependency-libraries
#include <ArduinoJson.h> // https://github.com/kakopappa/sinric/wiki/How-to-add-dependency-libraries
#include <StreamString.h>

ESP8266WiFiMulti WiFiMulti;
WebSocketsClient webSocket;
WiFiClient client;

#define MyApiKey "" // TODO: Change to your sinric API Key. Your API Key is displayed on sinric.com dashboard
#define MySSID "" // TODO: Change to your Wifi network SSID
#define MyWifiPassword "" // TODO: Change to your Wifi network password

#define HEARTBEAT_INTERVAL 300000 // 5 Minutes 

const int relayPin1 = 0; // TODO: Change according to your board
const int relayPin2 = 3; // TODO: Change according to your board

uint64_t heartbeatTimestamp = 0;
bool isConnected = false;
 
#define DEVICE1 "xxxxx"  //TODO: Device ID of first device
#define DEVICE2 "xxxxx"  //TODO: Device ID of second device

void setPowerStateOnServer(String deviceId, String value);

// deviceId is the ID assgined to your smart-home-device in sinric.com dashboard. Copy it from dashboard and paste it here

void turnOn(String deviceId) {
  if (deviceId == DEVICE1)
  {  
    Serial.print("Turn on device id: ");
    Serial.println(deviceId);
    
     digitalWrite(relayPin1, LOW); // turn on relay with voltage HIGH
  }
  else  if (deviceId == DEVICE2)
  {  
    Serial.print("Turn on device id: ");
    Serial.println(deviceId);
    
     digitalWrite(relayPin2, LOW); // turn on relay with voltage HIGH
  }  
  else {
    Serial.print("Turn on for unknown device id: ");
    Serial.println(deviceId);
  }     
}

void turnOff(String deviceId) {
   if (deviceId == DEVICE1)
   {  
     Serial.print("Turn off Device ID: ");
     Serial.println(deviceId);
     
     digitalWrite(relayPin1, HIGH);  // turn off relay with voltage LOW
   }
   else if (deviceId == DEVICE2)
   {  
     Serial.print("Turn off Device ID: ");
     Serial.println(relayPin2);
     
     digitalWrite(relayPin1, HIGH);  // turn off relay with voltage LOW
   }
   else {
     Serial.print("Turn off for unknown device id: ");
     Serial.println(deviceId);    
  }
}

void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
  switch(type) {
    case WStype_DISCONNECTED:
      isConnected = false;    
      Serial.printf("[WSc] Webservice disconnected from sinric.com!\n");
      break;
    case WStype_CONNECTED: {
      isConnected = true;
      Serial.printf("[WSc] Service connected to sinric.com at url: %s\n", payload);
      Serial.printf("Waiting for commands from sinric.com ...\n");        
      }
      break;
    case WStype_TEXT: {
        Serial.printf("[WSc] get text: %s\n", payload);
        // Example payloads

        // For Switch or Light device types
        // {"deviceId": xxxx, "action": "setPowerState", value: "ON"} // https://developer.amazon.com/docs/device-apis/alexa-powercontroller.html

        // For Light device type
        // Look at the light example in github
          
        DynamicJsonBuffer jsonBuffer;
        JsonObject& json = jsonBuffer.parseObject((char*)payload); 
        String deviceId = json ["deviceId"];     
        String action = json ["action"];
        
        if(action == "setPowerState") { // Switch or Light
            String value = json ["value"];
            if(value == "ON") {
                turnOn(deviceId);
            } else {
                turnOff(deviceId);
            }
        }
        else if (action == "test") {
            Serial.println("[WSc] received test command from sinric.com");
        }
      }
      break;
    case WStype_BIN:
      Serial.printf("[WSc] get binary length: %u\n", length);
      break;
  }
}

void setup() {
  Serial.begin(57600);
    
  pinMode(relayPin1, OUTPUT);
  pinMode(relayPin2, OUTPUT);
  
  WiFiMulti.addAP(MySSID, MyWifiPassword);
  Serial.println();
  Serial.print("Connecting to Wifi: ");
  Serial.println(MySSID);  

  // Waiting for Wifi connect
  while(WiFiMulti.run() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  if(WiFiMulti.run() == WL_CONNECTED) {
    Serial.println("");
    Serial.print("WiFi connected. ");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  }

  // server address, port and URL
  webSocket.begin("iot.sinric.com", 80, "/");

  // event handler
  webSocket.onEvent(webSocketEvent);
  webSocket.setAuthorization("apikey", MyApiKey);
  
  // try again every 5000ms if connection has failed
  webSocket.setReconnectInterval(5000);   // If you see 'class WebSocketsClient' has no member named 'setReconnectInterval' error update arduinoWebSockets
}

void loop() {
  webSocket.loop();
  
  if(isConnected) {
      uint64_t now = millis();
      
      // Send heartbeat in order to avoid disconnections during ISP resetting IPs over night. Thanks @MacSass
      if((now - heartbeatTimestamp) > HEARTBEAT_INTERVAL) {
          heartbeatTimestamp = now;
          webSocket.sendTXT("H");          
      }
  }   
}

// If you are going to use a push button to on/off the switch manually, use this function to update the status on the server
// so it will reflect on Alexa app.
// eg: setPowerStateOnServer("deviceid", "ON")

// Call ONLY If status changed. DO NOT CALL THIS IN loop() and overload the server. 
void setPowerStateOnServer(String deviceId, String value) {
  DynamicJsonBuffer jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();
  root["deviceId"] = deviceId;
  root["action"] = "setPowerState";
  root["value"] = value;
  StreamString databuf;
  root.printTo(databuf);
  
  webSocket.sendTXT(databuf);
}

Leave a Reply