diff --git a/platformio.ini b/platformio.ini
index 015894a7..3cad5ee1 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -27,7 +27,7 @@ lib_deps_external =
#E131@1.0.0
#webserver
FastLED@3.2.1
- NeoPixelBus@2.3.4
+ NeoPixelBus@2.4.1
#PubSubClient@2.7
#Time@1.5
#Timezone@1.2.1
diff --git a/readme.md b/readme.md
index 84381af0..4fe717ac 100644
--- a/readme.md
+++ b/readme.md
@@ -1,6 +1,6 @@
![WLED logo](https://raw.githubusercontent.com/Aircoookie/WLED/master/wled_logo.png)
-## Welcome to my project WLED! (v0.8.2)
+## Welcome to my project WLED! (v0.8.3-dev)
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B) LEDs!
@@ -25,7 +25,7 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control
- E1.31
- Hyperion
- UDP realtime
-- Alexa smart device (including dimming)
+- Alexa voice control (including dimming and color)
- Sync to Philips hue lights
- Adalight (PC ambilight via serial)
- Sync color of multiple WLED devices (UDP notifier)
diff --git a/wled00/NpbWrapper.h b/wled00/NpbWrapper.h
index c33c869c..92ce1007 100644
--- a/wled00/NpbWrapper.h
+++ b/wled00/NpbWrapper.h
@@ -24,7 +24,7 @@
#else //esp8266
//autoselect the right method depending on strip pin
#if LEDPIN == 2
- #define PIXELMETHOD NeoEsp8266Uart800KbpsMethod
+ #define PIXELMETHOD NeoEsp8266Uart1Ws2813Method //if you get an error here, please update to Neopixelbus v2.4.0+
#elif LEDPIN == 3
#define PIXELMETHOD NeoEsp8266Dma800KbpsMethod
#else
diff --git a/wled00/WS2812FX.cpp b/wled00/WS2812FX.cpp
index 1ec2d251..9857876b 100644
--- a/wled00/WS2812FX.cpp
+++ b/wled00/WS2812FX.cpp
@@ -42,6 +42,9 @@
#include "WS2812FX.h"
#include "palettes.h"
+
+#define LED_SKIP_AMOUNT 1
+
void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst)
{
if (supportWhite == _rgbwMode && countPixels == _length && _locked != NULL) return;
@@ -49,14 +52,19 @@ void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst)
_rgbwMode = supportWhite;
_skipFirstMode = skipFirst;
_length = countPixels;
- if (_skipFirstMode) _length++;
+
uint8_t ty = 1;
if (supportWhite) ty =2;
- bus->Begin((NeoPixelType)ty, _length);
+ uint16_t lengthRaw = _length;
+ if (_skipFirstMode) lengthRaw += LED_SKIP_AMOUNT;
+ bus->Begin((NeoPixelType)ty, lengthRaw);
+
if (_locked != NULL) delete _locked;
_locked = new byte[_length];
+
_segments[0].start = 0;
_segments[0].stop = _length -1;
+
unlockAll();
setBrightness(_brightness);
_running = true;
@@ -119,7 +127,12 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
}
if (!_cronixieMode)
{
- if (_skipFirstMode) {i++;if(i==1)bus->SetPixelColor(i, RgbwColor(0,0,0,0));}
+ if (_skipFirstMode)
+ {
+ if (i < LED_SKIP_AMOUNT) bus->SetPixelColor(i, RgbwColor(0,0,0,0));
+ i += LED_SKIP_AMOUNT;
+ }
+
bus->SetPixelColor(i, RgbwColor(r,g,b,w));
} else {
if(i>6)return;
@@ -132,27 +145,28 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
byte w2 = (_segments[0].colors[1] >>24) & 0xFF;
for (int j=o; j< o+19; j++)
{
- bus->SetPixelColor((_skipFirstMode)?j+1:j,RgbwColor(r2,g2,b2,w2));
+ bus->SetPixelColor(j, RgbwColor(r2,g2,b2,w2));
}
} else
{
for (int j=o; j< o+19; j++)
{
- bus->SetPixelColor((_skipFirstMode)?j+1:j,RgbwColor(0,0,0,0));
+ bus->SetPixelColor(j, RgbwColor(0,0,0,0));
}
}
+ if (_skipFirstMode) o += LED_SKIP_AMOUNT;
switch(_cronixieDigits[i])
{
- case 0: bus->SetPixelColor((_skipFirstMode)?o+6:o+5,RgbwColor(r,g,b,w)); break;
- case 1: bus->SetPixelColor((_skipFirstMode)?o+1:o+0,RgbwColor(r,g,b,w)); break;
- case 2: bus->SetPixelColor((_skipFirstMode)?o+7:o+6,RgbwColor(r,g,b,w)); break;
- case 3: bus->SetPixelColor((_skipFirstMode)?o+2:o+1,RgbwColor(r,g,b,w)); break;
- case 4: bus->SetPixelColor((_skipFirstMode)?o+8:o+7,RgbwColor(r,g,b,w)); break;
- case 5: bus->SetPixelColor((_skipFirstMode)?o+3:o+2,RgbwColor(r,g,b,w)); break;
- case 6: bus->SetPixelColor((_skipFirstMode)?o+9:o+8,RgbwColor(r,g,b,w)); break;
- case 7: bus->SetPixelColor((_skipFirstMode)?o+4:o+3,RgbwColor(r,g,b,w)); break;
- case 8: bus->SetPixelColor((_skipFirstMode)?o+10:o+9,RgbwColor(r,g,b,w)); break;
- case 9: bus->SetPixelColor((_skipFirstMode)?o+5:o+4,RgbwColor(r,g,b,w)); break;
+ case 0: bus->SetPixelColor(o+5, RgbwColor(r,g,b,w)); break;
+ case 1: bus->SetPixelColor(o+0, RgbwColor(r,g,b,w)); break;
+ case 2: bus->SetPixelColor(o+6, RgbwColor(r,g,b,w)); break;
+ case 3: bus->SetPixelColor(o+1, RgbwColor(r,g,b,w)); break;
+ case 4: bus->SetPixelColor(o+7, RgbwColor(r,g,b,w)); break;
+ case 5: bus->SetPixelColor(o+2, RgbwColor(r,g,b,w)); break;
+ case 6: bus->SetPixelColor(o+8, RgbwColor(r,g,b,w)); break;
+ case 7: bus->SetPixelColor(o+3, RgbwColor(r,g,b,w)); break;
+ case 8: bus->SetPixelColor(o+9, RgbwColor(r,g,b,w)); break;
+ case 9: bus->SetPixelColor(o+4, RgbwColor(r,g,b,w)); break;
}
}
}
@@ -340,7 +354,7 @@ uint32_t WS2812FX::getColor(void) {
uint32_t WS2812FX::getPixelColor(uint16_t i)
{
if (_reverseMode) i = _length- 1 -i;
- if (_skipFirstMode) i++;
+ if (_skipFirstMode) i += LED_SKIP_AMOUNT;
if (_cronixieMode)
{
if(i>6)return 0;
diff --git a/wled00/html_settings.h b/wled00/html_settings.h
index a83552d4..e79a29f4 100644
--- a/wled00/html_settings.h
+++ b/wled00/html_settings.h
@@ -437,7 +437,7 @@ HTTP traffic is unencrypted. An attacker in the same network can intercept form
Enable ArduinoOTA:
About
-WLED version 0.8.2
+WLED version 0.8.3
Contributors, dependencies and special thanks
A huge thank you to everyone who helped me create WLED!
(c) 2016-2018 Christian Schwinne
diff --git a/wled00/src/dependencies/espalexa/Espalexa.h b/wled00/src/dependencies/espalexa/Espalexa.h
new file mode 100644
index 00000000..3b817415
--- /dev/null
+++ b/wled00/src/dependencies/espalexa/Espalexa.h
@@ -0,0 +1,486 @@
+#ifndef Espalexa_h
+#define Espalexa_h
+
+/*
+ * Alexa Voice On/Off/Brightness/Color Control. Emulates a Philips Hue bridge to Alexa.
+ *
+ * This was put together from these two excellent projects:
+ * https://github.com/kakopappa/arduino-esp8266-alexa-wemo-switch
+ * https://github.com/probonopd/ESP8266HueEmulator
+ */
+/*
+ * @title Espalexa library
+ * @version 2.3.3
+ * @author Christian Schwinne
+ * @license MIT
+ * @contributors d-999
+ */
+
+#include "Arduino.h"
+
+//you can use these defines for library config in your sketch. Just use them before #include
+//#define ESPALEXA_ASYNC
+
+#ifndef ESPALEXA_MAXDEVICES
+ #define ESPALEXA_MAXDEVICES 10 //this limit only has memory reasons, set it higher should you need to
+#endif
+
+//#define ESPALEXA_DEBUG
+
+#ifdef ESPALEXA_ASYNC
+ #ifdef ARDUINO_ARCH_ESP32
+ #include
+ #else
+ #include
+ #endif
+ #include
+#else
+ #ifdef ARDUINO_ARCH_ESP32
+ #include
+ #include //if you get an error here please update to ESP32 arduino core 1.0.0
+ #else
+ #include
+ #include
+ #endif
+#endif
+#include
+
+#ifdef ESPALEXA_DEBUG
+ #pragma message "Espalexa 2.3.3 debug mode"
+ #define EA_DEBUG(x) Serial.print (x)
+ #define EA_DEBUGLN(x) Serial.println (x)
+#else
+ #define EA_DEBUG(x)
+ #define EA_DEBUGLN(x)
+#endif
+
+#include "EspalexaDevice.h"
+
+class Espalexa {
+private:
+ //private member vars
+ #ifdef ESPALEXA_ASYNC
+ AsyncWebServer* serverAsync;
+ AsyncWebServerRequest* server; //this saves many #defines
+ String body = "";
+ #elif defined ARDUINO_ARCH_ESP32
+ WebServer* server;
+ #else
+ ESP8266WebServer* server;
+ #endif
+ uint8_t currentDeviceCount = 0;
+
+ EspalexaDevice* devices[ESPALEXA_MAXDEVICES] = {};
+ //Keep in mind that Device IDs go from 1 to DEVICES, cpp arrays from 0 to DEVICES-1!!
+
+ WiFiUDP espalexaUdp;
+ IPAddress ipMulti;
+ bool udpConnected = false;
+ char packetBuffer[255]; //buffer to hold incoming udp packet
+ String escapedMac=""; //lowercase mac address
+
+ //private member functions
+ String deviceJsonString(uint8_t deviceId)
+ {
+ if (deviceId < 1 || deviceId > currentDeviceCount) return "{}"; //error
+ EspalexaDevice* dev = devices[deviceId-1];
+ String json = "{\"type\":\"";
+ json += dev->isColorDevice() ? "Extended color light" : "Dimmable light";
+ json += "\",\"manufacturername\":\"OpenSource\",\"swversion\":\"0.1\",\"name\":\"";
+ json += dev->getName();
+ json += "\",\"uniqueid\":\""+ WiFi.macAddress() +"-"+ (deviceId+1) ;
+ json += "\",\"modelid\":\"LST001\",\"state\":{\"on\":";
+ json += boolString(dev->getValue()) +",\"bri\":"+ (String)(dev->getLastValue()-1) ;
+ if (dev->isColorDevice())
+ {
+ json += ",\"xy\":[0.00000,0.00000],\"colormode\":\"";
+ json += (dev->isColorTemperatureMode()) ? "ct":"hs";
+ json += "\",\"effect\":\"none\",\"ct\":" + (String)(dev->getCt()) + ",\"hue\":" + (String)(dev->getHue()) + ",\"sat\":" + (String)(dev->getSat());
+ }
+ json +=",\"alert\":\"none\",\"reachable\":true}}";
+ return json;
+ }
+
+ //Espalexa status page /espalexa
+ void servePage()
+ {
+ EA_DEBUGLN("HTTP Req espalexa ...\n");
+ String res = "Hello from Espalexa!\r\n\r\n";
+ for (int i=0; igetName() + "): " + String(devices[i]->getValue()) + "\r\n";
+ }
+ res += "\r\nFree Heap: " + (String)ESP.getFreeHeap();
+ res += "\r\nUptime: " + (String)millis();
+ res += "\r\n\r\nEspalexa library v2.3.3 by Christian Schwinne 2019";
+ server->send(200, "text/plain", res);
+ }
+
+ //not found URI (only if internal webserver is used)
+ void serveNotFound()
+ {
+ EA_DEBUGLN("Not-Found HTTP call:");
+ #ifndef ESPALEXA_ASYNC
+ EA_DEBUGLN("URI: " + server->uri());
+ EA_DEBUGLN("Body: " + server->arg(0));
+ if(!handleAlexaApiCall(server->uri(), server->arg(0)))
+ #else
+ EA_DEBUGLN("URI: " + server->url());
+ EA_DEBUGLN("Body: " + body);
+ if(!handleAlexaApiCall(server))
+ #endif
+ server->send(404, "text/plain", "Not Found (espalexa-internal)");
+ }
+
+ //send description.xml device property page
+ void serveDescription()
+ {
+ EA_DEBUGLN("# Responding to description.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());
+
+ EA_DEBUG("Sending :");
+ EA_DEBUGLN(setup_xml);
+ }
+
+ //init the server
+ void startHttpServer()
+ {
+ #ifdef ESPALEXA_ASYNC
+ if (serverAsync == nullptr) {
+ serverAsync = new AsyncWebServer(80);
+ serverAsync->onNotFound([=](AsyncWebServerRequest *request){server = request; serveNotFound();});
+ }
+
+ serverAsync->onRequestBody([=](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
+ char b[len +1];
+ b[len] = 0;
+ memcpy(b, data, len);
+ body = b; //save the body so we can use it for the API call
+ EA_DEBUG("Received body: ");
+ EA_DEBUGLN(body);
+ });
+ serverAsync->on("/espalexa", HTTP_GET, [=](AsyncWebServerRequest *request){server = request; servePage();});
+ serverAsync->on("/description.xml", HTTP_GET, [=](AsyncWebServerRequest *request){server = request; serveDescription();});
+ serverAsync->begin();
+
+ #else
+ if (server == nullptr) {
+ #ifdef ARDUINO_ARCH_ESP32
+ server = new WebServer(80);
+ #else
+ server = new ESP8266WebServer(80);
+ #endif
+ server->onNotFound([=](){serveNotFound();});
+ }
+
+ server->on("/espalexa", HTTP_GET, [=](){servePage();});
+ server->on("/description.xml", HTTP_GET, [=](){serveDescription();});
+ server->begin();
+ #endif
+ }
+
+ //called when Alexa sends ON command
+ void alexaOn(uint8_t deviceId)
+ {
+ devices[deviceId-1]->setValue(devices[deviceId-1]->getLastValue());
+ devices[deviceId-1]->setPropertyChanged(1);
+ devices[deviceId-1]->doCallback();
+ }
+
+ //called when Alexa sends OFF command
+ void alexaOff(uint8_t deviceId)
+ {
+ devices[deviceId-1]->setValue(0);
+ devices[deviceId-1]->setPropertyChanged(2);
+ devices[deviceId-1]->doCallback();
+ }
+
+ //called when Alexa sends BRI command
+ void alexaDim(uint8_t deviceId, uint8_t briL)
+ {
+ if (briL == 255)
+ {
+ devices[deviceId-1]->setValue(255);
+ } else {
+ devices[deviceId-1]->setValue(briL+1);
+ }
+ devices[deviceId-1]->setPropertyChanged(3);
+ devices[deviceId-1]->doCallback();
+ }
+
+ //called when Alexa sends HUE command
+ void alexaCol(uint8_t deviceId, uint16_t hue, uint8_t sat)
+ {
+ devices[deviceId-1]->setColor(hue, sat);
+ devices[deviceId-1]->setPropertyChanged(4);
+ devices[deviceId-1]->doCallback();
+ }
+
+ //called when Alexa sends CT command (color temperature)
+ void alexaCt(uint8_t deviceId, uint16_t ct)
+ {
+ devices[deviceId-1]->setColor(ct);
+ devices[deviceId-1]->setPropertyChanged(5);
+ devices[deviceId-1]->doCallback();
+ }
+
+ //respond to UDP SSDP M-SEARCH
+ void respondToSearch()
+ {
+ 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=100\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";
+
+ espalexaUdp.beginPacket(espalexaUdp.remoteIP(), espalexaUdp.remotePort());
+ #ifdef ARDUINO_ARCH_ESP32
+ espalexaUdp.write((uint8_t*)response.c_str(), response.length());
+ #else
+ espalexaUdp.write(response.c_str());
+ #endif
+ espalexaUdp.endPacket();
+ }
+
+ String boolString(bool st)
+ {
+ return(st)?"true":"false";
+ }
+
+public:
+ Espalexa(){}
+
+ //initialize interfaces
+ #ifdef ESPALEXA_ASYNC
+ bool begin(AsyncWebServer* externalServer = nullptr)
+ #elif defined ARDUINO_ARCH_ESP32
+ bool begin(WebServer* externalServer = nullptr)
+ #else
+ bool begin(ESP8266WebServer* externalServer = nullptr)
+ #endif
+ {
+ EA_DEBUGLN("Espalexa Begin...");
+ EA_DEBUG("MAXDEVICES ");
+ EA_DEBUGLN(ESPALEXA_MAXDEVICES);
+ escapedMac = WiFi.macAddress();
+ escapedMac.replace(":", "");
+ escapedMac.toLowerCase();
+
+ #ifdef ESPALEXA_ASYNC
+ serverAsync = externalServer;
+ #else
+ server = externalServer;
+ #endif
+ #ifdef ARDUINO_ARCH_ESP32
+ udpConnected = espalexaUdp.beginMulticast(IPAddress(239, 255, 255, 250), 1900);
+ #else
+ udpConnected = espalexaUdp.beginMulticast(WiFi.localIP(), IPAddress(239, 255, 255, 250), 1900);
+ #endif
+
+ if (udpConnected){
+
+ startHttpServer();
+ EA_DEBUGLN("Done");
+ return true;
+ }
+ EA_DEBUGLN("Failed");
+ return false;
+ }
+
+ //service loop
+ void loop() {
+ #ifndef ESPALEXA_ASYNC
+ if (server == nullptr) return; //only if begin() was not called
+ server->handleClient();
+ #endif
+
+ if (!udpConnected) return;
+ int packetSize = espalexaUdp.parsePacket();
+ if (!packetSize) return; //no new udp packet
+
+ EA_DEBUGLN("Got UDP!");
+ int len = espalexaUdp.read(packetBuffer, 254);
+ if (len > 0) {
+ packetBuffer[len] = 0;
+ }
+
+ String request = packetBuffer;
+ EA_DEBUGLN(request);
+ if(request.indexOf("M-SEARCH") >= 0) {
+ if(request.indexOf("upnp:rootdevice") > 0 || request.indexOf("asic:1") > 0) {
+ EA_DEBUGLN("Responding search req...");
+ respondToSearch();
+ }
+ }
+ }
+
+ bool addDevice(EspalexaDevice* d)
+ {
+ EA_DEBUG("Adding device ");
+ EA_DEBUGLN((currentDeviceCount+1));
+ if (currentDeviceCount >= ESPALEXA_MAXDEVICES) return false;
+ devices[currentDeviceCount] = d;
+ currentDeviceCount++;
+ return true;
+ }
+
+ bool addDevice(String deviceName, CallbackBriFunction callback, uint8_t initialValue = 0)
+ {
+ EA_DEBUG("Constructing device ");
+ EA_DEBUGLN((currentDeviceCount+1));
+ if (currentDeviceCount >= ESPALEXA_MAXDEVICES) return false;
+ EspalexaDevice* d = new EspalexaDevice(deviceName, callback, initialValue);
+ return addDevice(d);
+ }
+
+ bool addDevice(String deviceName, CallbackColFunction callback, uint8_t initialValue = 0)
+ {
+ EA_DEBUG("Constructing device ");
+ EA_DEBUGLN((currentDeviceCount+1));
+ if (currentDeviceCount >= ESPALEXA_MAXDEVICES) return false;
+ EspalexaDevice* d = new EspalexaDevice(deviceName, callback, initialValue);
+ return addDevice(d);
+ }
+
+ //basic implementation of Philips hue api functions needed for basic Alexa control
+ #ifdef ESPALEXA_ASYNC
+ bool handleAlexaApiCall(AsyncWebServerRequest* request)
+ {
+ server = request; //copy request reference
+ String req = request->url(); //body from global variable
+ EA_DEBUGLN(request->contentType());
+ if (request->hasParam("body", true)) // This is necessary, otherwise ESP crashes if there is no body
+ {
+ EA_DEBUG("BodyMethod2");
+ body = request->getParam("body", true)->value();
+ }
+ EA_DEBUG("FinalBody: ");
+ EA_DEBUGLN(body);
+ #else
+ bool handleAlexaApiCall(String req, String body)
+ {
+ #endif
+ EA_DEBUGLN("AlexaApiCall");
+ if (req.indexOf("api") <0) return false; //return if not an API call
+ EA_DEBUGLN("ok");
+
+ if (body.indexOf("devicetype") > 0) //client wants a hue api username, we dont care and give static
+ {
+ EA_DEBUGLN("devType");
+ body = "";
+ server->send(200, "application/json", "[{\"success\":{\"username\": \"2WLEDHardQrI3WHYTHoMcXHgEspsM8ZZRpSKtBQr\"}}]");
+ return true;
+ }
+
+ if (req.indexOf("state") > 0) //client wants to control light
+ {
+ server->send(200, "application/json", "[{\"success\":true}]"); //short valid response
+
+ int tempDeviceId = req.substring(req.indexOf("lights")+7).toInt();
+ EA_DEBUG("ls"); EA_DEBUGLN(tempDeviceId);
+ if (body.indexOf("false")>0) {alexaOff(tempDeviceId); return true;}
+ if (body.indexOf("bri")>0 ) {alexaDim(tempDeviceId, body.substring(body.indexOf("bri") +5).toInt()); return true;}
+ if (body.indexOf("hue")>0 ) {alexaCol(tempDeviceId, body.substring(body.indexOf("hue") +5).toInt(), body.substring(body.indexOf("sat") +5).toInt()); return true;}
+ if (body.indexOf("ct") >0 ) {alexaCt (tempDeviceId, body.substring(body.indexOf("ct") +4).toInt()); return true;}
+ alexaOn(tempDeviceId);
+
+ return true;
+ }
+
+ int pos = req.indexOf("lights");
+ if (pos > 0) //client wants light info
+ {
+ int tempDeviceId = req.substring(pos+7).toInt();
+ EA_DEBUG("l"); EA_DEBUGLN(tempDeviceId);
+
+ if (tempDeviceId == 0) //client wants all lights
+ {
+ EA_DEBUGLN("lAll");
+ String jsonTemp = "{";
+ for (int i = 0; isend(200, "application/json", jsonTemp);
+ } else //client wants one light (tempDeviceId)
+ {
+ server->send(200, "application/json", deviceJsonString(tempDeviceId));
+ }
+
+ return true;
+ }
+
+ //we dont care about other api commands at this time and send empty JSON
+ server->send(200, "application/json", "{}");
+ return true;
+ }
+
+ //is an unique device ID
+ String getEscapedMac()
+ {
+ return escapedMac;
+ }
+
+ //convert brightness (0-255) to percentage
+ uint8_t toPercent(uint8_t bri)
+ {
+ uint16_t perc = bri * 100;
+ return perc / 255;
+ }
+
+ ~Espalexa(){delete devices;} //note: Espalexa is NOT meant to be destructed
+};
+
+#endif
+
diff --git a/wled00/src/dependencies/espalexa/EspalexaDevice.cpp b/wled00/src/dependencies/espalexa/EspalexaDevice.cpp
new file mode 100644
index 00000000..70f5cdb2
--- /dev/null
+++ b/wled00/src/dependencies/espalexa/EspalexaDevice.cpp
@@ -0,0 +1,176 @@
+//EspalexaDevice Class
+
+#include "EspalexaDevice.h"
+
+EspalexaDevice::EspalexaDevice(){}
+
+EspalexaDevice::EspalexaDevice(String deviceName, CallbackBriFunction gnCallback, uint8_t initialValue) { //constructor
+
+ _deviceName = deviceName;
+ _callback = gnCallback;
+ _val = initialValue;
+ _val_last = _val;
+}
+
+EspalexaDevice::EspalexaDevice(String deviceName, CallbackColFunction gnCallback, uint8_t initialValue) { //constructor for color device
+
+ _deviceName = deviceName;
+ _callbackCol = gnCallback;
+ _callback = nullptr;
+ _val = initialValue;
+ _val_last = _val;
+}
+
+EspalexaDevice::~EspalexaDevice(){/*nothing to destruct*/}
+
+bool EspalexaDevice::isColorDevice()
+{
+ //if brightness-only callback is null, we have color device
+ return (_callback == nullptr);
+}
+
+bool EspalexaDevice::isColorTemperatureMode()
+{
+ return _ct;
+}
+
+String EspalexaDevice::getName()
+{
+ return _deviceName;
+}
+
+uint8_t EspalexaDevice::getLastChangedProperty()
+{
+ return _changed;
+}
+
+uint8_t EspalexaDevice::getValue()
+{
+ return _val;
+}
+
+uint16_t EspalexaDevice::getHue()
+{
+ return _hue;
+}
+
+uint8_t EspalexaDevice::getSat()
+{
+ return _sat;
+}
+
+uint16_t EspalexaDevice::getCt()
+{
+ if (_ct == 0) return 500;
+ return _ct;
+}
+
+uint32_t EspalexaDevice::getColorRGB()
+{
+ uint8_t rgb[3];
+
+ if (isColorTemperatureMode())
+ {
+ //TODO tweak a bit to match hue lamp characteristics
+ //based on https://gist.github.com/paulkaplan/5184275
+ float temp = 10000/ _ct; //kelvins = 1,000,000/mired (and that /100)
+ float r, g, b;
+
+ if( temp <= 66 ){
+ r = 255;
+ g = temp;
+ g = 99.470802 * log(g) - 161.119568;
+ if( temp <= 19){
+ b = 0;
+ } else {
+ b = temp-10;
+ b = 138.517731 * log(b) - 305.044793;
+ }
+ } else {
+ r = temp - 60;
+ r = 329.698727 * pow(r, -0.13320476);
+ g = temp - 60;
+ g = 288.12217 * pow(g, -0.07551485 );
+ b = 255;
+ }
+
+ rgb[0] = (byte)constrain(r,0.1,255.1);
+ rgb[1] = (byte)constrain(g,0.1,255.1);
+ rgb[2] = (byte)constrain(b,0.1,255.1);
+ }
+ else
+ { //hue + sat mode
+ float h = ((float)_hue)/65535.0;
+ float s = ((float)_sat)/255.0;
+ byte i = floor(h*6);
+ float f = h * 6-i;
+ float p = 255 * (1-s);
+ float q = 255 * (1-f*s);
+ float t = 255 * (1-(1-f)*s);
+ switch (i%6) {
+ case 0: rgb[0]=255,rgb[1]=t,rgb[2]=p;break;
+ case 1: rgb[0]=q,rgb[1]=255,rgb[2]=p;break;
+ case 2: rgb[0]=p,rgb[1]=255,rgb[2]=t;break;
+ case 3: rgb[0]=p,rgb[1]=q,rgb[2]=255;break;
+ case 4: rgb[0]=t,rgb[1]=p,rgb[2]=255;break;
+ case 5: rgb[0]=255,rgb[1]=p,rgb[2]=q;
+ }
+ }
+ return ((rgb[0] << 16) | (rgb[1] << 8) | (rgb[2]));
+}
+
+uint8_t EspalexaDevice::getLastValue()
+{
+ if (_val_last == 0) return 255;
+ return _val_last;
+}
+
+void EspalexaDevice::setPropertyChanged(uint8_t p)
+{
+ //0: initial 1: on 2: off 3: bri 4: col 5: ct
+ _changed = p;
+}
+
+//you need to re-discover the device for the Alexa name to change
+void EspalexaDevice::setName(String name)
+{
+ _deviceName = name;
+}
+
+void EspalexaDevice::setValue(uint8_t val)
+{
+ if (_val != 0)
+ {
+ _val_last = _val;
+ }
+ if (val != 0)
+ {
+ _val_last = val;
+ }
+ _val = val;
+}
+
+void EspalexaDevice::setPercent(uint8_t perc)
+{
+ uint16_t val = perc * 255;
+ val /= 100;
+ if (val > 255) val = 255;
+ setValue(val);
+}
+
+void EspalexaDevice::setColor(uint16_t hue, uint8_t sat)
+{
+ _hue = hue;
+ _sat = sat;
+ _ct = 0;
+}
+
+void EspalexaDevice::setColor(uint16_t ct)
+{
+ _ct = ct;
+}
+
+void EspalexaDevice::doCallback()
+{
+ (_callback != nullptr) ? _callback(_val) : _callbackCol(_val, getColorRGB());
+}
\ No newline at end of file
diff --git a/wled00/src/dependencies/espalexa/EspalexaDevice.h b/wled00/src/dependencies/espalexa/EspalexaDevice.h
new file mode 100644
index 00000000..0974ff3a
--- /dev/null
+++ b/wled00/src/dependencies/espalexa/EspalexaDevice.h
@@ -0,0 +1,46 @@
+#ifndef EspalexaDevice_h
+#define EspalexaDevice_h
+
+#include "Arduino.h"
+
+typedef void (*CallbackBriFunction) (uint8_t br);
+typedef void (*CallbackColFunction) (uint8_t br, uint32_t col);
+
+class EspalexaDevice {
+private:
+ String _deviceName;
+ CallbackBriFunction _callback;
+ CallbackColFunction _callbackCol;
+ uint8_t _val, _val_last, _sat = 0;
+ uint16_t _hue = 0, _ct = 0;
+ uint8_t _changed = 0;
+
+public:
+ EspalexaDevice();
+ ~EspalexaDevice();
+ EspalexaDevice(String deviceName, CallbackBriFunction gnCallback, uint8_t initialValue =0);
+ EspalexaDevice(String deviceName, CallbackColFunction gnCallback, uint8_t initialValue =0);
+
+ bool isColorDevice();
+ bool isColorTemperatureMode();
+ String getName();
+ uint8_t getLastChangedProperty();
+ uint8_t getValue();
+ uint16_t getHue();
+ uint8_t getSat();
+ uint16_t getCt();
+ uint32_t getColorRGB();
+
+ void setPropertyChanged(uint8_t p);
+ void setValue(uint8_t bri);
+ void setPercent(uint8_t perc);
+ void setName(String name);
+ void setColor(uint16_t hue, uint8_t sat);
+ void setColor(uint16_t ct);
+
+ void doCallback();
+
+ uint8_t getLastValue(); //last value that was not off (1-255)
+};
+
+#endif
\ No newline at end of file
diff --git a/wled00/src/dependencies/espalexa/LICENSE b/wled00/src/dependencies/espalexa/LICENSE
new file mode 100644
index 00000000..37f4d769
--- /dev/null
+++ b/wled00/src/dependencies/espalexa/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Christian Schwinne
+
+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/timezone/Timezone.h b/wled00/src/dependencies/timezone/Timezone.h
index c55d0c46..991eca0a 100644
--- a/wled00/src/dependencies/timezone/Timezone.h
+++ b/wled00/src/dependencies/timezone/Timezone.h
@@ -16,7 +16,7 @@
#else
#include
#endif
-#include //http://www.arduino.cc/playground/Code/Time
+#include "../time/Time.h" //http://www.arduino.cc/playground/Code/Time
//convenient constants for dstRules
enum week_t {Last, First, Second, Third, Fourth};
diff --git a/wled00/wled00.ino b/wled00/wled00.ino
index 37bfec49..8abb527a 100644
--- a/wled00/wled00.ino
+++ b/wled00/wled00.ino
@@ -3,7 +3,7 @@
*/
/*
* @title WLED project sketch
- * @version 0.8.2
+ * @version 0.8.3
* @author Christian Schwinne
*/
@@ -60,6 +60,10 @@
#include "src/dependencies/time/Time.h"
#include "src/dependencies/time/TimeLib.h"
#include "src/dependencies/timezone/Timezone.h"
+#ifndef WLED_DISABLE_ALEXA
+ #define ESPALEXA_MAXDEVICES 1
+ #include "src/dependencies/espalexa/Espalexa.h"
+#endif
#ifndef WLED_DISABLE_BLYNK
#include "src/dependencies/blynk/BlynkSimpleEsp.h"
#endif
@@ -74,8 +78,8 @@
//version code in format yymmddb (b = daily build)
-#define VERSION 1812141
-char versionString[] = "0.8.2";
+#define VERSION 1901091
+char versionString[] = "0.8.3-dev";
//AP and OTA default passwords (for maximum change them!)
@@ -370,11 +374,11 @@ unsigned long auxStartTime = 0;
bool auxActive = false, auxActiveBefore = false;
//alexa udp
-WiFiUDP alexaUDP;
-bool alexaUdpConnected = false;
-IPAddress ipMulti(239, 255, 255, 250);
-unsigned int portMulti = 1900;
String escapedMac;
+#ifndef WLED_DISABLE_ALEXA
+Espalexa espalexa;
+EspalexaDevice* espalexaDevice;
+#endif
//dns server
DNSServer dnsServer;
@@ -465,6 +469,7 @@ void serveMessage(int,String,String,int=255);
void reset()
{
briT = 0;
+ delay(250); //enough time to send response to client
setAllLeds();
DEBUG_PRINTLN("MODULE RESET");
ESP.restart();
diff --git a/wled00/wled01_eeprom.ino b/wled00/wled01_eeprom.ino
index 4927433e..90552bcb 100644
--- a/wled00/wled01_eeprom.ino
+++ b/wled00/wled01_eeprom.ino
@@ -461,7 +461,7 @@ void loadSettingsFromEEPROM(bool first)
strip.colorOrder = EEPROM.read(383);
irEnabled = EEPROM.read(385);
strip.ablMilliampsMax = EEPROM.read(387) + ((EEPROM.read(388) << 8) & 0xFF00);
- } else if (lastEEPROMversion > 1) //ABL is off by default when updating from version older than 0.8.2
+ } else if (lastEEPROMversion > 1) //ABL is off by default when updating from version older than 0.8.3
{
strip.ablMilliampsMax = 65000;
} else {
diff --git a/wled00/wled03_set.ino b/wled00/wled03_set.ino
index 175796ad..df94d563 100644
--- a/wled00/wled03_set.ino
+++ b/wled00/wled03_set.ino
@@ -309,6 +309,7 @@ void handleSettingsSet(byte subPage)
}
saveSettingsToEEPROM();
if (subPage == 2) strip.init(useRGBW,ledCount,skipFirstLed);
+ if (subPage == 4) alexaInit();
}
diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino
index ab98c7a6..127a392a 100644
--- a/wled00/wled05_init.ino
+++ b/wled00/wled05_init.ino
@@ -271,7 +271,7 @@ void getBuildInfo()
oappend("\r\nstrip-pin: gpio");
oappendi(LEDPIN);
oappend("\r\nbrand: wled");
- oappend("\r\nbuild-type: src\r\n");
+ oappend("\r\nbuild-type: dev\r\n");
}
diff --git a/wled00/wled07_notify.ino b/wled00/wled07_notify.ino
index 958f8a59..6befaae5 100644
--- a/wled00/wled07_notify.ino
+++ b/wled00/wled07_notify.ino
@@ -16,9 +16,10 @@ void notify(byte callMode, bool followUp=false)
case 2: if (!notifyButton) return; break;
case 4: if (!notifyDirect) return; break;
case 6: if (!notifyDirect) return; break; //fx change
- case 7: if (!notifyHue) return; break;
+ case 7: if (!notifyHue) return; break;
case 8: if (!notifyDirect) return; break;
case 9: if (!notifyDirect) return; break;
+ case 10: if (!notifyAlexa) return; break;
default: return;
}
byte udpOut[WLEDPACKETSIZE];
diff --git a/wled00/wled08_led.ino b/wled00/wled08_led.ino
index ffda2762..65396161 100644
--- a/wled00/wled08_led.ino
+++ b/wled00/wled08_led.ino
@@ -36,7 +36,7 @@ void setAllLeds() {
}
whiteSecT = whiteSec;
}
- if (autoRGBtoRGBW)
+ if (useRGBW && autoRGBtoRGBW)
{
colorRGBtoRGBW(colT,&whiteT);
colorRGBtoRGBW(colSecT,&whiteSecT);
@@ -87,7 +87,7 @@ bool colorChanged()
void colorUpdated(int callMode)
{
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
- // 6: fx changed 7: hue 8: preset cycle 9: blynk
+ // 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
bool fxChanged = strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectPalette);
if (!colorChanged())
{
@@ -146,6 +146,9 @@ void colorUpdated(int callMode)
}
if (callMode == 8) return;
+ #ifndef WLED_DISABLE_ALEXA
+ if (espalexaDevice != nullptr) espalexaDevice->setValue(bri);
+ #endif
//only update Blynk and mqtt every 2 seconds to reduce lag
if (millis() - lastInterfaceUpdate <= 2000)
{
diff --git a/wled00/wled12_alexa.ino b/wled00/wled12_alexa.ino
index fe703c93..f9ccb6a5 100644
--- a/wled00/wled12_alexa.ino
+++ b/wled00/wled12_alexa.ino
@@ -12,280 +12,69 @@ void prepareIds() {
}
#ifndef WLED_DISABLE_ALEXA
+void onAlexaChange(byte b, uint32_t color);
+
void alexaInit()
{
if (alexaEnabled && WiFi.status() == WL_CONNECTED)
{
- alexaUdpConnected = connectUDP();
-
- if (alexaUdpConnected) alexaInitPages();
+ if (espalexaDevice == nullptr) //only init once
+ {
+ espalexaDevice = new EspalexaDevice(alexaInvocationName, onAlexaChange);
+ espalexa.addDevice(espalexaDevice);
+ espalexa.begin(&server);
+ } else {
+ espalexaDevice->setName(alexaInvocationName);
+ }
}
}
void handleAlexa()
{
- if (!alexaEnabled || WiFi.status() != WL_CONNECTED || !alexaUdpConnected) return;
-
- // if there's data available, read a packet
- int packetSize = alexaUDP.parsePacket();
- if(packetSize < 1) return;
-
- IPAddress remote = alexaUDP.remoteIP();
- int len = alexaUDP.read(obuf, 254);
- if (len > 0) obuf[len] = 0;
-
- if(strstr(obuf,"M-SEARCH") > 0) {
- if(strstr(obuf,"upnp:rootdevice") > 0 || strstr(obuf,"device:basic:1") > 0) {
- DEBUG_PRINTLN("Responding search req...");
- respondToSearch();
- }
- }
+ if (!alexaEnabled || WiFi.status() != WL_CONNECTED) return;
+ espalexa.loop();
}
-void alexaOn()
+void onAlexaChange(byte b, uint32_t color)
{
- if (macroAlexaOn == 0)
- {
- handleSet((notifyAlexa)?"win&T=1&IN":"win&T=1&NN&IN");
- } else
- {
- applyMacro(macroAlexaOn);
- }
-
- server.send(200, "application/json", "[{\"success\":{\"/lights/1/state/on\":true}}]");
-}
-
-void alexaOff()
-{
- if (macroAlexaOff == 0)
- {
- handleSet((notifyAlexa)?"win&T=0&IN":"win&T=0&NN&IN");
- } else
- {
- applyMacro(macroAlexaOff);
- }
-
- server.send(200, "application/json", "[{\"success\":{\"/lights/1/state/on\":false}}]");
-}
-
-void alexaDim(byte briL)
-{
- olen = 0;
- oappend("[{\"success\":{\"/lights/1/state/bri\":");
- oappendi(briL);
- oappend("}}]");
-
- server.send(200, "application/json", obuf);
+ byte m = espalexaDevice->getLastChangedProperty();
- String ct = (notifyAlexa)?"win&IN&A=":"win&NN&IN&A=";
- if (briL < 255)
+ if (m == 1){ //ON
+ if (!macroAlexaOn)
+ {
+ if (bri == 0)
+ {
+ bri = briLast;
+ colorUpdated(10);
+ }
+ } else applyMacro(macroAlexaOn);
+ } else if (m == 2) //OFF
{
- ct = ct + (briL+1);
- } else
+ if (!macroAlexaOff)
+ {
+ if (bri > 0)
+ {
+ briLast = bri;
+ bri = 0;
+ colorUpdated(10);
+ }
+ } else applyMacro(macroAlexaOff);
+ } else if (m == 3) //brightness
{
- ct = ct + (255);
+ bri = b;
+ colorUpdated(10);
+ } else //color
+ {
+ col[0] = ((color >> 16) & 0xFF);
+ col[1] = ((color >> 8) & 0xFF);
+ col[2] = (color & 0xFF);
+ if (useRGBW) colorRGBtoRGBW(col,&white);
+ colorUpdated(10);
}
- handleSet(ct);
}
-void respondToSearch() {
- DEBUG_PRINTLN("");
- DEBUG_PRINT("Send resp to ");
- DEBUG_PRINTLN(alexaUDP.remoteIP());
- DEBUG_PRINT("Port : ");
- DEBUG_PRINTLN(alexaUDP.remotePort());
-
- IPAddress localIP = WiFi.localIP();
- char s[16];
- sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
-
- olen = 0;
- oappend(
- "HTTP/1.1 200 OK\r\n"
- "EXT:\r\n"
- "CACHE-CONTROL: max-age=100\r\n" // SSDP_INTERVAL
- "LOCATION: http://");
- oappend(s);
- oappend(":80/description.xml\r\n"
- "SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.17.0\r\n" // _modelName, _modelNumber
- "hue-bridgeid: ");
- oappend((char*)escapedMac.c_str());
- oappend("\r\n"
- "ST: urn:schemas-upnp-org:device:basic:1\r\n" // _deviceType
- "USN: uuid:2f402f80-da50-11e1-9b23-");
- oappend((char*)escapedMac.c_str());
- oappend("::upnp:rootdevice\r\n" // _uuid::_deviceType
- "\r\n");
-
- alexaUDP.beginPacket(alexaUDP.remoteIP(), alexaUDP.remotePort());
- #ifdef ARDUINO_ARCH_ESP32
- alexaUDP.write((byte*)obuf, olen);
- #else
- alexaUDP.write(obuf);
- #endif
- alexaUDP.endPacket();
-
- DEBUG_PRINTLN("Response sent!");
-}
-
-void alexaInitPages() {
-
- server.on("/description.xml", HTTP_GET, [](){
- DEBUG_PRINTLN(" # Responding to description.xml ... #\n");
-
- IPAddress localIP = WiFi.localIP();
- char s[16];
- sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
-
- olen = 0;
- oappend(""
- ""
- "10"
- "http://");
- oappend(s);
- oappend(":80/"
- ""
- "urn:schemas-upnp-org:device:Basic:1"
- "Philips hue (");
- oappend(s);
- oappend(")"
- "Royal Philips Electronics"
- "http://www.philips.com"
- "Philips hue Personal Wireless Lighting"
- "Philips hue bridge 2012"
- "929000226503"
- "http://www.meethue.com"
- "");
- oappend((char*)escapedMac.c_str());
- oappend(""
- "uuid:2f402f80-da50-11e1-9b23-");
- oappend((char*)escapedMac.c_str());
- oappend(""
- "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", obuf);
-
- DEBUG_PRINTLN("Sending setup_xml");
- });
-
- // openHAB support
- server.on("/on.html", HTTP_GET, [](){
- DEBUG_PRINTLN("on req");
- server.send(200, "text/plain", "turned on");
- alexaOn();
- });
-
- server.on("/off.html", HTTP_GET, [](){
- DEBUG_PRINTLN("off req");
- server.send(200, "text/plain", "turned off");
- alexaOff();
- });
-
- server.on("/status.html", HTTP_GET, [](){
- DEBUG_PRINTLN("Got status request");
-
- char statrespone[] = "0";
- if (bri > 0) {
- statrespone[0] = '1';
- }
- server.send(200, "text/plain", statrespone);
- });
-}
-
-String boolString(bool st)
-{
- return (st)?"true":"false";
-}
-
-String briForHue(int realBri)
-{
- realBri--;
- if (realBri < 0) realBri = 0;
- return String(realBri);
-}
-
-bool handleAlexaApiCall(String req, String body) //basic implementation of Philips hue api functions needed for basic Alexa control
-{
- DEBUG_PRINTLN("AlexaApiCall");
- if (req.indexOf("api") <0) return false;
- DEBUG_PRINTLN("ok");
- if (body.indexOf("devicetype") > 0) //client wants a hue api username, we dont care and give static
- {
- DEBUG_PRINTLN("devType");
- server.send(200, "application/json", "[{\"success\":{\"username\": \"2WLEDHardQrI3WHYTHoMcXHgEspsM8ZZRpSKtBQr\"}}]");
- return true;
- }
- if (req.indexOf("state") > 0) //client wants to control light
- {
- DEBUG_PRINTLN("ls");
- if (body.indexOf("bri")>0) {alexaDim(body.substring(body.indexOf("bri") +5).toInt()); return true;}
- if (body.indexOf("false")>0) {alexaOff(); return true;}
- alexaOn();
-
- return true;
- }
- if (req.indexOf("lights/1") > 0) //client wants light info
- {
- DEBUG_PRINTLN("l1");
- server.send(200, "application/json", "{\"manufacturername\":\"OpenSource\",\"modelid\":\"LST001\",\"name\":\""+ String(alexaInvocationName) +"\",\"state\":{\"on\":"+ boolString(bri) +",\"hue\":0,\"bri\":"+ briForHue(bri) +",\"sat\":0,\"xy\":[0.00000,0.00000],\"ct\":500,\"alert\":\"none\",\"effect\":\"none\",\"colormode\":\"hs\",\"reachable\":true},\"swversion\":\"0.1\",\"type\":\"Extended color light\",\"uniqueid\":\"2\"}");
-
- return true;
- }
- if (req.indexOf("lights") > 0) //client wants all lights
- {
- DEBUG_PRINTLN("lAll");
- server.send(200, "application/json", "{\"1\":{\"type\":\"Extended color light\",\"manufacturername\":\"OpenSource\",\"swversion\":\"0.1\",\"name\":\""+ String(alexaInvocationName) +"\",\"uniqueid\":\""+ WiFi.macAddress() +"-2\",\"modelid\":\"LST001\",\"state\":{\"on\":"+ boolString(bri) +",\"bri\":"+ briForHue(bri) +",\"xy\":[0.00000,0.00000],\"colormode\":\"hs\",\"effect\":\"none\",\"ct\":500,\"hue\":0,\"sat\":0,\"alert\":\"none\",\"reachable\":true}}}");
- return true;
- }
-
- //we dont care about other api commands at this time and send empty JSON
- server.send(200, "application/json", "{}");
- return true;
-}
-
-bool connectUDP(){
- bool state = false;
-
- DEBUG_PRINTLN("");
- DEBUG_PRINTLN("Con UDP");
-
- #ifdef ARDUINO_ARCH_ESP32
- if(alexaUDP.beginMulticast(ipMulti, portMulti))
- #else
- if(alexaUDP.beginMulticast(WiFi.localIP(), ipMulti, portMulti))
- #endif
- {
- DEBUG_PRINTLN("Con success");
- state = true;
- }
- else{
- DEBUG_PRINTLN("Con failed");
- }
-
- return state;
-}
#else
void alexaInit(){}
void handleAlexa(){}
- void alexaInitPages(){}
- bool handleAlexaApiCall(String req, String body){return false;}
#endif
diff --git a/wled00/wled18_server.ino b/wled00/wled18_server.ino
index 0d4a0929..8c990fc8 100644
--- a/wled00/wled18_server.ino
+++ b/wled00/wled18_server.ino
@@ -178,7 +178,9 @@ void initServer()
}
if(!handleSet(server.uri())){
- if(!handleAlexaApiCall(server.uri(),server.arg(0)))
+ #ifndef WLED_DISABLE_ALEXA
+ if(!espalexa.handleAlexaApiCall(server.uri(),server.arg(0)))
+ #endif
server.send(404, "text/plain", "Not Found");
}
});