diff --git a/readme.md b/readme.md index 778be9d06..6e66a6950 100644 --- a/readme.md +++ b/readme.md @@ -1,17 +1,20 @@ +![WLED logo](https://raw.githubusercontent.com/Aircoookie/WLED/master/wled_logo.png) + ## Welcome to my project WLED! -WLED is a fast and (relatively) secure implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B) LEDs! +WLED is a fast, advanced and (relatively) secure implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B) LEDs! -### Features: (V0.7.1) +### Features: (v0.8.0) - RGB, HSB, and brightness sliders - All new, mobile-friendly web UI! - Settings page - configuration over network - Access Point and station mode - automatic failsafe AP -- Support of Blynk IoT cloud -- WS2812FX library integrated for over 50 special effects (+Custom Theater Chase)! +- Support of Blynk IoT cloud and MQTT +- WS2812FX library integrated for over 70 special effects (with FastLED palettes)! - Secondary color support lets you use even more effect combinations - Alexa smart home device server (including dimming) - Beta syncronization to Philips hue lights +- Realtime UDP Packet Control (E1.31, Hyperion, WARLS, DRGB, DRGBW) - Support for RGBW strips - 25 user presets! Save colors and effects and apply them easily! Supports cycling through them. - HTTP request API for simple integration @@ -24,7 +27,6 @@ WLED is a fast and (relatively) secure implementation of an ESP8266/ESP32 webser - Password protected OTA page for added security (OTA lock) - NTP and configurable analog clock function - Support for the Cronixie Clock kit by Diamex -- Realtime UDP Packet Control (E1.31, Hyperion, WARLS, DRGB, DRGBW) ### Quick start guide and documentation: @@ -32,16 +34,14 @@ See the [wiki](https://github.com/Aircoookie/WLED/wiki)! ### Other -Licensed under the MIT license -Uses libraries: -ESP8266/ESP32 Arduino Core -NeoPixelBus by Makuna -[WS2812FX](https://github.com/kitesurfer1404/WS2812FX) by kitesurfer1404 (Aircoookie fork) -Time library -Timezone library by JChristensen -Alexa code based on arduino-esp8266-alexa-multiple-wemo-switch by kakopappa +Licensed under the MIT license +Credits in About page! -Uses Linearicons by Perxis! (link in settings page) +Uses Linearicons by Perxis! + +Join the Discord [server](https://discord.gg/KuqP7NE) to discuss everything about WLED! +You can also send me mails to [dev.aircoookie@gmail.com](mailto:dev.aircoookie@gmail.com). +If you insist that you just love WLED too much, you can [send me a gift](https://paypal.me/aircoookie) diff --git a/wled00/data/index.htm b/wled00/data/index.htm index 353498808..d35ee2b9b 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -2,7 +2,7 @@ - WLED 0.8.0-a + WLED 0.8.0 )====="; diff --git a/wled00/htmls01.h b/wled00/htmls01.h index b9a2b8d25..b015bf583 100644 --- a/wled00/htmls01.h +++ b/wled00/htmls01.h @@ -250,6 +250,11 @@ Alexa invocation name:

Blynk

Device Auth token:
Clear the token field to disable. Setup info +

MQTT

+Broker:
+Device Topic:
+Group Topic:
+Reboot required to apply changes. MQTT info

Philips Hue

You can find the bridge IP and the light number in the 'About' section of the hue app.
Poll Hue light every ms:
@@ -406,7 +411,7 @@ HTTP traffic is unencrypted. An attacker in the same network can intercept form
Enable ArduinoOTA:

About

-WLED version 0.8.0-a

+WLED version 0.8.0

Contributors:
StormPie (Mobile HTML UI)

Thank you so much!

@@ -421,6 +426,7 @@ Thank you so much!

Timezone library by JChristensen
Blynk library (compacted)
E1.31 library by forkineye (modified)
+PubSubClient by knolleary (modified)
Espalexa by Aircoookie (modified)

UI icons by Linearicons created by Perxis! (CC-BY-SA 4.0)

Server message: Response error!
diff --git a/wled00/wled00.ino b/wled00/wled00.ino index 1eb429ea8..cf212f011 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -3,7 +3,7 @@ */ /* * @title WLED project sketch - * @version 0.8.0-a + * @version 0.8.0 * @author Christian Schwinne */ @@ -45,8 +45,8 @@ //version code in format yymmddb (b = daily build) -#define VERSION 1810011 -char versionString[] = "0.8.0-a"; +#define VERSION 1810031 +char versionString[] = "0.8.0"; //AP and OTA default passwords (for maximum change them!) @@ -59,7 +59,7 @@ char otaPass[33] = "wledota"; //to toggle usb serial debug (un)comment following line(s) -#define DEBUG +//#define DEBUG //Hardware CONFIG (only changeble HERE, not at runtime) @@ -111,7 +111,7 @@ byte nightlightDelayMins = 60; bool nightlightFade = true; //if enabled, light will gradually dim towards the target bri. Otherwise, it will instantly set after delay over bool fadeTransition = true; //enable crossfading color transition bool enableSecTransition = true; //also enable transition for secondary color -uint16_t transitionDelay = 1200; //default crossfade duration in ms +uint16_t transitionDelay = 900; //default crossfade duration in ms bool reverseMode = false; //flip entire LED strip (reverses all effect directions) bool initLedsLast = false; //turn on LEDs only after WiFi connected/AP open @@ -161,9 +161,9 @@ bool e131Enabled = true; //settings for E1.31 (sACN) protoc uint16_t e131Universe = 1; bool e131Multicast = false; -char mqttTopic0[33] = ""; //main MQTT topic (individual per device, default is wled/mac) -char mqttTopic1[33] = "wled/all"; //second MQTT topic (for example to group devices) -char mqttServer[33] = "37.187.106.16"; //both domains and IPs should work (no SSL) 37.187.106.16 +char mqttDeviceTopic[33] = ""; //main MQTT topic (individual per device, default is wled/mac) +char mqttGroupTopic[33] = "wled/all"; //second MQTT topic (for example to group devices) +char mqttServer[33] = ""; //both domains and IPs should work (no SSL) bool huePollingEnabled = false; //poll hue bridge for light state uint16_t huePollIntervalMs = 2500; //low values (< 1sec) may cause lag but offer quicker response @@ -272,7 +272,7 @@ bool onlyAP = false; //only Access Point active, no con bool udpConnected = false, udpRgbConnected = false; //ui style -char cssCol[9][5]={"","","","","",""}; +char cssCol[6][9]={"","","","","",""}; String cssColorString=""; bool showWelcomePage = false; @@ -332,6 +332,9 @@ unsigned long realtimeTimeout = 0; //mqtt bool mqttInit = false; long lastMQTTReconnectAttempt = 0; +long lastInterfaceUpdate = 0; +byte interfaceUpdateCallMode = 0; +uint32_t mqttFailedConAttempts = 0; //auxiliary debug pin byte auxTime = 0; diff --git a/wled00/wled01_eeprom.ino b/wled00/wled01_eeprom.ino index f3c0459d7..c5b2cfad2 100644 --- a/wled00/wled01_eeprom.ino +++ b/wled00/wled01_eeprom.ino @@ -6,7 +6,7 @@ #define EEPSIZE 3072 //eeprom Version code, enables default settings instead of 0 init on update -#define EEPVER 8 +#define EEPVER 9 //0 -> old version, default //1 -> 0.4p 1711272 and up //2 -> 0.4p 1711302 and up @@ -15,7 +15,8 @@ //5 -> 0.5.1 and up //6 -> 0.6.0 and up //7 -> 0.7.1 and up -//8 -> 0.8.0 and up +//8 -> 0.8.0-a and up +//9 -> 0.8.0 /* * Erase all configuration data @@ -147,7 +148,7 @@ void saveSettingsToEEPROM() int in = 900+k*8; for (int i=in; i < in+8; ++i) { - EEPROM.write(i, cssCol[i-in][k]); + EEPROM.write(i, cssCol[k][i-in]); }} EEPROM.write(948,currentTheme); @@ -242,6 +243,19 @@ void saveSettingsToEEPROM() EEPROM.write(2280 + i, timerWeekday[i]); EEPROM.write(2290 + i, timerMacro[i] ); } + + for (int i = 2300; i < 2333; ++i) + { + EEPROM.write(i, mqttServer[i-2300]); + } + for (int i = 2333; i < 2366; ++i) + { + EEPROM.write(i, mqttDeviceTopic[i-2333]); + } + for (int i = 2366; i < 2399; ++i) + { + EEPROM.write(i, mqttGroupTopic[i-2366]); + } EEPROM.commit(); } @@ -468,6 +482,25 @@ void loadSettingsFromEEPROM(bool first) timerMacro[i] = EEPROM.read(2290 + i); } } + + if (lastEEPROMversion > 8) + { + for (int i = 2300; i < 2333; ++i) + { + mqttServer[i-2300] = EEPROM.read(i); + if (mqttServer[i-2300] == 0) break; + } + for (int i = 2333; i < 2366; ++i) + { + mqttDeviceTopic[i-2333] = EEPROM.read(i); + if (mqttDeviceTopic[i-2333] == 0) break; + } + for (int i = 2366; i < 2399; ++i) + { + mqttGroupTopic[i-2366] = EEPROM.read(i); + if (mqttGroupTopic[i-2366] == 0) break; + } + } receiveDirect = !EEPROM.read(2200); enableRealtimeUI = EEPROM.read(2201); @@ -491,12 +524,6 @@ void loadSettingsFromEEPROM(bool first) presetApplyCol = EEPROM.read(2211); presetApplyFx = EEPROM.read(2212); } - - for (int i = 2220; i < 2255; ++i) - { - blynkApiKey[i-2220] = EEPROM.read(i); - if (blynkApiKey[i-2220] == 0) break; - } bootPreset = EEPROM.read(389); wifiLock = EEPROM.read(393); @@ -514,12 +541,18 @@ void loadSettingsFromEEPROM(bool first) for (int i=in; i < in+8; ++i) { if (EEPROM.read(i) == 0) break; - cssCol[i-in][k] =EEPROM.read(i); + cssCol[k][i-in] =EEPROM.read(i); }} //custom macro memory (16 slots/ each 64byte) //1024-2047 reserved + for (int i = 2220; i < 2255; ++i) + { + blynkApiKey[i-2220] = EEPROM.read(i); + if (blynkApiKey[i-2220] == 0) break; + } + //user MOD memory //2944 - 3071 reserved diff --git a/wled00/wled02_xml.ino b/wled00/wled02_xml.ino index 8aaca5638..07f55921c 100644 --- a/wled00/wled02_xml.ino +++ b/wled00/wled02_xml.ino @@ -241,7 +241,9 @@ void getSettingsJS(byte subPage) //get values for settings form in javascript sappend('c',"AL",alexaEnabled); sappends('s',"AI",alexaInvocationName); sappend('c',"SA",notifyAlexa); - sappends('s',"BK",(char*)((blynkEnabled)?"Hidden":"")); + sappends('s',"MS",mqttServer); + sappends('s',"MD",mqttDeviceTopic); + sappends('s',"MG",mqttGroupTopic); sappend('v',"H0",hueIP[0]); sappend('v',"H1",hueIP[1]); sappend('v',"H2",hueIP[2]); diff --git a/wled00/wled03_set.ino b/wled00/wled03_set.ino index 487c6fa29..4d1fac9b7 100644 --- a/wled00/wled03_set.ino +++ b/wled00/wled03_set.ino @@ -170,6 +170,10 @@ void handleSettingsSet(byte subPage) notifyAlexa = server.hasArg("SA"); if (server.hasArg("BK") && !server.arg("BK").equals("Hidden")) {strcpy(blynkApiKey,server.arg("BK").c_str()); initBlynk(blynkApiKey);} + + strcpy(mqttServer, server.arg("MS").c_str()); + strcpy(mqttDeviceTopic, server.arg("MD").c_str()); + strcpy(mqttGroupTopic, server.arg("MG").c_str()); notifyHue = server.hasArg("SH"); for (int i=0;i<4;i++){ diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino index 6ca487b7a..d29c15816 100644 --- a/wled00/wled05_init.ino +++ b/wled00/wled05_init.ino @@ -58,7 +58,7 @@ void wledInit() } prepareIds(); //UUID from MAC (for Alexa and MQTT) - if (mqttTopic0[0] == 0) strcpy(mqttTopic0, strcat("wled/", escapedMac.c_str())); + if (mqttDeviceTopic[0] == 0) strcpy(mqttDeviceTopic, strcat("wled/", escapedMac.c_str())); if (!onlyAP) mqttInit = initMQTT(); if (!initLedsLast) strip.service(); diff --git a/wled00/wled08_led.ino b/wled00/wled08_led.ino index c71deda14..f45e9b92a 100644 --- a/wled00/wled08_led.ino +++ b/wled00/wled08_led.ino @@ -92,12 +92,14 @@ void colorUpdated(int callMode) whiteSecIT = whiteSec; briIT = bri; if (bri > 0) briLast = bri; + notify(callMode); + if (fadeTransition) { //set correct delay if not using notification delay if (callMode != 3) transitionDelayTemp = transitionDelay; - if (transitionDelayTemp == 0) {setLedsStandard();strip.trigger();return;} + if (transitionDelayTemp == 0) {setLedsStandard(); strip.trigger(); return;} if (transitionActive) { @@ -120,11 +122,33 @@ void colorUpdated(int callMode) setLedsStandard(); strip.trigger(); } - if (callMode != 9 && callMode != 5 && callMode != 8) updateBlynk(); + + if (callMode == 8) return; + //only update Blynk and mqtt every 2 seconds to reduce lag + if (millis() - lastInterfaceUpdate <= 2000) + { + interfaceUpdateCallMode = callMode; + return; + } + updateInterfaces(callMode); +} + +void updateInterfaces(uint8_t callMode) +{ + if (callMode != 9 && callMode != 5) updateBlynk(); + publishMQTT(); + lastInterfaceUpdate = millis(); } void handleTransitions() { + //handle still pending interface update + if (interfaceUpdateCallMode && millis() - lastInterfaceUpdate > 2000) + { + updateInterfaces(interfaceUpdateCallMode); + interfaceUpdateCallMode = 0; //disable + } + if (transitionActive && transitionDelayTemp > 0) { float tper = (millis() - transitionStartTime)/(float)transitionDelayTemp; diff --git a/wled00/wled17_mqtt.ino b/wled00/wled17_mqtt.ino index 82df40eb3..93be98ed1 100644 --- a/wled00/wled17_mqtt.ino +++ b/wled00/wled17_mqtt.ino @@ -28,23 +28,38 @@ void callbackMQTT(char* topic, byte* payload, unsigned int length) { colorUpdated(1); } else if (strstr(topic, "/api")) { - handleSet(String((char*)payload)); + String apireq = "win&"; + handleSet(apireq += (char*)payload)); } else { parseMQTTBriPayload((char*)payload); } } -void publishStatus() +void publishMQTT() { if (!mqtt.connected()) return; DEBUG_PRINTLN("Publish MQTT"); - char s[4]; - sprintf(s,"%ld", bri); - mqtt.publish(strcat(mqttTopic0, "/g") , s); - XML_response(false); - mqtt.publish(strcat(mqttTopic0, "/vs"), obuf); + char s[10]; + char subuf[38]; + + sprintf(s, "%ld", bri); + strcpy(subuf, mqttDeviceTopic); + strcat(subuf, "/g"); + mqtt.publish(subuf, s); + + sprintf(s, "#%X", white*16777216 + col[0]*65536 + col[1]*256 + col[2]); + strcpy(subuf, mqttDeviceTopic); + strcat(subuf, "/c"); + mqtt.publish(subuf, s); + + //if you want to use this, increase the MQTT buffer in PubSubClient.h to 350+ + //it will publish the API response to MQTT + /*XML_response(false); + strcpy(subuf, mqttDeviceTopic); + strcat(subuf, "/v"); + mqtt.publish(subuf, obuf);*/ } bool reconnectMQTT() @@ -53,26 +68,26 @@ bool reconnectMQTT() { //re-subscribe to required topics char subuf[38]; - strcpy(subuf, mqttTopic0); + strcpy(subuf, mqttDeviceTopic); - if (mqttTopic0[0] != 0) + if (mqttDeviceTopic[0] != 0) { - strcpy(subuf, mqttTopic0); + strcpy(subuf, mqttDeviceTopic); mqtt.subscribe(subuf); strcat(subuf, "/col"); mqtt.subscribe(subuf); - strcpy(subuf, mqttTopic0); + strcpy(subuf, mqttDeviceTopic); strcat(subuf, "/api"); mqtt.subscribe(subuf); } - if (mqttTopic1[0] != 0) + if (mqttGroupTopic[0] != 0) { - strcpy(subuf, mqttTopic1); + strcpy(subuf, mqttGroupTopic); mqtt.subscribe(subuf); strcat(subuf, "/col"); mqtt.subscribe(subuf); - strcpy(subuf, mqttTopic1); + strcpy(subuf, mqttGroupTopic); strcat(subuf, "/api"); mqtt.subscribe(subuf); } @@ -100,12 +115,20 @@ bool initMQTT() void handleMQTT() { if (WiFi.status() != WL_CONNECTED || !mqttInit) return; - if (!mqtt.connected() && millis() - lastMQTTReconnectAttempt > 5000) + + //every time connection is unsuccessful, the attempt interval is increased, since attempt will block program for 7 sec each time + if (!mqtt.connected() && millis() - lastMQTTReconnectAttempt > 5000 + (5000 * mqttFailedConAttempts * mqttFailedConAttempts)) { DEBUG_PRINTLN("Attempting to connect MQTT..."); lastMQTTReconnectAttempt = millis(); - if (!reconnectMQTT()) return; + if (!reconnectMQTT()) + { + //still attempt reconnect about once daily + if (mqttFailedConAttempts < 120) mqttFailedConAttempts++; + return; + } DEBUG_PRINTLN("MQTT con!"); + mqttFailedConAttempts = 0; } mqtt.loop(); } diff --git a/wled_logo.png b/wled_logo.png new file mode 100644 index 000000000..905c793f7 Binary files /dev/null and b/wled_logo.png differ