diff --git a/wled00/src/dependencies/alexa-multiple/CallbackFunction.h b/wled00/src/dependencies/alexa-multiple/CallbackFunction.h deleted file mode 100644 index df9feb1f..00000000 --- a/wled00/src/dependencies/alexa-multiple/CallbackFunction.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALLBACKFUNCTION_H -#define CALLBACKFUNCTION_H - -#include - -typedef void (*CallbackFunction) (); - -#endif diff --git a/wled00/src/dependencies/alexa-multiple/LICENSE.txt b/wled00/src/dependencies/alexa-multiple/LICENSE.txt deleted file mode 100644 index 8d34afeb..00000000 --- a/wled00/src/dependencies/alexa-multiple/LICENSE.txt +++ /dev/null @@ -1,23 +0,0 @@ -https://github.com/kakopappa/arduino-esp8266-alexa-multiple-wemo-switch - -The MIT License (MIT) - -Copyright (c) 2015 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/wled00/src/dependencies/alexa-multiple/Switch.cpp b/wled00/src/dependencies/alexa-multiple/Switch.cpp deleted file mode 100644 index 5ed674ed..00000000 --- a/wled00/src/dependencies/alexa-multiple/Switch.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include "Switch.h" -#include "CallbackFunction.h" - -//#define DEBUG - -#ifdef DEBUG - #define DEBUG_PRINT(x) Serial.print (x) - #define DEBUG_PRINTLN(x) Serial.println (x) - #define DEBUG_PRINTF(x) Serial.printf (x) -#else - #define DEBUG_PRINT(x) - #define DEBUG_PRINTLN(x) - #define DEBUG_PRINTF(x) -#endif - -//<> -Switch::Switch(){ - DEBUG_PRINTLN("default constructor called"); -} -//Switch::Switch(String alexaInvokeName,unsigned int port){ -Switch::Switch(String alexaInvokeName, unsigned int port, CallbackFunction oncb, CallbackFunction offcb){ - 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+"-"+ String(port); - - device_name = alexaInvokeName; - localPort = port; - onCallback = oncb; - offCallback = offcb; - - startWebServer(); -} - - - -//<> -Switch::~Switch(){/*nothing to destruct*/} - -void Switch::serverLoop(){ - if (server != NULL) { - server->handleClient(); - delay(1); - } -} - -void Switch::startWebServer(){ - server = new ESP8266WebServer(localPort); - - server->on("/", [&]() { - handleRoot(); - }); - - - server->on("/setup.xml", [&]() { - handleSetupXml(); - }); - - server->on("/upnp/control/basicevent1", [&]() { - handleUpnpControl(); - }); - - server->on("/eventservice.xml", [&]() { - handleEventservice(); - }); - - //server->onNotFound(handleNotFound); - server->begin(); - - DEBUG_PRINTLN("WebServer started on port: "); - DEBUG_PRINTLN(localPort); -} - -void Switch::handleEventservice(){ - DEBUG_PRINTLN(" ########## Responding to eventservice.xml ... ########\n"); - - String eventservice_xml = "" - "" - "" - "SetBinaryState" - "" - "" - "" - "BinaryState" - "BinaryState" - "in" - "" - "" - "" - "" - "BinaryState" - "Boolean" - "0" - "" - "" - "level" - "string" - "0" - "" - "" - "" - "\r\n" - "\r\n"; - - server->send(200, "text/plain", eventservice_xml.c_str()); -} - -void Switch::handleUpnpControl(){ - DEBUG_PRINTLN("########## Responding to /upnp/control/basicevent1 ... ##########"); - - //for (int x=0; x <= HTTP.args(); x++) { - // DEBUG_PRINTLN(HTTP.arg(x)); - //} - - String request = server->arg(0); - DEBUG_PRINT("request:"); - DEBUG_PRINTLN(request); - - if(request.indexOf("1") > 0) { - DEBUG_PRINTLN("Got Turn on request"); - onCallback(); - } - - if(request.indexOf("0") > 0) { - DEBUG_PRINTLN("Got Turn off request"); - offCallback(); - } - - server->send(200, "text/plain", ""); -} - -void Switch::handleRoot(){ - server->send(200, "text/plain", "You should tell Alexa to discover devices"); -} - -void Switch::handleSetupXml(){ - DEBUG_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"; - - server->send(200, "text/xml", setup_xml.c_str()); - - DEBUG_PRINT("Sending :"); - DEBUG_PRINTLN(setup_xml); -} - -String Switch::getAlexaInvokeName() { - return device_name; -} - -void Switch::respondToSearch(IPAddress& senderIP, unsigned int senderPort) { - DEBUG_PRINTLN(""); - DEBUG_PRINT("Sending response to "); - DEBUG_PRINTLN(senderIP); - DEBUG_PRINT("Port : "); - DEBUG_PRINTLN(senderPort); - - 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: Sat, 26 Nov 2016 04:56:29 GMT\r\n" - "EXT:\r\n" - "LOCATION: http://" + String(s) + ":" + String(localPort) + "/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(senderIP, senderPort); - UDP.write(response.c_str()); - UDP.endPacket(); - - DEBUG_PRINTLN("Response sent !"); -} diff --git a/wled00/src/dependencies/alexa-multiple/Switch.h b/wled00/src/dependencies/alexa-multiple/Switch.h deleted file mode 100644 index ebe2039b..00000000 --- a/wled00/src/dependencies/alexa-multiple/Switch.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef SWITCH_H -#define SWITCH_H - -#include -#include -#include -#include -#include "CallbackFunction.h" - - -class Switch { -private: - ESP8266WebServer *server = NULL; - WiFiUDP UDP; - String serial; - String persistent_uuid; - String device_name; - unsigned int localPort; - CallbackFunction onCallback; - CallbackFunction offCallback; - - void startWebServer(); - void handleEventservice(); - void handleUpnpControl(); - void handleRoot(); - void handleSetupXml(); -public: - Switch(); - Switch(String alexaInvokeName, unsigned int port, CallbackFunction onCallback, CallbackFunction offCallback); - ~Switch(); - String getAlexaInvokeName(); - void serverLoop(); - void respondToSearch(IPAddress& senderIP, unsigned int senderPort); -}; - -#endif diff --git a/wled00/src/dependencies/alexa-multiple/UpnpBroadcastResponder.cpp b/wled00/src/dependencies/alexa-multiple/UpnpBroadcastResponder.cpp deleted file mode 100644 index 32eae5a1..00000000 --- a/wled00/src/dependencies/alexa-multiple/UpnpBroadcastResponder.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "UpnpBroadcastResponder.h" -#include "Switch.h" -#include - -//#define DEBUG - -#ifdef DEBUG - #define DEBUG_PRINT(x) Serial.print (x) - #define DEBUG_PRINTLN(x) Serial.println (x) - #define DEBUG_PRINTF(x) Serial.printf (x) -#else - #define DEBUG_PRINT(x) - #define DEBUG_PRINTLN(x) - #define DEBUG_PRINTF(x) -#endif - -// Multicast declarations -IPAddress ipMulti(239, 255, 255, 250); -const unsigned int portMulti = 1900; -char packetBuffer[512]; - -#define MAX_SWITCHES 14 -Switch switches[MAX_SWITCHES] = {}; -int numOfSwitchs = 0; - -//#define numOfSwitchs (sizeof(switches)/sizeof(Switch)) //array size - -//<> -UpnpBroadcastResponder::UpnpBroadcastResponder(){ - -} - -//<> -UpnpBroadcastResponder::~UpnpBroadcastResponder(){/*nothing to destruct*/} - -bool UpnpBroadcastResponder::beginUdpMulticast(){ - boolean state = false; - - DEBUG_PRINTLN("Begin multicast .."); - - if(UDP.beginMulticast(WiFi.localIP(), ipMulti, portMulti)) { - DEBUG_PRINT("Udp multicast server started at "); - DEBUG_PRINT(ipMulti); - DEBUG_PRINT(":"); - DEBUG_PRINTLN(portMulti); - - state = true; - } - else{ - DEBUG_PRINTLN("Connection failed"); - } - - return state; -} - -//Switch *ptrArray; - -void UpnpBroadcastResponder::addDevice(Switch& device) { - DEBUG_PRINT("Adding switch : "); - DEBUG_PRINT(device.getAlexaInvokeName()); - DEBUG_PRINT(" index : "); - DEBUG_PRINTLN(numOfSwitchs); - - switches[numOfSwitchs] = device; - numOfSwitchs++; -} - -void UpnpBroadcastResponder::serverLoop(){ - int packetSize = UDP.parsePacket(); - if (packetSize <= 0) - return; - - IPAddress senderIP = UDP.remoteIP(); - unsigned int senderPort = UDP.remotePort(); - - // read the packet into the buffer - UDP.read(packetBuffer, packetSize); - - // check if this is a M-SEARCH for WeMo device - String request = String((char *)packetBuffer); - - if(request.indexOf('M-SEARCH') > 0) { - if(request.indexOf("urn:Belkin:device:**") > 0) { - DEBUG_PRINTLN("Got UDP Belkin Request.."); - - // int arrSize = sizeof(switchs) / sizeof(Switch); - - for(int n = 0; n < numOfSwitchs; n++) { - Switch &sw = switches[n]; - - if (&sw != NULL) { - sw.respondToSearch(senderIP, senderPort); - } - } - } - } -} - diff --git a/wled00/src/dependencies/alexa-multiple/UpnpBroadcastResponder.h b/wled00/src/dependencies/alexa-multiple/UpnpBroadcastResponder.h deleted file mode 100644 index b8c80397..00000000 --- a/wled00/src/dependencies/alexa-multiple/UpnpBroadcastResponder.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef UPNPBROADCASTRESPONDER_H -#define UPNPBROADCASTRESPONDER_H - -#include -#include -#include -#include "Switch.h" - -class UpnpBroadcastResponder { -private: - WiFiUDP UDP; -public: - UpnpBroadcastResponder(); - ~UpnpBroadcastResponder(); - bool beginUdpMulticast(); - void serverLoop(); - void addDevice(Switch& device); -}; - -#endif diff --git a/wled00/wled00.ino b/wled00/wled00.ino index be3e35cb..2af260b3 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -17,15 +17,12 @@ #include "src/dependencies/time/Time.h" #include "src/dependencies/time/TimeLib.h" #include "src/dependencies/timezone/Timezone.h" -#include "src/dependencies/alexa-multiple/switch.h" -#include "src/dependencies/alexa-multiple/UpnpBroadcastResponder.h" -#include "src/dependencies/alexa-multiple/CallbackFunction.h" #include "htmls00.h" #include "htmls01.h" #include "WS2812FX.h" //version in format yymmddb (b = daily build) -#define VERSION 1712300 +#define VERSION 1712310 //AP and OTA default passwords (change them!) String appass = "wled1234"; @@ -34,10 +31,10 @@ String otapass = "wledota"; //If you have an RGBW strip, uncomment first line in WS2812FX.h! //overlays, needed for clocks etc. -//#define USEOVERLAYS +#define USEOVERLAYS //support for the CRONIXIE clock by Diamex (disable overlays!) -#define CRONIXIE +//#define CRONIXIE //spiffs FS only useful for debug //#define USEFS @@ -217,8 +214,12 @@ boolean useGammaCorrectionRGB = true; int arlsOffset = -22; //10: -22 assuming arls52 //alexa -Switch *alexa = NULL; -UpnpBroadcastResponder upnpBroadcastResponder; +WiFiUDP UDP; +IPAddress ipMulti(239, 255, 255, 250); +unsigned int portMulti = 1900; +unsigned int localPort = 1900; +char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; +String escapedMac; ESP8266WebServer server(80); ESP8266HTTPUpdateServer httpUpdater; diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino index ace3bd4e..df3db00b 100644 --- a/wled00/wled05_init.ino +++ b/wled00/wled05_init.ino @@ -160,6 +160,7 @@ void wledInit() server.send(404, "text/plain", "FileNotFound"); } }); + alexaInit(); server.begin(); DEBUG_PRINTLN("HTTP server started"); diff --git a/wled00/wled07_notify.ino b/wled00/wled07_notify.ino index 11f448ce..adf6ff8d 100644 --- a/wled00/wled07_notify.ino +++ b/wled00/wled07_notify.ino @@ -46,7 +46,7 @@ void handleNotifications() if(packetSize && notifierUdp.remoteIP() != WiFi.localIP()) { notifierUdp.read(udpIn, packetSize); - if (udpIn[0] == 0) //wled notifier + if (udpIn[0] == 0 && !arlsTimeout) //wled notifier, block if realtime packets active { col[0] = udpIn[3]; col[1] = udpIn[4]; diff --git a/wled00/wled12_alexa.ino b/wled00/wled12_alexa.ino index 1aac3530..907cc79c 100644 --- a/wled00/wled12_alexa.ino +++ b/wled00/wled12_alexa.ino @@ -6,9 +6,11 @@ void alexaInit() { if (alexaEnabled && WiFi.status() == WL_CONNECTED) { - upnpBroadcastResponder.beginUdpMulticast(); - alexa = new Switch(alexaInvocationName, 81, alexaOn, alexaOff); - upnpBroadcastResponder.addDevice(*alexa); + prepareIds(); + + udpConnected = connectUDP(); + + if (udpConnected) alexaInitPages(); } } @@ -16,8 +18,25 @@ void handleAlexa() { if (alexaEnabled && WiFi.status() == WL_CONNECTED) { - upnpBroadcastResponder.serverLoop(); - alexa->serverLoop(); + if(udpConnected){ + // if there’s data available, read a packet + int packetSize = UDP.parsePacket(); + if(packetSize) { + IPAddress remote = UDP.remoteIP(); + int len = UDP.read(packetBuffer, 255); + if (len > 0) { + packetBuffer[len] = 0; + } + String request = packetBuffer; + + if(request.indexOf("M-SEARCH") >= 0) { + if((request.indexOf("urn:Belkin:device:**") > 0) || (request.indexOf("ssdp:all") > 0) || (request.indexOf("upnp:rootdevice") > 0)) { + Serial.println("Responding to search request ..."); + respondToSearch(); + } + } + } + } } } @@ -30,6 +49,18 @@ void alexaOn() { applyMacro(alexaOnMacro); } + + String body = + "\r\n" + "\r\n" + "1\r\n" + "\r\n" + " "; + + server.send(200, "text/xml", body.c_str()); + + Serial.print("Sending :"); + Serial.println(body); } void alexaOff() @@ -41,6 +72,18 @@ void alexaOff() { applyMacro(alexaOffMacro); } + + String body = + "\r\n" + "\r\n" + "0\r\n" + "\r\n" + " "; + + server.send(200, "text/xml", body.c_str()); + + Serial.print("Sending :"); + Serial.println(body); } void alexaDim(uint8_t bri) @@ -50,3 +93,219 @@ void alexaDim(uint8_t bri) handleSet(ct); } +void prepareIds() { + escapedMac = WiFi.macAddress(); + escapedMac.replace(":", ""); + escapedMac.toLowerCase(); +} + +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" + "EXT:\r\n" + "CACHE-CONTROL: max-age=%u\r\n" // SSDP_INTERVAL + "LOCATION: http://"+ String(s) +":80/description.xml\r\n" + "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.17.0\r\n" // _modelName, _modelNumber + "hue-bridgeid: "+ escapedMac +"\r\n" + "ST: urn:schemas-upnp-org:device:basic:1\r\n" // _deviceType + "USN: uuid:2f402f80-da50-11e1-9b23-"+ escapedMac +"::upnp:rootdevice\r\n" // _uuid::_deviceType + "\r\n"; + + UDP.beginPacket(UDP.remoteIP(), UDP.remotePort()); + UDP.write(response.c_str()); + UDP.endPacket(); + + Serial.println("Response sent !"); +} + +void alexaInitPages() { + server.on("/upnp/control/basicevent1", HTTP_POST, []() { + Serial.println("########## Responding to /upnp/control/basicevent1 ... ##########"); + + String request = server.arg(0); + Serial.print("request:"); + Serial.println(request); + + if(request.indexOf("SetBinaryState") >= 0) { + if(request.indexOf("1") >= 0) { + Serial.println("Got Turn on request"); + alexaOn(); + } + + if(request.indexOf("0") >= 0) { + Serial.println("Got Turn off request"); + alexaOff(); + } + } + + if(request.indexOf("GetBinaryState") >= 0) { + Serial.println("Got binary state request"); + sendState(); + } + + server.send(200, "text/plain", ""); + }); + + server.on("/eventservice.xml", HTTP_GET, [](){ + Serial.println(" ########## Responding to eventservice.xml ... ########\n"); + + String eventservice_xml = "" + "" + "" + "SetBinaryState" + "" + "" + "" + "BinaryState" + "BinaryState" + "in" + "" + "" + "" + "" + "GetBinaryState" + "" + "" + "" + "BinaryState" + "BinaryState" + "out" + "" + "" + "" + "" + "" + "" + "BinaryState" + "Boolean" + "0" + "" + "" + "level" + "string" + "0" + "" + "" + "\r\n" + "\r\n"; + + server.send(200, "text/plain", eventservice_xml.c_str()); + }); + + server.on("/description.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 = "" + "" + "10" + "http://"+ String(s) +":80/" + "" + "urn:schemas-upnp-org:device:Basic:1" + "Philips hue ("+ String(s) +")" + "Royal Philips Electronics" + "http://www.philips.com" + "Philips hue Personal Wireless Lighting" + "Philips hue bridge 2012" + "929000226503" + "http://www.meethue.com" + ""+ escapedMac +"" + "uuid:2f402f80-da50-11e1-9b23-"+ escapedMac +"" + "index.html" + "" + " " + " image/png" + " 48" + " 48" + " 24" + " hue_logo_0.png" + " " + " " + " image/png" + " 120" + " 120" + " 24" + " hue_logo_3.png" + " " + "" + "" + ""; + + server.send(200, "text/xml", setup_xml.c_str()); + + Serial.print("Sending :"); + Serial.println(setup_xml); + }); + + // openHAB support + server.on("/on.html", HTTP_GET, [](){ + Serial.println("on req"); + server.send(200, "text/plain", "turned on"); + alexaOn(); + }); + + server.on("/off.html", HTTP_GET, [](){ + Serial.println("off req"); + server.send(200, "text/plain", "turned off"); + alexaOff(); + }); + + server.on("/status.html", HTTP_GET, [](){ + Serial.println("Got status request"); + + String statrespone = "0"; + if (bri > 0) { + statrespone = "1"; + } + server.send(200, "text/plain", statrespone); + + }); +} + + +boolean connectUDP(){ + boolean state = false; + + Serial.println(""); + Serial.println("Con UDP"); + + if(UDP.beginMulticast(WiFi.localIP(), ipMulti, portMulti)) { + Serial.println("Con success"); + state = true; + } + else{ + Serial.println("Con failed"); + } + + return state; +} + +void sendState() { + + String body = + "\r\n" + "\r\n" + ""; + + body += ((bri>0) ? "1" : "0"); + + body += "\r\n" + "\r\n" + " \r\n"; + + server.send(200, "text/xml", body.c_str()); +} +