From c277ebb43e907196e692d6fec0d06a3018961062 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Wed, 16 Dec 2020 22:55:07 +0100 Subject: [PATCH] Fixed Alexa discovery --- CHANGELOG.md | 4 + wled00/src/dependencies/espalexa/Espalexa.h | 86 +++++++++++---------- wled00/wled.h | 2 +- 3 files changed, 52 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55503660..c44923cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ### Development versions after 0.11.0 release +#### Build 2012160 + +- Bump Espalexa to 2.5.0, fixing discovery (PR Espalexa/#152, originally PR #1497) + #### Build 2012150 - Added Blends FX (PR #1491) diff --git a/wled00/src/dependencies/espalexa/Espalexa.h b/wled00/src/dependencies/espalexa/Espalexa.h index b0962c49..0ec4e2e5 100644 --- a/wled00/src/dependencies/espalexa/Espalexa.h +++ b/wled00/src/dependencies/espalexa/Espalexa.h @@ -10,7 +10,7 @@ */ /* * @title Espalexa library - * @version 2.4.6 + * @version 2.5.0 * @author Christian Schwinne * @license MIT * @contributors d-999 @@ -50,7 +50,7 @@ #include "../network/Network.h" #ifdef ESPALEXA_DEBUG - #pragma message "Espalexa 2.4.6 debug mode" + #pragma message "Espalexa 2.5.0 debug mode" #define EA_DEBUG(x) Serial.print (x) #define EA_DEBUGLN(x) Serial.println (x) #else @@ -60,6 +60,7 @@ #include "EspalexaDevice.h" +#define DEVICE_UNIQUE_ID_LENGTH 12 class Espalexa { private: @@ -116,17 +117,24 @@ private: return ""; } - //Workaround functions courtesy of Sonoff-Tasmota - uint32_t encodeLightId(uint8_t idx) + void encodeLightId(uint8_t idx, char* out) { + //Unique id must be 12 character len + //use the last 10 characters of the MAC followed by the device id in hex value + //uniqueId: aabbccddeeii + uint8_t mac[6]; WiFi.macAddress(mac); - uint32_t id = (mac[3] << 20) | (mac[4] << 12) | (mac[5] << 4) | (idx & 0xF); - return id; - } - uint32_t decodeLightId(uint32_t id) { - return id & 0xF; + //shift the mac address to the left (discard first byte) + for (uint8_t i = 0; i < 5; i++) { + mac[i] = mac[i+1]; + } + mac[5] = idx; + + for (uint8_t i = 0; i < 6; i++) { + sprintf(out + i*2, "%.2x", mac[i]); + } } //device JSON string: color+temperature device emulates LCT015, dimmable device LWB010, (TODO: on/off Plug 01, color temperature device LWT010, color device LST001) @@ -136,10 +144,8 @@ private: if (deviceId >= currentDeviceCount) {strcpy(buf,"{}"); return;} //error EspalexaDevice* dev = devices[deviceId]; - //char buf_bri[12] = ""; - //brightness support, add "bri" to JSON - //if (dev->getType() != EspalexaDeviceType::onoff) - // sprintf(buf_bri,",\"bri\":%u", dev->getLastValue()-1); + char buf_lightid[13]; + encodeLightId(deviceId + 1, buf_lightid); char buf_col[80] = ""; //color support @@ -161,10 +167,10 @@ private: sprintf_P(buf, PSTR("{\"state\":{\"on\":%s,\"bri\":%u%s%s,\"alert\":\"none%s\",\"mode\":\"homeautomation\",\"reachable\":true}," "\"type\":\"%s\",\"name\":\"%s\",\"modelid\":\"%s\",\"manufacturername\":\"Philips\",\"productname\":\"E%u" - "\",\"uniqueid\":\"%u\",\"swversion\":\"espalexa-2.4.6\"}") + "\",\"uniqueid\":\"%s\",\"swversion\":\"espalexa-2.5.0\"}") , (dev->getValue())?"true":"false", dev->getLastValue()-1, buf_col, buf_ct, buf_cm, typeString(dev->getType()), - dev->getName().c_str(), modelidString(dev->getType()), static_cast(dev->getType()), encodeLightId(deviceId+1)); + dev->getName().c_str(), modelidString(dev->getType()), static_cast(dev->getType()), buf_lightid); } //Espalexa status page /espalexa @@ -186,7 +192,7 @@ private: } res += "\r\nFree Heap: " + (String)ESP.getFreeHeap(); res += "\r\nUptime: " + (String)millis(); - res += "\r\n\r\nEspalexa library v2.4.6 by Christian Schwinne 2020"; + res += "\r\n\r\nEspalexa library v2.5.0 by Christian Schwinne 2020"; server->send(200, "text/plain", res); } #endif @@ -222,7 +228,7 @@ private: "http://%s:80/" "" "urn:schemas-upnp-org:device:Basic:1" - "Espalexa (%s)" + "Espalexa (%s:80)" "Royal Philips Electronics" "http://www.philips.com" "Philips hue Personal Wireless Lighting" @@ -237,8 +243,8 @@ private: server->send(200, "text/xml", buf); - EA_DEBUG("Send setup.xml"); - //EA_DEBUGLN(setup_xml); + EA_DEBUGLN("Send setup.xml"); + EA_DEBUGLN(buf); } //init the server @@ -290,7 +296,7 @@ private: sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]); char buf[1024]; - + sprintf_P(buf,PSTR("HTTP/1.1 200 OK\r\n" "EXT:\r\n" "CACHE-CONTROL: max-age=100\r\n" // SSDP_INTERVAL @@ -298,7 +304,7 @@ private: "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.17.0\r\n" // _modelName, _modelNumber "hue-bridgeid: %s\r\n" "ST: urn:schemas-upnp-org:device:basic:1\r\n" // _deviceType - "USN: uuid:2f402f80-da50-11e1-9b23-%s::ssdp:all\r\n" // _uuid::_deviceType + "USN: uuid:2f402f80-da50-11e1-9b23-%s::upnp:rootdevice\r\n" // _uuid::_deviceType "\r\n"),s,escapedMac.c_str(),escapedMac.c_str()); espalexaUdp.beginPacket(espalexaUdp.remoteIP(), espalexaUdp.remotePort()); @@ -359,24 +365,28 @@ public: if (!udpConnected) return; int packetSize = espalexaUdp.parsePacket(); - if (!packetSize) return; //no new udp packet + if (packetSize < 1) return; //no new udp packet EA_DEBUGLN("Got UDP!"); - char packetBuffer[255]; //buffer to hold incoming udp packet - uint16_t len = espalexaUdp.read(packetBuffer, 254); - if (len > 0) { - packetBuffer[len] = 0; - } + + unsigned char packetBuffer[packetSize+1]; //buffer to hold incoming udp packet + espalexaUdp.read(packetBuffer, packetSize); + packetBuffer[packetSize] = 0; + espalexaUdp.flush(); if (!discoverable) return; //do not reply to M-SEARCH if not discoverable - - String request = packetBuffer; - if(request.indexOf("M-SEARCH") >= 0) { - EA_DEBUGLN(request); - if(request.indexOf("upnp:rootdevice") > 0 || request.indexOf("asic:1") > 0 || request.indexOf("ssdp:all") > 0) { - EA_DEBUGLN("Responding search req..."); - respondToSearch(); - } + + const char* request = (const char *) packetBuffer; + if (strstr(request, "M-SEARCH") == nullptr) return; + + EA_DEBUGLN(request); + if (strstr(request, "ssdp:disc") != nullptr && //short for "ssdp:discover" + (strstr(request, "upnp:rootd") != nullptr || //short for "upnp:rootdevice" + strstr(request, "ssdp:all") != nullptr || + strstr(request, "asic:1") != nullptr )) //short for "device:basic:1" + { + EA_DEBUGLN("Responding search req..."); + respondToSearch(); } } @@ -452,13 +462,12 @@ public: return true; } - if (req.indexOf("state") > 0) //client wants to control light + if ((req.indexOf("state") > 0) && (body.length() > 0)) //client wants to control light { server->send(200, "application/json", F("[{\"success\":{\"/lights/1/state/\": true}}]")); uint32_t devId = req.substring(req.indexOf("lights")+7).toInt(); EA_DEBUG("ls"); EA_DEBUGLN(devId); - devId = decodeLightId(devId); EA_DEBUGLN(devId); devId--; //zero-based for devices array if (devId >= currentDeviceCount) return true; //return if invalid ID @@ -530,7 +539,7 @@ public: String jsonTemp = "{"; for (int i = 0; isend(200, "application/json", jsonTemp); } else //client wants one light (devId) { - devId = decodeLightId(devId); EA_DEBUGLN(devId); if (devId > currentDeviceCount) { diff --git a/wled00/wled.h b/wled00/wled.h index bd4de87f..793dfc31 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2012150 +#define VERSION 2012160 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG