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
#### Build 2012160
- Bump Espalexa to 2.5.0, fixing discovery (PR Espalexa/#152, originally PR #1497)
#### Build 2012150
- Added Blends FX (PR #1491)

View File

@ -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<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
@ -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:
"<URLBase>http://%s:80/</URLBase>"
"<device>"
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>"
"<friendlyName>Espalexa (%s)</friendlyName>"
"<friendlyName>Espalexa (%s:80)</friendlyName>"
"<manufacturer>Royal Philips Electronics</manufacturer>"
"<manufacturerURL>http://www.philips.com</manufacturerURL>"
"<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>"
@ -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; i<currentDeviceCount; i++)
{
jsonTemp += "\"" + String(encodeLightId(i+1)) + "\":";
jsonTemp += "\"" + String(i+1) + "\":";
char buf[512];
deviceJsonString(i+1, buf);
jsonTemp += buf;
@ -540,7 +549,6 @@ public:
server->send(200, "application/json", jsonTemp);
} else //client wants one light (devId)
{
devId = decodeLightId(devId);
EA_DEBUGLN(devId);
if (devId > currentDeviceCount)
{

View File

@ -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