Skip to content

Instantly share code, notes, and snippets.

@kakopappa
Last active January 14, 2019 01:53
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kakopappa/02299a8ceec0aaaad3ea3bd7f2af8066 to your computer and use it in GitHub Desktop.
Save kakopappa/02299a8ceec0aaaad3ea3bd7f2af8066 to your computer and use it in GitHub Desktop.
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WiFiUdp.h>
#include <functional>
void prepareIds();
boolean connectWifi();
boolean connectUDP();
void startHttpServer();
void turnOnRelay();
void turnOffRelay();
void sendRelayState();
const char* ssid = "************";
const char* password = "********";
String friendlyName = "box"; // Alexa device name
unsigned int localPort = 1900; // local port to listen on
WiFiUDP UDP;
boolean udpConnected = false;
IPAddress ipMulti(239, 255, 255, 250);
unsigned int portMulti = 1900; // local port to listen on
ESP8266WebServer HTTP(80);
boolean wifiConnected = false;
boolean relayState = false;
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,
String serial;
String persistent_uuid;
const int relayPin = D1;
boolean cannotConnectToWifi = false;
void setup() {
Serial.begin(115200);
// Setup Relay
pinMode(relayPin, OUTPUT);
prepareIds();
// Initialise wifi connection
wifiConnected = connectWifi();
// only proceed if wifi connection successful
if(wifiConnected){
Serial.println("Ask Alexa to discover devices");
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 there’s data available, read a packet
int packetSize = UDP.parsePacket();
if(packetSize) {
//Serial.println("");
//Serial.print("Received packet of size ");
//Serial.println(packetSize);
//Serial.print("From ");
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);
}
} else {
// Turn on/off to indicate cannot connect ..
}
}
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() {
Serial.println("");
Serial.print("Sending response to ");
Serial.println(UDP.remoteIP());
Serial.print("Port : ");
Serial.println(UDP.remotePort());
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();
Serial.println("Response sent !");
}
void startHttpServer() {
HTTP.on("/index.html", HTTP_GET, [](){
Serial.println("Got Request index.html ...\n");
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);
Serial.print("request:");
Serial.println(request);
if(request.indexOf("SetBinaryState") >= 0) {
if(request.indexOf("<BinaryState>1</BinaryState>") >= 0) {
Serial.println("Got Turn on request");
turnOnRelay();
}
if(request.indexOf("<BinaryState>0</BinaryState>") >= 0) {
Serial.println("Got Turn off request");
turnOffRelay();
}
}
if(request.indexOf("GetBinaryState") >= 0) {
Serial.println("Got binary state request");
sendRelayState();
}
HTTP.send(200, "text/plain", "");
});
HTTP.on("/eventservice.xml", HTTP_GET, [](){
Serial.println(" ########## Responding to eventservice.xml ... ########\n");
String eventservice_xml = "<scpd xmlns=\"urn:Belkin:service-1-0\">"
"<actionList>"
"<action>"
"<name>SetBinaryState</name>"
"<argumentList>"
"<argument>"
"<retval/>"
"<name>BinaryState</name>"
"<relatedStateVariable>BinaryState</relatedStateVariable>"
"<direction>in</direction>"
"</argument>"
"</argumentList>"
"</action>"
"<action>"
"<name>GetBinaryState</name>"
"<argumentList>"
"<argument>"
"<retval/>"
"<name>BinaryState</name>"
"<relatedStateVariable>BinaryState</relatedStateVariable>"
"<direction>out</direction>"
"</argument>"
"</argumentList>"
"</action>"
"</actionList>"
"<serviceStateTable>"
"<stateVariable sendEvents=\"yes\">"
"<name>BinaryState</name>"
"<dataType>Boolean</dataType>"
"<defaultValue>0</defaultValue>"
"</stateVariable>"
"<stateVariable sendEvents=\"yes\">"
"<name>level</name>"
"<dataType>string</dataType>"
"<defaultValue>0</defaultValue>"
"</stateVariable>"
"</serviceStateTable>"
"</scpd>\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 = "<?xml version=\"1.0\"?>"
"<root>"
"<device>"
"<deviceType>urn:Belkin:device:controllee:1</deviceType>"
"<friendlyName>"+ friendlyName +"</friendlyName>"
"<manufacturer>Belkin International Inc.</manufacturer>"
"<modelName>Socket</modelName>"
"<modelNumber>3.1415</modelNumber>"
"<modelDescription>Belkin Plugin Socket 1.0</modelDescription>\r\n"
"<UDN>uuid:"+ persistent_uuid +"</UDN>"
"<serialNumber>221517K0101769</serialNumber>"
"<binaryState>0</binaryState>"
"<serviceList>"
"<service>"
"<serviceType>urn:Belkin:service:basicevent:1</serviceType>"
"<serviceId>urn:Belkin:serviceId:basicevent1</serviceId>"
"<controlURL>/upnp/control/basicevent1</controlURL>"
"<eventSubURL>/upnp/event/basicevent1</eventSubURL>"
"<SCPDURL>/eventservice.xml</SCPDURL>"
"</service>"
"</serviceList>"
"</device>"
"</root>\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 turnOnRelay() {
digitalWrite(relayPin, HIGH); // turn on relay with voltage HIGH
relayState = true;
String body =
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>\r\n"
"<u:SetBinaryStateResponse xmlns:u=\"urn:Belkin:service:basicevent:1\">\r\n"
"<BinaryState>1</BinaryState>\r\n"
"</u:SetBinaryStateResponse>\r\n"
"</s:Body> </s:Envelope>";
HTTP.send(200, "text/xml", body.c_str());
Serial.print("Sending :");
Serial.println(body);
}
void turnOffRelay() {
digitalWrite(relayPin, LOW); // turn off relay with voltage LOW
relayState = false;
String body =
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>\r\n"
"<u:SetBinaryStateResponse xmlns:u=\"urn:Belkin:service:basicevent:1\">\r\n"
"<BinaryState>0</BinaryState>\r\n"
"</u:SetBinaryStateResponse>\r\n"
"</s:Body> </s:Envelope>";
HTTP.send(200, "text/xml", body.c_str());
Serial.print("Sending :");
Serial.println(body);
}
void sendRelayState() {
String body =
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>\r\n"
"<u:GetBinaryStateResponse xmlns:u=\"urn:Belkin:service:basicevent:1\">\r\n"
"<BinaryState>";
body += (relayState ? "1" : "0");
body += "</BinaryState>\r\n"
"</u:GetBinaryStateResponse>\r\n"
"</s:Body> </s:Envelope>\r\n";
HTTP.send(200, "text/xml", body.c_str());
}
@PrashantaRout
Copy link

Hi Kokopappa,
Code looks very clean. But still it does not work with ECHO releases recently in India. I think it is looking for only Philips Hue not Belkin WEMO.
Any help to make it work , would be thankful. Would be eagerly waiting for your response, keeping fingers crossed

Serial Output I am getting from your code

Received packet of size 356
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: urn:schemas-upnp-org:device:InternetGatewayDevice:1
US

Received packet of size 293
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: uuid:99CBC468-C219-F215-62B7-041F85883EFC
USN: uuid:99

Received packet of size 284
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: upnp:rootdevice
USN: uuid:99CBC468-C219-F215-62B7-041F

Received packet of size 348
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: urn:schemas-upnp-org:service:Layer3Forwarding:1
USN: u

Received packet of size 332
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: urn:schemas-upnp-org:device:WANDevice:1
USN: uuid:101A

Received packet of size 332
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: urn:schemas-upnp-org:device:LANDevice:1
USN: uuid:5ECC

Received packet of size 173
From 192.168.1.109, port 58387
Request:
M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 1
ST: urn:dial-multiscreen-org:service:dial:1
USER-AGENT: Google Chrome/62.0.3202.94 Windows

Received packet of size 173
From 192.168.1.109, port 58387
Request:
M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 1
ST: urn:dial-multiscreen-org:service:dial:1
USER-AGENT: Google Chrome/62.0.3202.94 Windows

Received packet of size 173
From 192.168.1.109, port 58387
Request:
M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 1
ST: urn:dial-multiscreen-org:service:dial:1
USER-AGENT: Google Chrome/62.0.3202.94 Windows

Received packet of size 173
From 192.168.1.109, port 58387
Request:
M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 1
ST: urn:dial-multiscreen-org:service:dial:1
USER-AGENT: Google Chrome/62.0.3202.94 Windows

Received packet of size 356
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: urn:schemas-upnp-org:device:InternetGatewayDevice:1
US

Received packet of size 293
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: uuid:99CBC468-C219-F215-62B7-041F85883EFC
USN: uuid:99

Received packet of size 284
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: upnp:rootdevice
USN: uuid:99CBC468-C219-F215-62B7-041F

Received packet of size 348
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: urn:schemas-upnp-org:service:Layer3Forwarding:1
USN: u

Received packet of size 332
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: urn:schemas-upnp-org:device:WANDevice:1
USN: uuid:101A

Received packet of size 346
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: urn:schemas-upnp-org:service:WANIPConnection:1
USN: uu

Received packet of size 356
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: urn:schemas-upnp-org:device:InternetGatewayDevice:1
US

Received packet of size 293
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: uuid:99CBC468-C219-F215-62B7-041F85883EFC
USN: uuid:99

Received packet of size 348
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: urn:schemas-upnp-org:service:Layer3Forwarding:1
USN: u

Received packet of size 332
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: urn:schemas-upnp-org:device:WANDevice:1
USN: uuid:101A

Received packet of size 293
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: uuid:101A0754-40FF-5A61-2EF3-C0DCEFF7EC6C
USN: uuid:10

Received packet of size 346
From 192.168.1.1, port 1900
Request:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
Cache-Control: max-age=60
Location: http://192.168.1.1:1780/InternetGatewayDevice.xml
NTS: ssdp:alive
Server: POSIX, UPnP/1.0 linux/5.100.138.11
NT: urn:schemas-upnp-org:service:WANIPConnection:1
USN: uu

@kakopappa
Copy link
Author

kakopappa commented Dec 19, 2017

hello, sorry about the late response.

I have updated the code https://github.com/kakopappa/arduino-esp8266-alexa-wemo-switch/blob/master/sinric.ino

Can you check whether it works for you now?

Thanks

@satishkumar2005
Copy link

HI Kakopappa,

code is not working on echo plus device, Nodemcu is not discoverable. Kindly share if we need to make any changes in code for echo plus or we need any additional library.

Thanks

@Red-Robbo
Copy link

Hi Kakopappa,
I had exactly the same problem as others using Echo Plus Release 2, & NodeMCU not being discoverable, but thanks to your code, the device is now recognised by Alexa fine, and able to turn output on and off successfully.
Thank You!

@RobertoAPinheiro
Copy link

RobertoAPinheiro commented Jan 18, 2018

Hi Kokopappa, first, my congratulations for the code!
But, how can I add more than one device, because I have 4 relays on my node?
Thank You!!!

@gilahacker
Copy link

+1 to RobertoAPinheiro's question. I'm trying to help my brother set this up. It works as is for the first pin, but the device he's using has 8 pins.

At the very least, I'm guessing we'll need to duplicate the "device" bit in setup_xml for each pin, and switch relayPin and friendlyname to arrays, but I'm not sure exactly what else.

@n6zop
Copy link

n6zop commented May 13, 2018

Just setup the program and the hardware. It's great. Thanks Kokapappa. This code work very well. I more problems getting my Alexa set up. I was trying to change the code some to control two relays with it. I'm not a programmer, I have learned some since I got to playing with Arduino. I will still try to get more then one relay working.

@Zaxper95
Copy link

Zaxper95 commented May 26, 2018

hi Kokopappa,
I have been searching for code only to find the one that will let my esp8266 d1 mini be discovered by amazon echo dot and your code is the only one that I have found so far that works. I am using your code to get echo dot to turn on light on and off using a relay, and I am not sure where to sandwich that code into your code. My knowledge of Arduino is very basic. Please help. Here is the code I have so far.

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

void prepareIds();
boolean connectWifi();
boolean connectUDP();
void startHttpServer();
void turnOnRelay();
void turnOffRelay();
void sendRelayState();

const char* ssid = "-----------";
const char* password = "------------";
String friendlyName = "the light"; // Alexa device name
unsigned int localPort = 1900; // local port to listen on
bool state;

WiFiUDP UDP;

boolean udpConnected = false;

IPAddress ipMulti(239, 255, 255, 250);

unsigned int portMulti = 1900; // local port to listen on

ESP8266WebServer HTTP(80);

boolean wifiConnected = false;

boolean relayState = false;

char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,

String serial;

String persistent_uuid;

const int relayPin = D1;

boolean cannotConnectToWifi = false;

void setup() {

Serial.begin(115200);

// Setup Relay

pinMode(relayPin, OUTPUT);

prepareIds();

// Initialise wifi connection

wifiConnected = connectWifi();

// only proceed if wifi connection successful

if(wifiConnected){

Serial.println("Ask Alexa to discover devices");

udpConnected = connectUDP();



if (udpConnected){

  // initialise pins if needed 
  Serial.print("Device "); Serial.print(friendlyName);
  Serial.print(" state: ");
  if(state){
    Serial.println("ON");
    digitalWrite(D2,HIGH);
  }else{
    Serial.print("OFF");
    digitalWrite(D2,LOW);
  }

  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 there’s data available, read a packet

  int packetSize = UDP.parsePacket();

  

  if(packetSize) {

    //Serial.println("");

    //Serial.print("Received packet of size ");

    //Serial.println(packetSize);

    //Serial.print("From ");

    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);

}

} else {

  // Turn on/off to indicate cannot connect ..      

}

}

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() {

Serial.println("");

Serial.print("Sending response to ");

Serial.println(UDP.remoteIP());

Serial.print("Port : ");

Serial.println(UDP.remotePort());



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();                    



 Serial.println("Response sent !");

}

void startHttpServer() {

HTTP.on("/index.html", HTTP_GET, [](){

  Serial.println("Got Request index.html ...\n");

  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);      

  Serial.print("request:");

  Serial.println(request);



  if(request.indexOf("SetBinaryState") >= 0) {

    if(request.indexOf("<BinaryState>1</BinaryState>") >= 0) {

        Serial.println("Got Turn on request");

        turnOnRelay();

    }



    if(request.indexOf("<BinaryState>0</BinaryState>") >= 0) {

        Serial.println("Got Turn off request");

        turnOffRelay();

    }

  }



  if(request.indexOf("GetBinaryState") >= 0) {

    Serial.println("Got binary state request");

    sendRelayState();

  }

  

  

  HTTP.send(200, "text/plain", "");

});



HTTP.on("/eventservice.xml", HTTP_GET, [](){

  Serial.println(" ########## Responding to eventservice.xml ... ########\n");

  String eventservice_xml = "<scpd xmlns=\"urn:Belkin:service-1-0\">"

    "<actionList>"

      "<action>"

        "<name>SetBinaryState</name>"

        "<argumentList>"

          "<argument>"

            "<retval/>"

            "<name>BinaryState</name>"

            "<relatedStateVariable>BinaryState</relatedStateVariable>"

            "<direction>in</direction>"

            "</argument>"

        "</argumentList>"

      "</action>"

      "<action>"

        "<name>GetBinaryState</name>"

        "<argumentList>"

          "<argument>"

            "<retval/>"

            "<name>BinaryState</name>"

            "<relatedStateVariable>BinaryState</relatedStateVariable>"

            "<direction>out</direction>"

            "</argument>"

        "</argumentList>"

      "</action>"

  "</actionList>"

    "<serviceStateTable>"

      "<stateVariable sendEvents=\"yes\">"

        "<name>BinaryState</name>"

        "<dataType>Boolean</dataType>"

        "<defaultValue>0</defaultValue>"

       "</stateVariable>"

       "<stateVariable sendEvents=\"yes\">"

          "<name>level</name>"

          "<dataType>string</dataType>"

          "<defaultValue>0</defaultValue>"

       "</stateVariable>"

    "</serviceStateTable>"

    "</scpd>\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 = "<?xml version=\"1.0\"?>"

        "<root>"

         "<device>"

            "<deviceType>urn:Belkin:device:controllee:1</deviceType>"

            "<friendlyName>"+ friendlyName +"</friendlyName>"

            "<manufacturer>Belkin International Inc.</manufacturer>"

            "<modelName>Socket</modelName>"

            "<modelNumber>3.1415</modelNumber>"

            "<modelDescription>Belkin Plugin Socket 1.0</modelDescription>\r\n"

            "<UDN>uuid:"+ persistent_uuid +"</UDN>"

            "<serialNumber>221517K0101769</serialNumber>"

            "<binaryState>0</binaryState>"

            "<serviceList>"

              "<service>"

                  "<serviceType>urn:Belkin:service:basicevent:1</serviceType>"

                  "<serviceId>urn:Belkin:serviceId:basicevent1</serviceId>"

                  "<controlURL>/upnp/control/basicevent1</controlURL>"

                  "<eventSubURL>/upnp/event/basicevent1</eventSubURL>"

                  "<SCPDURL>/eventservice.xml</SCPDURL>"

              "</service>"

          "</serviceList>" 

          "</device>"

        "</root>\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 turnOnRelay() {

digitalWrite(relayPin, HIGH); // turn on relay with voltage HIGH

relayState = true;

String body =

  "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>\r\n"

  "<u:SetBinaryStateResponse xmlns:u=\"urn:Belkin:service:basicevent:1\">\r\n"

  "<BinaryState>1</BinaryState>\r\n"

  "</u:SetBinaryStateResponse>\r\n"

  "</s:Body> </s:Envelope>";

HTTP.send(200, "text/xml", body.c_str());

Serial.print("Sending :");

Serial.println(body);

}

void turnOffRelay() {

digitalWrite(relayPin, LOW); // turn off relay with voltage LOW

relayState = false;

String body =

  "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>\r\n"

  "<u:SetBinaryStateResponse xmlns:u=\"urn:Belkin:service:basicevent:1\">\r\n"

  "<BinaryState>0</BinaryState>\r\n"

  "</u:SetBinaryStateResponse>\r\n"

  "</s:Body> </s:Envelope>";

HTTP.send(200, "text/xml", body.c_str());

Serial.print("Sending :");

Serial.println(body);

}

void sendRelayState() {

String body =

  "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>\r\n"

  "<u:GetBinaryStateResponse xmlns:u=\"urn:Belkin:service:basicevent:1\">\r\n"

  "<BinaryState>";

body += (relayState ? "1" : "0");

body += "\r\n"

  "</u:GetBinaryStateResponse>\r\n"

  "</s:Body> </s:Envelope>\r\n";

HTTP.send(200, "text/xml", body.c_str());

}
PS: I have figured it out. Thank you, your code was perfect.

@arshad3699
Copy link

hi Zaxper95
plz upload code..,my alexa is not discovering NodeMCU
plz hlp

@RyuAustria
Copy link

RyuAustria commented Jun 6, 2018

Hello kakopappa,
The code is working perfectly! However, which parts of the code do I have to change/add in order to control more than 1 relay? Maybe just an overview would help. Thanks!

@RafVerzet
Copy link

Hello Kakopappa and all members,
thanks for your code, so far it is the only one I found that works with my Echo Dot v2. But like other members I would like to add more devices to the code. Does anyone have any idea how to add multiple devices? I am using a WeMos D1 lite mini with 9 DO so it would be a petty not to use them all :-)
Thanks for your help!

@Stuckeymax
Copy link

Hello kakopappa. I adapted your code to press 3 buttons on an RTS Somfy handheld motorized drapery controller, see somfydevkit.ino. Thanks for the hard work. I'm using a NodeMCU v1.0 board, and aside from the occasional crash (perhaps 1 per week or less), it has been working great.

Best regards ;)

Stuckeymax

@peteiwenzel
Copy link

Hi kakopappa - I've used your code but unfortunately my device is not discover-able by Alexa. Can you suggest what troubleshooting I should do? Below is the serial output. As an FYI it seems that I cannot get any code to work (e.g. FauxmoESP, etc). I am using NodeMCU ESP-12E, ESP8266 v2.4.2, and Arduino IDE 1.8.8.

19:44:43.678 -> ⸮
19:44:43.678 -> Connecting to WiFi
19:44:43.678 -> Connecting ......
19:44:45.184 -> Connected to PetaPepe 2.4
19:44:45.184 -> IP address: 192.168.1.147
19:44:45.184 -> Ask Alexa to discover devices
19:44:45.184 ->
19:44:45.184 -> Connecting to UDP
19:44:45.184 -> Connection successful
19:44:45.184 -> HTTP Server started ..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment