diff --git a/readme.md b/readme.md index 8225e21517..b6abc86f3b 100644 --- a/readme.md +++ b/readme.md @@ -3,22 +3,25 @@ WLED is a fast and (relatively) secure implementation of an ESP8266 webserver to control NeoPixel (WS2812B) LEDs! Now also with experimental ESP32 support. -### Features: (V0.5.0) +### Features: (V0.6.0) - RGB, HSB, and brightness sliders - Settings page - configuration over network - Access Point and station mode - automatic failsafe AP - WS2812FX library integrated for over 50 special effects! - Secondary color support lets you use even more effect combinations +- Alexa smart home device server (including dimming) +- Beta syncronization to Philips hue lights - Support for RGBW strips - 25 user presets! Save your favorite colors and effects and apply them easily! +- HTTP request API for simple integration +- Macro functions to automatically execute API calls - Nightlight function (gradually dims down) - Notifier function (multiple ESPs sync color via UDP broadcast) - Support for power pushbutton - Custom Theater Chase - Full OTA software update capability (HTTP and ArduinoOTA) - Password protected OTA page for added security (OTA lock) -- Alexa smart home device server (including dimming) -- NTP and experimental analog clock function +- NTP and configurable analog clock function - Support for the Cronixie Clock kit by Diamex - Realtime UDP Packet Control (WARLS) possible - Client HTML UI controlled, customizable themes diff --git a/wled00/WS2812FX.cpp b/wled00/WS2812FX.cpp index 7e60af38da..0d6958cee7 100644 --- a/wled00/WS2812FX.cpp +++ b/wled00/WS2812FX.cpp @@ -2040,12 +2040,17 @@ void WS2812FX::setBrightness(byte b) void WS2812FX::show() { #ifdef ARDUINO_ARCH_ESP32 + #ifdef WORKAROUND_ESP32_BITBANG delay(1); portDISABLE_INTERRUPTS(); //this is a workaround to prevent flickering (see https://github.com/adafruit/Adafruit_NeoPixel/issues/139) + #endif + #endif NeoPixelBrightnessBus::Show(); + + #ifdef ARDUINO_ARCH_ESP32 + #ifdef WORKAROUND_ESP32_BITBANG portENABLE_INTERRUPTS(); - #else - NeoPixelBrightnessBus::Show(); + #endif #endif } diff --git a/wled00/WS2812FX.h b/wled00/WS2812FX.h index 87755e46ef..047df7fd73 100644 --- a/wled00/WS2812FX.h +++ b/wled00/WS2812FX.h @@ -1,10 +1,16 @@ //#define RGBW #define PIN 2 //strip pin. Only change for ESP32 +#define WORKAROUND_ESP32_BITBANG +//see https://github.com/Aircoookie/WLED/issues/2 for flicker free ESP32 support //automatically uses the right driver method for each platform #ifdef ARDUINO_ARCH_ESP32 +#ifdef WORKAROUND_ESP32_BITBANG #define PIXELMETHOD NeoEsp32BitBangWs2813Method #else +#define PIXELMETHOD NeoEsp32RmtWS2813_V3Method +#endif +#else #define PIXELMETHOD NeoEsp8266Uart800KbpsMethod #endif diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 44368c827a..324a226d22 100644 Binary files a/wled00/data/settings_leds.htm and b/wled00/data/settings_leds.htm differ diff --git a/wled00/htmls01.h b/wled00/htmls01.h index 2bd7b7bdf9..54e0600013 100644 --- a/wled00/htmls01.h +++ b/wled00/htmls01.h @@ -117,6 +117,7 @@ Default Target brightness:

Advanced

Reverse LED order (rotate 180):
+Init LEDs after WiFi:
WARLS offset:
diff --git a/wled00/wled00.ino b/wled00/wled00.ino index b1de3ff703..10ea871d2e 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -33,7 +33,7 @@ #include "WS2812FX.h" //version in format yymmddb (b = daily build) -#define VERSION 1803144 +#define VERSION 1803146 const String versionString = "0.6.0"; //AP and OTA default passwords (change them!) @@ -74,6 +74,7 @@ IPAddress staticSubnet(255, 255, 255, 0); IPAddress staticDNS(8, 8, 8, 8); //only for NTP bool useHSB = false, useHSBDefault = false; bool turnOnAtBoot = true; +bool initLedsLast = false; byte bootPreset = 0; byte colS[]{255, 159, 0}; byte colSecS[]{0, 0, 0}; @@ -99,8 +100,7 @@ byte effectSpeedDefault = 75; byte effectIntensityDefault = 128; //NTP stuff bool ntpEnabled = false; -IPAddress ntpServerIP; -const char* ntpServerName = "0.wled.pool.ntp.org"; +String ntpServerName = "0.wled.pool.ntp.org"; //custom chase byte ccNumPrimary = 2; byte ccNumSecondary = 4; @@ -123,20 +123,13 @@ unsigned long countdownTime = 1514764800L; double transitionResolution = 0.011; //hue -long hueLastRequestSent = 0; bool huePollingEnabled = false, hueAttempt = false; uint16_t huePollIntervalMs = 2500; -uint32_t huePollIntervalMsTemp = 2500; String hueApiKey = "api"; byte huePollLightId = 1; IPAddress hueIP = (0,0,0,0); bool notifyHue = true; bool hueApplyOnOff = true, hueApplyBri = true, hueApplyColor = true; -String hueError = "Inactive"; -uint16_t hueFailCount = 0; -float hueXLast=0, hueYLast=0; -uint16_t hueHueLast=0, hueCtLast=0; -byte hueSatLast=0, hueBriLast=0; //Internal vars byte col[]{0, 0, 0}; @@ -176,15 +169,19 @@ String cssFont="Verdana"; String cssColorString=""; //NTP stuff bool ntpConnected = false; -unsigned int ntpLocalPort = 2390; -const uint16_t NTP_PACKET_SIZE = 48; -byte ntpPacketBuffer[NTP_PACKET_SIZE]; -unsigned long ntpLastSyncTime = 999000000L; -unsigned long ntpPacketSentTime = 999000000L; byte currentTimezone = 0; time_t local; int utcOffsetSecs = 0; +//hue +String hueError = "Inactive"; +uint16_t hueFailCount = 0; +float hueXLast=0, hueYLast=0; +uint16_t hueHueLast=0, hueCtLast=0; +byte hueSatLast=0, hueBriLast=0; +long hueLastRequestSent = 0; +uint32_t huePollIntervalMsTemp = huePollIntervalMs; + //overlay stuff byte overlayDefault = 0; byte overlayCurrent = 0; @@ -242,6 +239,12 @@ HTTPClient hueClient; ESP8266HTTPUpdateServer httpUpdater; WiFiUDP notifierUdp; WiFiUDP ntpUdp; +IPAddress ntpServerIP; +unsigned int ntpLocalPort = 2390; +const uint16_t NTP_PACKET_SIZE = 48; +byte ntpPacketBuffer[NTP_PACKET_SIZE]; +unsigned long ntpLastSyncTime = 999000000L; +unsigned long ntpPacketSentTime = 999000000L; WS2812FX strip = WS2812FX(LEDCOUNT); diff --git a/wled00/wled01_eeprom.ino b/wled00/wled01_eeprom.ino index 78d1aafb58..c91af4be07 100644 --- a/wled00/wled01_eeprom.ino +++ b/wled00/wled01_eeprom.ino @@ -6,13 +6,14 @@ #define EEPSIZE 3072 //eeprom Version code, enables default settings instead of 0 init on update -#define EEPVER 5 +#define EEPVER 6 //0 -> old version, default //1 -> 0.4p 1711272 and up //2 -> 0.4p 1711302 and up //3 -> 0.4 1712121 and up //4 -> 0.5.0 and up -//5 -> 0.6.0 and up +//5 -> 0.5.1 and up +//6 -> 0.6.0 and up //todo add settings void clearEEPROM() @@ -145,6 +146,7 @@ void saveSettingsToEEPROM() EEPROM.write(394, (abs(utcOffsetSecs) >> 0) & 0xFF); EEPROM.write(395, (abs(utcOffsetSecs) >> 8) & 0xFF); EEPROM.write(396, (utcOffsetSecs<0)); //is negative + EEPROM.write(397, initLedsLast); for (int k=0;k<6;k++){ int in = 900+k*8; @@ -380,6 +382,8 @@ void loadSettingsFromEEPROM(bool first) hueApplyBri = EEPROM.read(2104); hueApplyColor = EEPROM.read(2105); huePollLightId = EEPROM.read(2106); + } + if (lastEEPROMversion > 5) { overlayMin = EEPROM.read(2150); overlayMax = EEPROM.read(2151); analogClock12pixel = EEPROM.read(2152); @@ -415,6 +419,7 @@ void loadSettingsFromEEPROM(bool first) wifiLock = EEPROM.read(393); utcOffsetSecs = ((EEPROM.read(394) << 0) & 0xFF) + ((EEPROM.read(395) << 8) & 0xFF00); if (EEPROM.read(396)) utcOffsetSecs = -utcOffsetSecs; //negative + initLedsLast = EEPROM.read(397); //favorite setting memory (25 slots/ each 20byte) //400 - 899 reserved @@ -519,6 +524,7 @@ String loadMacro(byte index) if (EEPROM.read(i) == 0) break; m += char(EEPROM.read(i)); } + if (m.charAt(0) < 65 || m.charAt(0) > 90) return ""; //do simple check if macro is valid (capital first letter) return m; } diff --git a/wled00/wled02_xml.ino b/wled00/wled02_xml.ino index ee7039e1d5..a6cc53c3c0 100644 --- a/wled00/wled02_xml.ino +++ b/wled00/wled02_xml.ino @@ -166,6 +166,7 @@ String getSettings(byte subPage) resp += ds + "TL" + v + nightlightDelayMins +";"; resp += ds + "TW" + c + nightlightFade +";"; resp += ds + "RV" + c + reverseMode +";"; + resp += ds + "EI" + c + initLedsLast +";"; resp += ds + "WO" + v + arlsOffset +";"; } diff --git a/wled00/wled03_set.ino b/wled00/wled03_set.ino index 3800d6256c..5f84cebb74 100644 --- a/wled00/wled03_set.ino +++ b/wled00/wled03_set.ino @@ -231,6 +231,7 @@ void handleSettingsSet(byte subPage) } nightlightFade = server.hasArg("TW"); reverseMode = server.hasArg("RV"); + initLedsLast = server.hasArg("EI"); strip.setReverseMode(reverseMode); if (server.hasArg("WO")) { diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino index 2501762a6f..a0c66d8324 100644 --- a/wled00/wled05_init.ino +++ b/wled00/wled05_init.ino @@ -4,27 +4,19 @@ void wledInit() { + EEPROM.begin(EEPSIZE); + if (!EEPROM.read(397)) strip.init(); //quick init + Serial.begin(115200); - + #ifdef USEFS SPIFFS.begin(); - { - Dir dir = SPIFFS.openDir("/"); - while (dir.next()) { - String fileName = dir.fileName(); - size_t fileSize = dir.fileSize(); - #ifdef DEBUG - Serial.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str()); - #endif - } - DEBUG_PRINTF("\n"); - } #endif - DEBUG_PRINTLN("Init EEPROM"); - EEPROM.begin(EEPSIZE); + DEBUG_PRINTLN("Load EEPROM"); loadSettingsFromEEPROM(true); - DEBUG_PRINT("CC: SSID: "); + if (!initLedsLast) initStrip(); + DEBUG_PRINT("C-SSID: "); DEBUG_PRINT(clientSSID); buildCssColorString(); userBeginPreConnection(); @@ -140,7 +132,7 @@ void wledInit() }); server.on("/reset", HTTP_GET, [](){ - serveMessage(200,"Rebooting now...","(takes ~20 seconds, wait for auto-redirect)",139); + serveMessage(200,"Rebooting now...","(takes ~20 seconds, wait for auto-redirect)",79); reset(); }); @@ -301,10 +293,15 @@ void wledInit() ArduinoOTA.begin(); } + if (initLedsLast) initStrip(); userBegin(); + if (macroBoot>0) applyMacro(macroBoot); +} - // Initialize NeoPixel Strip - strip.init(); +void initStrip() +{ + // Initialize NeoPixel Strip and button + if (initLedsLast) strip.init(); strip.setLedCount(ledCount); strip.setReverseMode(reverseMode); strip.setColor(0); @@ -314,7 +311,6 @@ void wledInit() pinMode(buttonPin, INPUT_PULLUP); if (bootPreset>0) applyPreset(bootPreset, turnOnAtBoot, true, true); - if (macroBoot>0) applyMacro(macroBoot); colorUpdated(0); if(digitalRead(buttonPin) == LOW) buttonEnabled = false; //disable button if it is "pressed" unintentionally } @@ -331,17 +327,32 @@ void initCon() int fail_count = 0; if (clientSSID.length() <1 || clientSSID.equals("Your_Network")) fail_count = apWaitTimeSecs*2; WiFi.begin(clientSSID.c_str(), clientPass.c_str()); - while(WiFi.status() != WL_CONNECTED) { - delay(500); - DEBUG_PRINTLN("C_NC"); - fail_count++; - if (!recoveryAPDisabled && fail_count > apWaitTimeSecs*2) + unsigned long lastTry = 0; + bool con = false; + while(!con) + { + yield(); + if (!initLedsLast) { - WiFi.disconnect(); - DEBUG_PRINTLN("Can't connect. Opening AP..."); - onlyAP = true; - initAP(); - return; + handleTransitions(); + handleButton(); + handleOverlays(); + if (briT) strip.service(); + } + if (millis()-lastTry > 499) { + con = (WiFi.status() == WL_CONNECTED); + if (con) DEBUG_PRINTLN("rofl"); + lastTry = millis(); + DEBUG_PRINTLN("C_NC"); + if (!recoveryAPDisabled && fail_count > apWaitTimeSecs*2) + { + WiFi.disconnect(); + DEBUG_PRINTLN("Can't connect. Opening AP..."); + onlyAP = true; + initAP(); + return; + } + fail_count++; } } } diff --git a/wled00/wled07_notify.ino b/wled00/wled07_notify.ino index 3898e580a7..0a96ae220f 100644 --- a/wled00/wled07_notify.ino +++ b/wled00/wled07_notify.ino @@ -28,12 +28,14 @@ void notify(byte callMode, bool followUp=false) udpOut[8] = effectCurrent; udpOut[9] = effectSpeed; udpOut[10] = white; - udpOut[11] = 3; //compatibilityVersionByte: 0: old 1: supports white 2: supports secondary color 3: supports FX intensity, 24 byte packet + udpOut[11] = 4; //compatibilityVersionByte: 0: old 1: supports white 2: supports secondary color 3: supports FX intensity, 24 byte packet 4: supports transitionDelay udpOut[12] = colSec[0]; udpOut[13] = colSec[1]; udpOut[14] = colSec[2]; udpOut[15] = whiteSec; udpOut[16] = effectIntensity; + udpOut[17] = (transitionDelay >> 0) & 0xFF; + udpOut[18] = (transitionDelay >> 8) & 0xFF; IPAddress broadcastIp; broadcastIp = ~WiFi.subnetMask() | WiFi.gatewayIP(); diff --git a/wled00/wled10_ntp.ino b/wled00/wled10_ntp.ino index c9b5fd713b..c3224764f3 100644 --- a/wled00/wled10_ntp.ino +++ b/wled00/wled10_ntp.ino @@ -69,7 +69,8 @@ void handleNetworkTime() void sendNTPPacket() { - WiFi.hostByName(ntpServerName, ntpServerIP); + const char* ntpsrv = ntpServerName.c_str(); + WiFi.hostByName(ntpsrv, ntpServerIP); DEBUG_PRINTLN("send NTP packet"); memset(ntpPacketBuffer, 0, NTP_PACKET_SIZE); diff --git a/wled00/wled11_ol.ino b/wled00/wled11_ol.ino index a6a094fde8..1cdc9cddb6 100644 --- a/wled00/wled11_ol.ino +++ b/wled00/wled11_ol.ino @@ -118,19 +118,19 @@ void _nixieNumber(int number, int dur) void handleOverlays() { - if (overlayCurrent == 0) return; - if (millis() - overlayRefreshedTime > overlayRefreshMs) { initCronixie(); updateLocalTime(); switch (overlayCurrent) { + case 0: break;//no overlay case 1: _overlaySolid(); break;//solid secondary color case 2: _overlayAnalogClock(); break;//2 analog clock case 3: _overlayNixieClock(); break;//nixie 1-digit case 4: _overlayCronixie();//Diamex cronixie clock kit } + if (!countdownMode || overlayCurrent < 2) checkCountdown(); //countdown macro activation must work overlayRefreshedTime = millis(); } } diff --git a/wled00/wled15_hue.ino b/wled00/wled15_hue.ino index 6f3789b528..39ead60467 100644 --- a/wled00/wled15_hue.ino +++ b/wled00/wled15_hue.ino @@ -64,7 +64,7 @@ bool sendHuePoll(bool sAuth) st = false; } if (!st){ //error - if (hueFailCount<7) huePollIntervalMsTemp*=2; // only poll every 5min when unable to connect + if (huePollIntervalMsTemp<300000) huePollIntervalMsTemp*=2; // only poll every ~5min when unable to connect hueFailCount++; if (hueFailCount > 150) huePollingEnabled = false; //disable after many hours offline }