Fixed Alexa discovery

This commit is contained in:
cschwinne 2020-12-16 22:55:07 +01:00
parent c9cd7b087a
commit c277ebb43e
3 changed files with 52 additions and 40 deletions

View File

@ -2,6 +2,10 @@
### Development versions after 0.11.0 release ### 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 #### Build 2012150
- Added Blends FX (PR #1491) - Added Blends FX (PR #1491)

View File

@ -10,7 +10,7 @@
*/ */
/* /*
* @title Espalexa library * @title Espalexa library
* @version 2.4.6 * @version 2.5.0
* @author Christian Schwinne * @author Christian Schwinne
* @license MIT * @license MIT
* @contributors d-999 * @contributors d-999
@ -50,7 +50,7 @@
#include "../network/Network.h" #include "../network/Network.h"
#ifdef ESPALEXA_DEBUG #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_DEBUG(x) Serial.print (x)
#define EA_DEBUGLN(x) Serial.println (x) #define EA_DEBUGLN(x) Serial.println (x)
#else #else
@ -60,6 +60,7 @@
#include "EspalexaDevice.h" #include "EspalexaDevice.h"
#define DEVICE_UNIQUE_ID_LENGTH 12
class Espalexa { class Espalexa {
private: private:
@ -116,17 +117,24 @@ private:
return ""; return "";
} }
//Workaround functions courtesy of Sonoff-Tasmota void encodeLightId(uint8_t idx, char* out)
uint32_t encodeLightId(uint8_t idx)
{ {
//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]; uint8_t mac[6];
WiFi.macAddress(mac); 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) { //shift the mac address to the left (discard first byte)
return id & 0xF; 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) //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 if (deviceId >= currentDeviceCount) {strcpy(buf,"{}"); return;} //error
EspalexaDevice* dev = devices[deviceId]; EspalexaDevice* dev = devices[deviceId];
//char buf_bri[12] = ""; char buf_lightid[13];
//brightness support, add "bri" to JSON encodeLightId(deviceId + 1, buf_lightid);
//if (dev->getType() != EspalexaDeviceType::onoff)
// sprintf(buf_bri,",\"bri\":%u", dev->getLastValue()-1);
char buf_col[80] = ""; char buf_col[80] = "";
//color support //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}," 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" "\"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->getValue())?"true":"false", dev->getLastValue()-1, buf_col, buf_ct, buf_cm, typeString(dev->getType()),
dev->getName().c_str(), modelidString(dev->getType()), static_cast<uint8_t>(dev->getType()), encodeLightId(deviceId+1)); dev->getName().c_str(), modelidString(dev->getType()), static_cast<uint8_t>(dev->getType()), buf_lightid);
} }
//Espalexa status page /espalexa //Espalexa status page /espalexa
@ -186,7 +192,7 @@ private:
} }
res += "\r\nFree Heap: " + (String)ESP.getFreeHeap(); res += "\r\nFree Heap: " + (String)ESP.getFreeHeap();
res += "\r\nUptime: " + (String)millis(); 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); server->send(200, "text/plain", res);
} }
#endif #endif
@ -222,7 +228,7 @@ private:
"<URLBase>http://%s:80/</URLBase>" "<URLBase>http://%s:80/</URLBase>"
"<device>" "<device>"
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>" "<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>"
"<friendlyName>Espalexa (%s)</friendlyName>" "<friendlyName>Espalexa (%s:80)</friendlyName>"
"<manufacturer>Royal Philips Electronics</manufacturer>" "<manufacturer>Royal Philips Electronics</manufacturer>"
"<manufacturerURL>http://www.philips.com</manufacturerURL>" "<manufacturerURL>http://www.philips.com</manufacturerURL>"
"<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>" "<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>"
@ -237,8 +243,8 @@ private:
server->send(200, "text/xml", buf); server->send(200, "text/xml", buf);
EA_DEBUG("Send setup.xml"); EA_DEBUGLN("Send setup.xml");
//EA_DEBUGLN(setup_xml); EA_DEBUGLN(buf);
} }
//init the server //init the server
@ -298,7 +304,7 @@ private:
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.17.0\r\n" // _modelName, _modelNumber "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.17.0\r\n" // _modelName, _modelNumber
"hue-bridgeid: %s\r\n" "hue-bridgeid: %s\r\n"
"ST: urn:schemas-upnp-org:device:basic:1\r\n" // _deviceType "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()); "\r\n"),s,escapedMac.c_str(),escapedMac.c_str());
espalexaUdp.beginPacket(espalexaUdp.remoteIP(), espalexaUdp.remotePort()); espalexaUdp.beginPacket(espalexaUdp.remoteIP(), espalexaUdp.remotePort());
@ -359,24 +365,28 @@ public:
if (!udpConnected) return; if (!udpConnected) return;
int packetSize = espalexaUdp.parsePacket(); int packetSize = espalexaUdp.parsePacket();
if (!packetSize) return; //no new udp packet if (packetSize < 1) return; //no new udp packet
EA_DEBUGLN("Got UDP!"); EA_DEBUGLN("Got UDP!");
char packetBuffer[255]; //buffer to hold incoming udp packet
uint16_t len = espalexaUdp.read(packetBuffer, 254); unsigned char packetBuffer[packetSize+1]; //buffer to hold incoming udp packet
if (len > 0) { espalexaUdp.read(packetBuffer, packetSize);
packetBuffer[len] = 0; packetBuffer[packetSize] = 0;
}
espalexaUdp.flush(); espalexaUdp.flush();
if (!discoverable) return; //do not reply to M-SEARCH if not discoverable if (!discoverable) return; //do not reply to M-SEARCH if not discoverable
String request = packetBuffer; const char* request = (const char *) packetBuffer;
if(request.indexOf("M-SEARCH") >= 0) { if (strstr(request, "M-SEARCH") == nullptr) return;
EA_DEBUGLN(request);
if(request.indexOf("upnp:rootdevice") > 0 || request.indexOf("asic:1") > 0 || request.indexOf("ssdp:all") > 0) { EA_DEBUGLN(request);
EA_DEBUGLN("Responding search req..."); if (strstr(request, "ssdp:disc") != nullptr && //short for "ssdp:discover"
respondToSearch(); (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; 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}}]")); server->send(200, "application/json", F("[{\"success\":{\"/lights/1/state/\": true}}]"));
uint32_t devId = req.substring(req.indexOf("lights")+7).toInt(); uint32_t devId = req.substring(req.indexOf("lights")+7).toInt();
EA_DEBUG("ls"); EA_DEBUGLN(devId); EA_DEBUG("ls"); EA_DEBUGLN(devId);
devId = decodeLightId(devId);
EA_DEBUGLN(devId); EA_DEBUGLN(devId);
devId--; //zero-based for devices array devId--; //zero-based for devices array
if (devId >= currentDeviceCount) return true; //return if invalid ID if (devId >= currentDeviceCount) return true; //return if invalid ID
@ -530,7 +539,7 @@ public:
String jsonTemp = "{"; String jsonTemp = "{";
for (int i = 0; i<currentDeviceCount; i++) for (int i = 0; i<currentDeviceCount; i++)
{ {
jsonTemp += "\"" + String(encodeLightId(i+1)) + "\":"; jsonTemp += "\"" + String(i+1) + "\":";
char buf[512]; char buf[512];
deviceJsonString(i+1, buf); deviceJsonString(i+1, buf);
jsonTemp += buf; jsonTemp += buf;
@ -540,7 +549,6 @@ public:
server->send(200, "application/json", jsonTemp); server->send(200, "application/json", jsonTemp);
} else //client wants one light (devId) } else //client wants one light (devId)
{ {
devId = decodeLightId(devId);
EA_DEBUGLN(devId); EA_DEBUGLN(devId);
if (devId > currentDeviceCount) if (devId > currentDeviceCount)
{ {

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // 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 //uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG //#define WLED_USE_MY_CONFIG