-
-
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()); | |
| } |
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!
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!
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
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 ..
hi Zaxper95
plz upload code..,my alexa is not discovering NodeMCU
plz hlp