Amazon Alexa

How to turn On/Off TV or Air Conditioner via Alexa

It is very easy to control TVs, Air conditioners or any device that supports infrared communication using Amazon Alexa. In this tutorial we will learn how to control home applicances with On and Off requests using Amazon Alexa.

Step 1

You must learn your remote's On and Off buttons. Here is the learning example code to do that.

Step 2

Once you have learned On and Off button IR codes, you are ready to transmit it back. Here is the learning example code to do that.

Step 3

Now you are ready to integrate with Alexa. You already know how to emit the On and Off buttons in previous steps. Now you need to integrate the Turn on and Turn Off Amazon Alexa voice commands. To do that you have to connect your board to Sinric

Step 4

Signup for Sinric account. Install the Amazon Alexa Skill. Create a smart home device. Connect your ESP to Sinric platform. (Detail instructions are on Sinric home page)

Complete Code

You can find the complete Amazon Alexa integration here

Or

When you ask Alexa to find connected devices, it will send a UPnP broadcast your WiFi network to detect any smart home devices connected. Will emulate a smart home device named "TV" and respond to On/Off requests from Amazon Alexa. (This might not work for all models)

Here's the full example


#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WiFiUdp.h>
#include <functional>
#include <SoftwareSerial.h>

void prepareIds();
boolean connectWifi();
boolean connectUDP();
void startHttpServer();
void turnOnTv();
void turnOffTv();

const char* ssid = "xxxx"; //TODO: replace wifi-name
const char* password = "********"; //TODO: replace wifi-password
String device_name = "tv"; //TODO: Change to your device name
char* turnOnIrCode = "152,35,181,140, ....."; //TODO: Replace your IR code
char* turnOffIrCode = "152,35,181,140, ....."; //TODO: Replace your IR code

WiFiUDP UDP;
boolean udpConnected = false;
IPAddress ipMulti(239, 255, 255, 250);
unsigned int portMulti = 1900;      // local port to listen on
unsigned int localPort = 1900;      // local port to listen on
ESP8266WebServer HTTP(80); 
boolean wifiConnected = false;
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,
String serial;
String persistent_uuid;

boolean cannotConnectToWifi = false;
SoftwareSerial mySerial(D1, D2); // RX, TX

void setup() {
  Serial.begin(115200);
  
  prepareIds();
  
  // Initialise wifi connection
  wifiConnected = connectWifi();

  // only proceed if wifi connection successful
  if(wifiConnected){
    udpConnected = connectUDP();
    
    if (udpConnected){
      // initialise pins if needed 
      startHttpServer();
    }
  }  
}

void loop() {

  HTTP.handleClient();
  delay(1);
  
  
  // if there's data available, read a packet
  // check if the WiFi and UDP connections were successful
  if(wifiConnected){
    if(udpConnected){    
      // if theres data available, read a packet
      int packetSize = UDP.parsePacket();
      
      if(packetSize) {
        IPAddress remote = UDP.remoteIP();
        
        for (int i =0; i < 4; i++) {
          Serial.print(remote[i], DEC);
          if (i < 3) {
            Serial.print(".");
          }
        }
        
        Serial.print(", port ");
        Serial.println(UDP.remotePort());
        
        int len = UDP.read(packetBuffer, 255);
        
        if (len > 0) {
            packetBuffer[len] = 0;
        }

        String request = packetBuffer;
        //Serial.println("Request:");
        //Serial.println(request);
         
        if(request.indexOf('M-SEARCH') > 0) {
            if(request.indexOf("urn:Belkin:device:**") > 0) {
                Serial.println("Responding to search request ...");
                respondToSearch();
            }
        }
      }
        
      delay(10);
    }
  }
}

void prepareIds() {
  uint32_t chipId = ESP.getChipId();
  char uuid[64];
  sprintf_P(uuid, PSTR("38323636-4558-4dda-9188-cda0e6%02x%02x%02x"),
        (uint16_t) ((chipId >> 16) & 0xff),
        (uint16_t) ((chipId >>  8) & 0xff),
        (uint16_t)   chipId        & 0xff);

  serial = String(uuid);
  persistent_uuid = "Socket-1_0-" + serial;
}

void respondToSearch() {
    IPAddress localIP = WiFi.localIP();
    char s[16];
    sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);

    String response = 
         "HTTP/1.1 200 OK\r\n"
         "CACHE-CONTROL: max-age=86400\r\n"
         "DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n"
         "EXT:\r\n"
         "LOCATION: http://" + String(s) + ":80/setup.xml\r\n"
         "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
         "01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n"
         "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"
         "ST: urn:Belkin:device:**\r\n"
         "USN: uuid:" + persistent_uuid + "::urn:Belkin:device:**\r\n"
         "X-User-Agent: redsonic\r\n\r\n";

    UDP.beginPacket(UDP.remoteIP(), UDP.remotePort());
    UDP.write(response.c_str());
    UDP.endPacket();                    
}

void startHttpServer() {
    HTTP.on("/index.html", HTTP_GET, [](){
      HTTP.send(200, "text/plain", "Hello World!");
    });

    HTTP.on("/upnp/control/basicevent1", HTTP_POST, []() {
      Serial.println("########## Responding to  /upnp/control/basicevent1 ... ##########");      

      //for (int x=0; x <= HTTP.args(); x++) {
      //  Serial.println(HTTP.arg(x));
      //}
  
      String request = HTTP.arg(0);      
      
      if(request.indexOf("1") > 0) {
          Serial.println("Got Turn on request");
          turnOnTv();
      }

      if(request.indexOf("0") > 0) {
          Serial.println("Got Turn off request");
          turnOffTv();
      }
      
      HTTP.send(200, "text/plain", "");
    });

    HTTP.on("/eventservice.xml", HTTP_GET, [](){
      Serial.println(" ########## Responding to eventservice.xml ... ########\n");
      String eventservice_xml = ""
            ""
              ""
                "SetBinaryState"
                ""
                  ""
                    ""
                    "BinaryState"
                    "BinaryState"
                    "in"
                  ""
                ""
                 ""
                  ""
                    "BinaryState"
                    "Boolean"
                    "0"
                  ""
                  ""
                    "level"
                    "string"
                    "0"
                  ""
                ""
              ""
            "\r\n"
            "\r\n";
            
      HTTP.send(200, "text/plain", eventservice_xml.c_str());
    });
    
    HTTP.on("/setup.xml", HTTP_GET, [](){
      Serial.println(" ########## Responding to setup.xml ... ########\n");

      IPAddress localIP = WiFi.localIP();
      char s[16];
      sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
    
      String setup_xml = ""
            ""
             ""
                "urn:Belkin:device:controllee:1"
                ""+ device_name +""
                "Belkin International Inc."
                "Emulated Socket"
                "3.1415"
                "uuid:"+ persistent_uuid +""
                "221517K0101769"
                "0"
                ""
                  ""
                      "urn:Belkin:service:basicevent:1"
                      "urn:Belkin:serviceId:basicevent1"
                      "/upnp/control/basicevent1"
                      "/upnp/event/basicevent1"
                      "/eventservice.xml"
                  ""
              "" 
              ""
            "\r\n"
            "\r\n";
            
        HTTP.send(200, "text/xml", setup_xml.c_str());
        
        Serial.print("Sending :");
        Serial.println(setup_xml);
    });
    
    HTTP.begin();  
    Serial.println("HTTP Server started ..");
}


      
// connect to wifi � returns true if successful or false if not
boolean connectWifi(){
  boolean state = true;
  int i = 0;
  
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");
  Serial.println("Connecting to WiFi");

  // Wait for connection
  Serial.print("Connecting ...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    if (i > 10){
      state = false;
      break;
    }
    i++;
  }
  
  if (state){
    Serial.println("");
    Serial.print("Connected to ");
    Serial.println(ssid);
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  }
  else {
    Serial.println("");
    Serial.println("Connection failed.");
  }
  
  return state;
}

boolean connectUDP(){
  boolean state = false;
  
  Serial.println("");
  Serial.println("Connecting to UDP");
  
  if(UDP.beginMulticast(WiFi.localIP(), ipMulti, portMulti)) {
    Serial.println("Connection successful");
    state = true;
  }
  else{
    Serial.println("Connection failed");
  }
  
  return state;
}

void turnOnTv() {
  // Send turn On 
  uint8_t irArray[512];
  unsigned int idx = 1;
  char *str;

  irArray[0] = 227; // Sending ir command
  
  // Convert string to array
  while ((str = strtok_r(turnOnIrCode, ",", &turnOnIrCode)) != NULL) {
    uint8_t ir = (uint8_t)atoi(str + '\0');
    irArray[idx++] = ir;
    yield();
  }
  
  // Write the array to Serial port.
  mySerial.write((uint8_t*)irArray, idx);

}

void turnOffTv() {
  // Send turn off
  uint8_t irArray[512];
  unsigned int idx = 1;
  char *str;

  irArray[0] = 227; // Sending ir command
  
  // Convert string to array
  while ((str = strtok_r(turnOffIrCode, ",", &turnOffIrCode)) != NULL) {
    uint8_t ir = (uint8_t)atoi(str + '\0');
    irArray[idx++] = ir;
    yield();
  }
  
  // Write the array to Serial port.
  mySerial.write((uint8_t*)irArray, idx);
}