diff --git a/CHANGELOG.md b/CHANGELOG.md index 5090a4b..48406c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,29 @@ ### Development versions after the 0.10.2 release +#### Build 2009202 + +- Fixed LPD8806 compilation + +#### Build 2009201 + +- Added support for preset cycle toggling using CY=2 +- Added ESP32 touch pin support (#1190) +- Fixed modem sleep on ESP8266 (#1184) + +#### Build 2009200 + +- Increased available heap memory by 4kB +- Use F() macro for the majority of strings +- Restructure timezone code +- Restructured settings saved code +- Updated ArduinoJSON to 6.16.1 + +#### Build 2009170 + +- New WLED logo on Welcome screen (#1164) +- Fixed 170th pixel dark in E1.31 + #### Build 2009100 - Fixed sunrise mode not reinitializing diff --git a/platformio.ini b/platformio.ini index 77f0bc6..5504540 100644 --- a/platformio.ini +++ b/platformio.ini @@ -165,7 +165,8 @@ lib_extra_dirs = lib_compat_mode = strict lib_deps = FastLED@3.3.2 - NeoPixelBus@2.5.7 + #NeoPixelBus@2.5.7 + https://github.com/Makuna/NeoPixelBus ESPAsyncTCP@1.2.0 ESPAsyncUDP AsyncTCP@1.0.3 @@ -336,6 +337,14 @@ lib_ignore = ESPAsyncTCP ESPAsyncUDP +[env:custom32_TOUCHPIN_T0] +board = esp32dev +platform = espressif32@1.12.4 +build_flags = ${common.build_flags_esp32} -D TOUCHPIN=T0 +lib_ignore = + ESPAsyncTCP + ESPAsyncUDP + [env:wemos_shield_esp32] board = esp32dev platform = espressif32@1.12.4 diff --git a/platformio_override.ini.example b/platformio_override.ini.example index da02497..240c486 100644 --- a/platformio_override.ini.example +++ b/platformio_override.ini.example @@ -21,6 +21,7 @@ build_flags = ${common.build_flags_esp8266} ; PIN defines - uncomment and change, if needed: ; -D LEDPIN=2 ; -D BTNPIN=0 +; -D TOUCHPIN=T0 ; -D IR_PIN=4 ; -D RLYPIN=12 ; -D RLYMDE=1 diff --git a/readme.md b/readme.md index dd86013..2080fd4 100644 --- a/readme.md +++ b/readme.md @@ -72,7 +72,7 @@ WS2811 | 12v | 3-LED segments WS2815 | 12v | GS8208 | 12v | -## 🧊 Compatibe PC RGB Fans and ARGB accessories +## 🧊 Compatible PC RGB Fans and ARGB accessories Brand | Model | Comments |---|---|---| Corsair | HD120 Fan | Uses WS2812B, data-in only @@ -97,7 +97,7 @@ If WLED really brightens up your every day, you can [![](https://img.shields.io/ *Disclaimer:* -If you are sensitive to photoeleptic seizures it is not recommended that you use this software. +If you are sensitive to photosensitive epilepsy it is not recommended that you use this software. In case you still want to try, don't use strobe, lighting or noise modes or high effect speed settings. -As per the MIT license, i assume no liability for any damage to you or any other person or equipment. +As per the MIT license, I assume no liability for any damage to you or any other person or equipment. diff --git a/usermods/ESP32_TouchBrightnessControl/readme.md b/usermods/ESP32_TouchBrightnessControl/readme.md new file mode 100644 index 0000000..f210b33 --- /dev/null +++ b/usermods/ESP32_TouchBrightnessControl/readme.md @@ -0,0 +1,19 @@ +# ESP32 Touch Brightness Control + +Toggle On/Off with a long press (800ms) +Switch through 5 brightness levels (defined in usermod_touchbrightness.h, values 0-255) with a short (100ms) touch + +## Installation + +Copy 'usermod_touchbrightness.h' to the wled00 directory. +in 'usermod_list.cpp' add this: + +> #include "usermod_touchbrightness.h" +above "void registerUsermods()" + +and + +> usermods.add(new TouchBrightnessControl()); +inside the "registerUsermods()" function + + diff --git a/usermods/ESP32_TouchBrightnessControl/usermod_touchbrightness.h b/usermods/ESP32_TouchBrightnessControl/usermod_touchbrightness.h new file mode 100644 index 0000000..1b77959 --- /dev/null +++ b/usermods/ESP32_TouchBrightnessControl/usermod_touchbrightness.h @@ -0,0 +1,89 @@ +// +// usermod_touchbrightness.h +// github.com/aircoookie/WLED +// +// Created by Justin Kühner on 14.09.2020. +// Copyright © 2020 NeariX. All rights reserved. +// https://github.com/NeariX67/ +// Discord: @NeariX#4799 + + +#pragma once + +#include "wled.h" + +#define threshold 40 //Increase value if touches falsely accur. Decrease value if actual touches are not recognized +#define touchPin T0 //T0 = D4 / GPIO4 + +//Define the 5 brightness levels +//Long press to turn off / on +#define brightness1 51 +#define brightness2 102 +#define brightness3 153 +#define brightness4 204 +#define brightness5 255 + + +#ifdef ESP32 + + +class TouchBrightnessControl : public Usermod { + private: + unsigned long lastTime = 0; //Interval + unsigned long lastTouch = 0; //Timestamp of last Touch + unsigned long lastRelease = 0; //Timestamp of last Touch release + boolean released = true; //current Touch state (touched/released) + uint16_t touchReading = 0; //sensor reading, maybe use uint8_t??? + uint16_t touchDuration = 0; //duration of last touch + public: + + void setup() { + lastTouch = millis(); + lastRelease = millis(); + lastTime = millis(); + } + + void loop() { + if (millis() - lastTime >= 50) { //Check every 50ms if a touch occurs + lastTime = millis(); + touchReading = touchRead(touchPin); //Read touch sensor on pin T0 (GPIO4 / D4) + + if(touchReading < threshold && released) { //Touch started + released = false; + lastTouch = millis(); + } + else if(touchReading >= threshold && !released) { //Touch released + released = true; + lastRelease = millis(); + touchDuration = lastRelease - lastTouch; //Calculate duration + } + + //Serial.println(touchDuration); + + if(touchDuration >= 800 && released) { //Toggle power if button press is longer than 800ms + touchDuration = 0; //Reset touch duration to avoid multiple actions on same touch + toggleOnOff(); + colorUpdated(2); //Refresh values + } + else if(touchDuration >= 100 && released) { //Switch to next brightness if touch is between 100 and 800ms + touchDuration = 0; //Reset touch duration to avoid multiple actions on same touch + if(bri < brightness1) { + bri = brightness1; + } else if(bri >= brightness1 && bri < brightness2) { + bri = brightness2; + } else if(bri >= brightness2 && bri < brightness3) { + bri = brightness3; + } else if(bri >= brightness3 && bri < brightness4) { + bri = brightness4; + } else if(bri >= brightness4 && bri < brightness5) { + bri = brightness5; + } else if(bri >= brightness5) { + bri = brightness1; + } + colorUpdated(2); //Refresh values + } + + } + } +}; +#endif diff --git a/wled00/FX.h b/wled00/FX.h index 86238c2..3a1a99e 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -49,7 +49,11 @@ /* each segment uses 52 bytes of SRAM memory, so if you're application fails because of insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ -#define MAX_NUM_SEGMENTS 10 +#ifdef ESP8266 + #define MAX_NUM_SEGMENTS 10 +#else + #define MAX_NUM_SEGMENTS 10 +#endif /* How much data bytes all segments combined may allocate */ #ifdef ESP8266 diff --git a/wled00/NpbWrapper.h b/wled00/NpbWrapper.h index 2fa6ab4..dbb867b 100644 --- a/wled00/NpbWrapper.h +++ b/wled00/NpbWrapper.h @@ -21,6 +21,10 @@ #define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended) #endif +#ifndef TOUCHPIN +//#define TOUCHPIN T0 //touch pin. Behaves the same as button. ESP32 only. +#endif + #ifndef IR_PIN #define IR_PIN 4 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0 #endif @@ -138,6 +142,7 @@ #define PIXELFEATURE4 DotStarLbgrFeature #elif defined(USE_LPD8806) #define PIXELFEATURE3 Lpd8806GrbFeature + #define PIXELFEATURE4 Lpd8806GrbFeature #elif defined(USE_WS2801) #define PIXELFEATURE3 NeoRbgFeature #define PIXELFEATURE4 NeoRbgFeature diff --git a/wled00/button.cpp b/wled00/button.cpp index e71cce9..3c7b7f1 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -15,13 +15,24 @@ void shortPressAction() } } +bool isButtonPressed() +{ + #ifdef BTNPIN + if (digitalRead(BTNPIN) == LOW) return true; + #endif + #ifdef TOUCHPIN + if (touchRead(TOUCHPIN) <= TOUCH_THRESHOLD) return true; + #endif + return false; +} + void handleButton() { -#ifdef BTNPIN +#if defined(BTNPIN) || defined(TOUCHPIN) if (!buttonEnabled) return; - - if (digitalRead(BTNPIN) == LOW) //pressed + + if (isButtonPressed()) //pressed { if (!buttonPressedBefore) buttonPressedTime = millis(); buttonPressedBefore = true; @@ -37,7 +48,7 @@ void handleButton() } } } - else if (digitalRead(BTNPIN) == HIGH && buttonPressedBefore) //released + else if (!isButtonPressed() && buttonPressedBefore) //released { long dur = millis() - buttonPressedTime; if (dur < 50) {buttonPressedBefore = false; return;} //too short "press", debounce diff --git a/wled00/const.h b/wled00/const.h index d3a354b..73de807 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -104,6 +104,15 @@ #define SEG_OPTION_FREEZE 5 //Segment contents will not be refreshed #define SEG_OPTION_TRANSITIONAL 7 +// WLED Error modes +#define ERR_NONE 0 // All good :) +#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?) +#define ERR_JSON 9 // JSON parsing failed (input too large?) +#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?) +#define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached +#define ERR_FS_PLOAD 12 // It was attempted to load a preset that does not exist +#define ERR_FS_GENERAL 19 // A general unspecified filesystem error occured + //Timer mode types #define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness #define NL_MODE_FADE 1 //Fade to target brightness gradually @@ -126,12 +135,14 @@ #define ABL_MILLIAMPS_DEFAULT 850; // auto lower brightness to stay close to milliampere limit -// WLED Error modes -#define ERR_NONE 0 // All good :) -#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?) -#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?) -#define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached -#define ERR_FS_PLOAD 12 // It was attempted to load a preset that does not exist -#define ERR_FS_GENERAL 19 // A general unspecified filesystem error occured + +#define TOUCH_THRESHOLD 32 // limit to recognize a touch, higher value means more sensitive + +// Size of buffer for API JSON object (increase for more segments) +#ifdef ESP8266 + #define JSON_BUFFER_SIZE 9216 +#else + #define JSON_BUFFER_SIZE 16384 +#endif #endif diff --git a/wled00/e131.cpp b/wled00/e131.cpp index 7f67aad..2656f9e 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -137,14 +137,14 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){ uint16_t ledsInFirstUniverse = (MAX_CHANNELS_PER_UNIVERSE - DMXAddress) / 3; previousLeds = ledsInFirstUniverse + (previousUniverses - 1) * MAX_LEDS_PER_UNIVERSE; } - uint16_t ledsTotal = previousLeds + (dmxChannels - dmxOffset) / 3; + uint16_t ledsTotal = previousLeds + (dmxChannels - dmxOffset +1) / 3; for (uint16_t i = previousLeds; i < ledsTotal; i++) { setRealtimePixel(i, e131_data[dmxOffset++], e131_data[dmxOffset++], e131_data[dmxOffset++], 0); } break; } default: - DEBUG_PRINTLN("unknown E1.31 DMX mode"); + DEBUG_PRINTLN(F("unknown E1.31 DMX mode")); return; // nothing to do break; } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index bdfc6ef..eb8ec87 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -21,6 +21,7 @@ void updateBlynk(); //button.cpp void shortPressAction(); +bool isButtonPressed(); void handleButton(); void handleIO(); @@ -197,7 +198,7 @@ bool applyPreset(byte index, bool loadBri = true); void savePreset(byte index, bool persist = true, const char* pname = nullptr, byte prio = 50, JsonObject saveobj = JsonObject()); void loadMacro(byte index, char* m); void applyMacro(byte index); -void saveMacro(byte index, String mc, bool persist = true); //only commit on single save, not in settings +void saveMacro(byte index, const String& mc, bool persist = true); //only commit on single save, not in settings //wled_serial.cpp void handleSerial(); @@ -209,10 +210,10 @@ void initServer(); void serveIndexOrWelcome(AsyncWebServerRequest *request); void serveIndex(AsyncWebServerRequest* request); String msgProcessor(const String& var); -void serveMessage(AsyncWebServerRequest* request, uint16_t code, String headl, String subl="", byte optionT=255); +void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& headl, const String& subl="", byte optionT=255); String settingsProcessor(const String& var); String dmxProcessor(const String& var); -void serveSettings(AsyncWebServerRequest* request); +void serveSettings(AsyncWebServerRequest* request, bool post = false); //ws.cpp void handleWs(); diff --git a/wled00/hue.cpp b/wled00/hue.cpp index 77091f6..607aa9a 100644 --- a/wled00/hue.cpp +++ b/wled00/hue.cpp @@ -34,7 +34,7 @@ void handleHue() void reconnectHue() { if (!WLED_CONNECTED || !huePollingEnabled) return; - DEBUG_PRINTLN("Hue reconnect"); + DEBUG_PRINTLN(F("Hue reconnect")); if (hueClient == nullptr) { hueClient = new AsyncClient(); hueClient->onConnect(&onHueConnect, hueClient); @@ -47,13 +47,13 @@ void reconnectHue() void onHueError(void* arg, AsyncClient* client, int8_t error) { - DEBUG_PRINTLN("Hue err"); + DEBUG_PRINTLN(F("Hue err")); hueError = HUE_ERROR_TIMEOUT; } void onHueConnect(void* arg, AsyncClient* client) { - DEBUG_PRINTLN("Hue connect"); + DEBUG_PRINTLN(F("Hue connect")); sendHuePoll(); } @@ -68,9 +68,10 @@ void sendHuePoll() req += F("\r\nContent-Length: 25\r\n\r\n{\"devicetype\":\"wled#esp\"}"); } else { - req += "GET /api/"; + req += F("GET /api/"); req += hueApiKey; - req += "/lights/" + String(huePollLightId); + req += F("/lights/"); + req += String(huePollLightId); req += F(" HTTP/1.1\r\nHost: "); req += hueIP.toString(); req += "\r\n\r\n"; @@ -100,7 +101,7 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len) hueError = HUE_ERROR_JSON_PARSING; return; } - int hueErrorCode = root[0]["error"]["type"]; + int hueErrorCode = root[0][F("error")][F("type")]; if (hueErrorCode)//hue bridge returned error { hueError = hueErrorCode; @@ -115,7 +116,7 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len) if (hueAuthRequired) { - const char* apikey = root[0]["success"]["username"]; + const char* apikey = root[0][F("success")][F("username")]; if (apikey != nullptr && strlen(apikey) < sizeof(hueApiKey)) { strcpy(hueApiKey, apikey); @@ -146,10 +147,10 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len) { hueBri = root["bri"]; hueBri++; - const char* cm =root["colormode"]; + const char* cm =root[F("colormode")]; if (cm != nullptr) //Color device { - if (strstr(cm,"ct") != nullptr) //ct mode + if (strstr(cm,("ct")) != nullptr) //ct mode { hueCt = root["ct"]; hueColormode = 3; @@ -160,8 +161,8 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len) hueColormode = 1; } else //hs mode { - hueHue = root["hue"]; - hueSat = root["sat"]; + hueHue = root[F("hue")]; + hueSat = root[F("sat")]; hueColormode = 2; } } diff --git a/wled00/json.cpp b/wled00/json.cpp index 8239e0e..8e41023 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -6,19 +6,19 @@ void deserializeSegment(JsonObject elem, byte it) { - byte id = elem["id"] | it; + byte id = elem[F("id")] | it; if (id < strip.getMaxSegments()) { WS2812FX::Segment& seg = strip.getSegment(id); - uint16_t start = elem["start"] | seg.start; - int stop = elem["stop"] | -1; + uint16_t start = elem[F("start")] | seg.start; + int stop = elem[F("stop")] | -1; if (stop < 0) { - uint16_t len = elem["len"]; + uint16_t len = elem[F("len")]; stop = (len > 0) ? start + len : seg.stop; } - uint16_t grp = elem["grp"] | seg.grouping; - uint16_t spc = elem["spc"] | seg.spacing; + uint16_t grp = elem[F("grp")] | seg.grouping; + uint16_t spc = elem[F("spc")] | seg.spacing; strip.setSegment(id, start, stop, grp, spc); int segbri = elem["bri"] | -1; @@ -31,7 +31,7 @@ void deserializeSegment(JsonObject elem, byte it) seg.setOption(SEG_OPTION_ON, elem["on"] | seg.getOption(SEG_OPTION_ON)); - JsonArray colarr = elem["col"]; + JsonArray colarr = elem[F("col")]; if (!colarr.isNull()) { for (uint8_t i = 0; i < 3; i++) @@ -57,25 +57,25 @@ void deserializeSegment(JsonObject elem, byte it) } //if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal); - seg.setOption(SEG_OPTION_SELECTED, elem["sel"] | seg.getOption(SEG_OPTION_SELECTED)); - seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED)); - seg.setOption(SEG_OPTION_MIRROR , elem["mi"] | seg.getOption(SEG_OPTION_MIRROR )); + seg.setOption(SEG_OPTION_SELECTED, elem[F("sel")] | seg.getOption(SEG_OPTION_SELECTED)); + seg.setOption(SEG_OPTION_REVERSED, elem[F("rev")] | seg.getOption(SEG_OPTION_REVERSED)); + seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR )); //temporary, strip object gets updated via colorUpdated() if (id == strip.getMainSegmentId()) { - effectCurrent = elem["fx"] | effectCurrent; - effectSpeed = elem["sx"] | effectSpeed; - effectIntensity = elem["ix"] | effectIntensity; - effectPalette = elem["pal"] | effectPalette; + effectCurrent = elem[F("fx")] | effectCurrent; + effectSpeed = elem[F("sx")] | effectSpeed; + effectIntensity = elem[F("ix")] | effectIntensity; + effectPalette = elem[F("pal")] | effectPalette; } else { //permanent - byte fx = elem["fx"] | seg.mode; + byte fx = elem[F("fx")] | seg.mode; if (fx != seg.mode && fx < strip.getModeCount()) strip.setMode(id, fx); - seg.speed = elem["sx"] | seg.speed; - seg.intensity = elem["ix"] | seg.intensity; - seg.palette = elem["pal"] | seg.palette; + seg.speed = elem[F("sx")] | seg.speed; + seg.intensity = elem[F("ix")] | seg.intensity; + seg.palette = elem[F("pal")] | seg.palette; } - JsonArray iarr = elem["i"]; //set individual LEDs + JsonArray iarr = elem[F("i")]; //set individual LEDs if (!iarr.isNull()) { strip.setPixelSegment(id); @@ -127,9 +127,9 @@ void deserializeSegment(JsonObject elem, byte it) bool deserializeState(JsonObject root) { strip.applyToAllSelected = false; - bool stateResponse = root["v"] | false; + bool stateResponse = root[F("v")] | false; - int ps = root["ps"] | -1; + int ps = root[F("ps")] | -1; if (ps >= 0) applyPreset(ps); bri = root["bri"] | bri; @@ -137,14 +137,14 @@ bool deserializeState(JsonObject root) bool on = root["on"] | (bri > 0); if (!on != !bri) toggleOnOff(); - int tr = root["transition"] | -1; + int tr = root[F("transition")] | -1; if (tr >= 0) { transitionDelay = tr; transitionDelay *= 100; } - tr = root["tt"] | -1; + tr = root[F("tt")] | -1; if (tr >= 0) { transitionDelayTemp = tr; @@ -152,42 +152,42 @@ bool deserializeState(JsonObject root) jsonTransitionOnce = true; } - int cy = root["pl"] | -2; + int cy = root[F("pl")] | -2; if (cy > -2) presetCyclingEnabled = (cy >= 0); - JsonObject ccnf = root["ccnf"]; - presetCycleMin = ccnf["min"] | presetCycleMin; - presetCycleMax = ccnf["max"] | presetCycleMax; - tr = ccnf["time"] | -1; + JsonObject ccnf = root[F("ccnf")]; + presetCycleMin = ccnf[F("min")] | presetCycleMin; + presetCycleMax = ccnf[F("max")] | presetCycleMax; + tr = ccnf[F("time")] | -1; if (tr >= 2) presetCycleTime = tr; - JsonObject nl = root["nl"]; + JsonObject nl = root[F("nl")]; nightlightActive = nl["on"] | nightlightActive; - nightlightDelayMins = nl["dur"] | nightlightDelayMins; - nightlightMode = nl["fade"] | nightlightMode; //deprecated - nightlightMode = nl["mode"] | nightlightMode; - nightlightTargetBri = nl["tbri"] | nightlightTargetBri; + nightlightDelayMins = nl[F("dur")] | nightlightDelayMins; + nightlightMode = nl[F("fade")] | nightlightMode; //deprecated + nightlightMode = nl[F("mode")] | nightlightMode; + nightlightTargetBri = nl[F("tbri")] | nightlightTargetBri; - JsonObject udpn = root["udpn"]; - notifyDirect = udpn["send"] | notifyDirect; - receiveNotifications = udpn["recv"] | receiveNotifications; - bool noNotification = udpn["nn"]; //send no notification just for this request + JsonObject udpn = root[F("udpn")]; + notifyDirect = udpn[F("send")] | notifyDirect; + receiveNotifications = udpn[F("recv")] | receiveNotifications; + bool noNotification = udpn[F("nn")]; //send no notification just for this request - int timein = root["time"] | -1; + int timein = root[F("time")] | -1; if (timein != -1) setTime(timein); - doReboot = root["rb"] | doReboot; + doReboot = root[F("rb")] | doReboot; - realtimeOverride = root["lor"] | realtimeOverride; + realtimeOverride = root[F("lor")] | realtimeOverride; if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS; byte prevMain = strip.getMainSegmentId(); - strip.mainSegment = root["mainseg"] | prevMain; + strip.mainSegment = root[F("mainseg")] | prevMain; if (strip.getMainSegmentId() != prevMain) setValuesFromMainSeg(); int it = 0; - JsonVariant segVar = root["seg"]; + JsonVariant segVar = root[F("seg")]; if (segVar.is()) { - int id = segVar["id"] | -1; + int id = segVar[F("id")] | -1; if (id < 0) { //set all selected segments bool didSet = false; @@ -222,9 +222,9 @@ bool deserializeState(JsonObject root) colorUpdated(noNotification ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE); //write presets to flash directly? - bool persistSaves = !(root["np"] | false); + bool persistSaves = !(root[F("np")] | false); - ps = root["psave"] | -1; + ps = root[F("psave")] | -1; if (ps >= 0) savePreset(ps, persistSaves, root["n"], root["p"] | 50, root["o"].as()); return stateResponse; @@ -232,12 +232,12 @@ bool deserializeState(JsonObject root) void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool forPreset) { - root["id"] = id; - root["start"] = seg.start; - root["stop"] = seg.stop; - if (!forPreset) root["len"] = seg.stop - seg.start; - root["grp"] = seg.grouping; - root["spc"] = seg.spacing; + root[F("id")] = id; + root[F("start")] = seg.start; + root[F("stop")] = seg.stop; + if (!forPreset) root[F("len")] = seg.stop - seg.start; + root[F("grp")] = seg.grouping; + root[F("spc")] = seg.spacing; root["on"] = seg.getOption(SEG_OPTION_ON); byte segbri = seg.opacity; root["bri"] = (segbri) ? segbri : 255; @@ -263,52 +263,52 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo } } - root["fx"] = seg.mode; - root["sx"] = seg.speed; - root["ix"] = seg.intensity; - root["pal"] = seg.palette; - root["sel"] = seg.isSelected(); - root["rev"] = seg.getOption(SEG_OPTION_REVERSED); - root["mi"] = seg.getOption(SEG_OPTION_MIRROR); + root[F("fx")] = seg.mode; + root[F("sx")] = seg.speed; + root[F("ix")] = seg.intensity; + root[F("pal")] = seg.palette; + root[F("sel")] = seg.isSelected(); + root[F("rev")] = seg.getOption(SEG_OPTION_REVERSED); + root[F("mi")] = seg.getOption(SEG_OPTION_MIRROR); } - void serializeState(JsonObject root, bool forPreset) { + if (errorFlag) root[F("error")] = errorFlag; root["on"] = (bri > 0); root["bri"] = briLast; - root["transition"] = transitionDelay/100; //in 100ms + root[F("transition")] = transitionDelay/100; //in 100ms if (!forPreset) { if (errorFlag) root["error"] = errorFlag; - - root["ps"] = currentPreset; - root["pss"] = savedPresets; - root["pl"] = (presetCyclingEnabled) ? 0: -1; - + + root[F("ps")] = currentPreset; + root[F("pss")] = savedPresets; + root[F("pl")] = (presetCyclingEnabled) ? 0: -1; + usermods.addToJsonState(root); //temporary for preset cycle JsonObject ccnf = root.createNestedObject("ccnf"); - ccnf["min"] = presetCycleMin; - ccnf["max"] = presetCycleMax; - ccnf["time"] = presetCycleTime; - + ccnf[F("min")] = presetCycleMin; + ccnf[F("max")] = presetCycleMax; + ccnf[F("time")] = presetCycleTime; + JsonObject nl = root.createNestedObject("nl"); nl["on"] = nightlightActive; - nl["dur"] = nightlightDelayMins; - nl["fade"] = (nightlightMode > NL_MODE_SET); //deprecated - nl["mode"] = nightlightMode; - nl["tbri"] = nightlightTargetBri; - - JsonObject udpn = root.createNestedObject("udpn"); - udpn["send"] = notifyDirect; - udpn["recv"] = receiveNotifications; + nl[F("dur")] = nightlightDelayMins; + nl[F("fade")] = (nightlightMode > NL_MODE_SET); //deprecated + nl[F("mode")] = nightlightMode; + nl[F("tbri")] = nightlightTargetBri; - root["lor"] = realtimeOverride; + JsonObject udpn = root.createNestedObject("udpn"); + udpn[F("send")] = notifyDirect; + udpn[F("recv")] = receiveNotifications; + + root[F("lor")] = realtimeOverride; } - root["mainseg"] = strip.getMainSegmentId(); + root[F("mainseg")] = strip.getMainSegmentId(); JsonArray seg = root.createNestedArray("seg"); for (byte s = 0; s < strip.getMaxSegments(); s++) @@ -344,61 +344,62 @@ int getSignalQuality(int rssi) void serializeInfo(JsonObject root) { - root["ver"] = versionString; - root["vid"] = VERSION; - //root["cn"] = WLED_CODENAME; + root[F("ver")] = versionString; + root[F("vid")] = VERSION; + //root[F("cn")] = WLED_CODENAME; JsonObject leds = root.createNestedObject("leds"); - leds["count"] = ledCount; - leds["rgbw"] = useRGBW; - leds["wv"] = useRGBW && (strip.rgbwMode == RGBW_MODE_MANUAL_ONLY || strip.rgbwMode == RGBW_MODE_DUAL); //should a white channel slider be displayed? + leds[F("count")] = ledCount; + leds[F("rgbw")] = useRGBW; + leds[F("wv")] = useRGBW && (strip.rgbwMode == RGBW_MODE_MANUAL_ONLY || strip.rgbwMode == RGBW_MODE_DUAL); //should a white channel slider be displayed? JsonArray leds_pin = leds.createNestedArray("pin"); leds_pin.add(LEDPIN); - leds["pwr"] = strip.currentMilliamps; - leds["maxpwr"] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0; - leds["maxseg"] = strip.getMaxSegments(); - leds["seglock"] = false; //will be used in the future to prevent modifications to segment config + leds[F("pwr")] = strip.currentMilliamps; + leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0; + leds[F("maxseg")] = strip.getMaxSegments(); + leds[F("seglock")] = false; //will be used in the future to prevent modifications to segment config - root["str"] = syncToggleReceive; + root[F("str")] = syncToggleReceive; - root["name"] = serverDescription; - root["udpport"] = udpPort; - root["live"] = (bool)realtimeMode; + root[F("name")] = serverDescription; + root[F("udpport")] = udpPort; + root[F("live")] = (bool)realtimeMode; switch (realtimeMode) { case REALTIME_MODE_INACTIVE: root["lm"] = ""; break; case REALTIME_MODE_GENERIC: root["lm"] = ""; break; - case REALTIME_MODE_UDP: root["lm"] = "UDP"; break; - case REALTIME_MODE_HYPERION: root["lm"] = "Hyperion"; break; - case REALTIME_MODE_E131: root["lm"] = "E1.31"; break; + case REALTIME_MODE_UDP: root["lm"] = F("UDP"); break; + case REALTIME_MODE_HYPERION: root["lm"] = F("Hyperion"); break; + case REALTIME_MODE_E131: root["lm"] = F("E1.31"); break; case REALTIME_MODE_ADALIGHT: root["lm"] = F("USB Adalight/TPM2"); break; - case REALTIME_MODE_ARTNET: root["lm"] = "Art-Net"; break; + case REALTIME_MODE_ARTNET: root["lm"] = F("Art-Net"); break; case REALTIME_MODE_TPM2NET: root["lm"] = F("tpm2.net"); break; } if (realtimeIP[0] == 0) { - root["lip"] = ""; + root[F("lip")] = ""; } else { - root["lip"] = realtimeIP.toString(); + root[F("lip")] = realtimeIP.toString(); } #ifdef WLED_ENABLE_WEBSOCKETS - root["ws"] = ws.count(); + root[F("ws")] = ws.count(); #else - root["ws"] = -1; + root[F("ws")] = -1; #endif - root["fxcount"] = strip.getModeCount(); - root["palcount"] = strip.getPaletteCount(); + root[F("fxcount")] = strip.getModeCount(); + root[F("palcount")] = strip.getPaletteCount(); JsonObject wifi_info = root.createNestedObject("wifi"); - wifi_info["bssid"] = WiFi.BSSIDstr(); + wifi_info[F("bssid")] = WiFi.BSSIDstr(); int qrssi = WiFi.RSSI(); - wifi_info["rssi"] = qrssi; - wifi_info["signal"] = getSignalQuality(qrssi); - wifi_info["channel"] = WiFi.channel(); + + wifi_info[F("rssi")] = qrssi; + wifi_info[F("signal")] = getSignalQuality(qrssi); + wifi_info[F("channel")] = WiFi.channel(); JsonObject fs_info = root.createNestedObject("fs"); FSInfo fsi; @@ -408,30 +409,31 @@ void serializeInfo(JsonObject root) #ifdef ARDUINO_ARCH_ESP32 #ifdef WLED_DEBUG - wifi_info["txPower"] = (int) WiFi.getTxPower(); - wifi_info["sleep"] = (bool) WiFi.getSleep(); + wifi_info[F("txPower")] = (int) WiFi.getTxPower(); + wifi_info[F("sleep")] = (bool) WiFi.getSleep(); #endif - root["arch"] = "esp32"; - root["core"] = ESP.getSdkVersion(); - //root["maxalloc"] = ESP.getMaxAllocHeap(); + root[F("arch")] = "esp32"; + root[F("core")] = ESP.getSdkVersion(); + //root[F("maxalloc")] = ESP.getMaxAllocHeap(); #ifdef WLED_DEBUG - root["resetReason0"] = (int)rtc_get_reset_reason(0); - root["resetReason1"] = (int)rtc_get_reset_reason(1); + root[F("resetReason0")] = (int)rtc_get_reset_reason(0); + root[F("resetReason1")] = (int)rtc_get_reset_reason(1); #endif - root["lwip"] = 0; + root[F("lwip")] = 0; #else - root["arch"] = "esp8266"; - root["core"] = ESP.getCoreVersion(); - //root["maxalloc"] = ESP.getMaxFreeBlockSize(); + root[F("arch")] = "esp8266"; + root[F("core")] = ESP.getCoreVersion(); + //root[F("maxalloc")] = ESP.getMaxFreeBlockSize(); #ifdef WLED_DEBUG - root["resetReason"] = (int)ESP.getResetInfoPtr()->reason; + root[F("resetReason")] = (int)ESP.getResetInfoPtr()->reason; #endif - root["lwip"] = LWIP_VERSION_MAJOR; + root[F("lwip")] = LWIP_VERSION_MAJOR; #endif - root["freeheap"] = ESP.getFreeHeap(); - root["uptime"] = millis()/1000 + rolloverMillis*4294967; + root[F("freeheap")] = ESP.getFreeHeap(); + root[F("uptime")] = millis()/1000 + rolloverMillis*4294967; + usermods.addToJsonInfo(root); byte os = 0; @@ -459,11 +461,11 @@ void serializeInfo(JsonObject root) #ifndef WLED_DISABLE_OTA os += 0x01; #endif - root["opt"] = os; + root[F("opt")] = os; - root["brand"] = "WLED"; - root["product"] = "FOSS"; - root["mac"] = escapedMac; + root[F("brand")] = "WLED"; + root[F("product")] = F("FOSS"); + root[F("mac")] = escapedMac; } void serveJson(AsyncWebServerRequest* request) @@ -477,11 +479,11 @@ void serveJson(AsyncWebServerRequest* request) serveLiveLeds(request); return; } - else if (url.indexOf("eff") > 0) { + else if (url.indexOf(F("eff")) > 0) { request->send_P(200, "application/json", JSON_mode_names); return; } - else if (url.indexOf("pal") > 0) { + else if (url.indexOf(F("pal")) > 0) { request->send_P(200, "application/json", JSON_palette_names); return; } @@ -490,7 +492,7 @@ void serveJson(AsyncWebServerRequest* request) return; } - AsyncJsonResponse* response = new AsyncJsonResponse(); + AsyncJsonResponse* response = new AsyncJsonResponse(JSON_BUFFER_SIZE); JsonObject doc = response->getRoot(); switch (subJson) @@ -506,8 +508,8 @@ void serveJson(AsyncWebServerRequest* request) serializeInfo(info); if (subJson != 3) { - doc["effects"] = serialized((const __FlashStringHelper*)JSON_mode_names); - doc["palettes"] = serialized((const __FlashStringHelper*)JSON_palette_names); + doc[F("effects")] = serialized((const __FlashStringHelper*)JSON_mode_names); + doc[F("palettes")] = serialized((const __FlashStringHelper*)JSON_palette_names); } } @@ -529,7 +531,8 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient) uint16_t used = ledCount; uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS - char buffer[2000] = "{\"leds\":["; + char buffer[2000]; + strcpy_P(buffer, PSTR("{\"leds\":[")); obuf = buffer; olen = 9; @@ -538,7 +541,7 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient) olen += sprintf(obuf + olen, "\"%06X\",", strip.getPixelColor(i)); } olen -= 1; - oappend("],\"n\":"); + oappend((const char*)F("],\"n\":")); oappendi(n); oappend("}"); if (request) { diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index 7234297..6d8a3b9 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -48,18 +48,18 @@ void onMqttConnect(bool sessionPresent) } doPublishMqtt = true; - DEBUG_PRINTLN("MQTT ready"); + DEBUG_PRINTLN(F("MQTT ready")); } void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { - DEBUG_PRINT("MQTT msg: "); + DEBUG_PRINT(F("MQTT msg: ")); DEBUG_PRINTLN(topic); // paranoia check to avoid npe if no payload if (payload==nullptr) { - DEBUG_PRINTLN("no payload -> leave"); + DEBUG_PRINTLN(F("no payload -> leave")); return; } DEBUG_PRINTLN(payload); @@ -83,7 +83,7 @@ void publishMqtt() { doPublishMqtt = false; if (!WLED_MQTT_CONNECTED) return; - DEBUG_PRINTLN("Publish MQTT"); + DEBUG_PRINTLN(F("Publish MQTT")); char s[10]; char subuf[38]; @@ -100,7 +100,7 @@ void publishMqtt() strcpy(subuf, mqttDeviceTopic); strcat(subuf, "/status"); - mqtt->publish(subuf, 0, true, "online"); + mqtt->publish(subuf, 0, true, (const char*)F("online")); char apires[1024]; XML_response(nullptr, apires); @@ -124,7 +124,7 @@ bool initMqtt() } if (mqtt->connected()) return true; - DEBUG_PRINTLN("Reconnecting MQTT"); + DEBUG_PRINTLN(F("Reconnecting MQTT")); IPAddress mqttIP; if (mqttIP.fromString(mqttServer)) //see if server is IP or domain { @@ -137,7 +137,7 @@ bool initMqtt() strcpy(mqttStatusTopic, mqttDeviceTopic); strcat(mqttStatusTopic, "/status"); - mqtt->setWill(mqttStatusTopic, 0, true, "offline"); + mqtt->setWill(mqttStatusTopic, 0, true, (const char*)F("offline")); mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME); mqtt->connect(); return true; diff --git a/wled00/ntp.cpp b/wled00/ntp.cpp index 5a79629..51d52d9 100644 --- a/wled00/ntp.cpp +++ b/wled00/ntp.cpp @@ -4,69 +4,127 @@ /* * Acquires time from NTP server */ +Timezone* tz; -TimeChangeRule UTCr = {Last, Sun, Mar, 1, 0}; // UTC -Timezone tzUTC(UTCr, UTCr); +#define TZ_UTC 0 +#define TZ_UK 1 +#define TZ_EUROPE_CENTRAL 2 +#define TZ_EUROPE_EASTERN 3 +#define TZ_US_EASTERN 4 +#define TZ_US_CENTRAL 5 +#define TZ_US_MOUNTAIN 6 +#define TZ_US_ARIZONA 7 +#define TZ_US_PACIFIC 8 +#define TZ_CHINA 9 +#define TZ_JAPAN 10 +#define TZ_AUSTRALIA_EASTERN 11 +#define TZ_NEW_ZEALAND 12 +#define TZ_NORTH_KOREA 13 +#define TZ_INDIA 14 +#define TZ_SASKACHEWAN 15 +#define TZ_AUSTRALIA_NORTHERN 16 +#define TZ_AUSTRALIA_SOUTHERN 17 +#define TZ_INIT 255 -TimeChangeRule BST = {Last, Sun, Mar, 1, 60}; // British Summer Time -TimeChangeRule GMT = {Last, Sun, Oct, 2, 0}; // Standard Time -Timezone tzUK(BST, GMT); +byte tzCurrent = TZ_INIT; //uninitialized -TimeChangeRule CEST = {Last, Sun, Mar, 2, 120}; //Central European Summer Time -TimeChangeRule CET = {Last, Sun, Oct, 3, 60}; //Central European Standard Time -Timezone tzEUCentral(CEST, CET); +void updateTimezone() { + delete tz; + TimeChangeRule tcrDaylight = {Last, Sun, Mar, 1, 0}; //UTC + TimeChangeRule tcrStandard = tcrDaylight; //UTC -TimeChangeRule EEST = {Last, Sun, Mar, 3, 180}; //Central European Summer Time -TimeChangeRule EET = {Last, Sun, Oct, 4, 120}; //Central European Standard Time -Timezone tzEUEastern(EEST, EET); + switch (currentTimezone) { + case TZ_UK : { + tcrDaylight = {Last, Sun, Mar, 1, 60}; //British Summer Time + tcrStandard = {Last, Sun, Oct, 2, 0}; //Standard Time + break; + } + case TZ_EUROPE_CENTRAL : { + tcrDaylight = {Last, Sun, Mar, 2, 120}; //Central European Summer Time + tcrStandard = {Last, Sun, Oct, 3, 60}; //Central European Standard Time + break; + } + case TZ_EUROPE_EASTERN : { + tcrDaylight = {Last, Sun, Mar, 3, 180}; //East European Summer Time + tcrStandard = {Last, Sun, Oct, 4, 120}; //East European Standard Time + break; + } + case TZ_US_EASTERN : { + tcrDaylight = {Second, Sun, Mar, 2, -240}; //EDT = UTC - 4 hours + tcrStandard = {First, Sun, Nov, 2, -300}; //EST = UTC - 5 hours + break; + } + case TZ_US_CENTRAL : { + tcrDaylight = {Second, Sun, Mar, 2, -300}; //CDT = UTC - 5 hours + tcrStandard = {First, Sun, Nov, 2, -360}; //CST = UTC - 6 hours + break; + } + case TZ_US_MOUNTAIN : { + tcrDaylight = {Second, Sun, Mar, 2, -360}; //MDT = UTC - 6 hours + tcrStandard = {First, Sun, Nov, 2, -420}; //MST = UTC - 7 hours + break; + } + case TZ_US_ARIZONA : { + tcrDaylight = {First, Sun, Nov, 2, -420}; //MST = UTC - 7 hours + tcrStandard = {First, Sun, Nov, 2, -420}; //MST = UTC - 7 hours + break; + } + case TZ_US_PACIFIC : { + tcrDaylight = {Second, Sun, Mar, 2, -420}; //PDT = UTC - 7 hours + tcrStandard = {First, Sun, Nov, 2, -480}; //PST = UTC - 8 hours + break; + } + case TZ_CHINA : { + tcrDaylight = {Last, Sun, Mar, 1, 480}; //CST = UTC + 8 hours + tcrStandard = tcrDaylight; + break; + } + case TZ_JAPAN : { + tcrDaylight = {Last, Sun, Mar, 1, 540}; //JST = UTC + 9 hours + tcrStandard = tcrDaylight; + break; + } + case TZ_AUSTRALIA_EASTERN : { + tcrDaylight = {Second, Sun, Oct, 2, 660}; //AEDT = UTC + 11 hours + tcrStandard = {First, Sun, Apr, 3, 600}; //AEST = UTC + 10 hours + break; + } + case TZ_NEW_ZEALAND : { + tcrDaylight = {Second, Sun, Sep, 2, 780}; //NZDT = UTC + 13 hours + tcrStandard = {First, Sun, Apr, 3, 720}; //NZST = UTC + 12 hours + break; + } + case TZ_NORTH_KOREA : { + tcrDaylight = {Last, Sun, Mar, 1, 510}; //Pyongyang Time = UTC + 8.5 hours + tcrStandard = tcrDaylight; + break; + } + case TZ_INDIA : { + tcrDaylight = {Last, Sun, Mar, 1, 330}; //India Standard Time = UTC + 5.5 hours + tcrStandard = tcrDaylight; + break; + } + case TZ_SASKACHEWAN : { + tcrDaylight = {First, Sun, Nov, 2, -360}; //CST = UTC - 6 hours + tcrStandard = tcrDaylight; + break; + } + case TZ_AUSTRALIA_NORTHERN : { + tcrStandard = {First, Sun, Apr, 3, 570}; //ACST = UTC + 9.5 hours + tcrStandard = tcrDaylight; + break; + } + case TZ_AUSTRALIA_SOUTHERN : { + tcrDaylight = {First, Sun, Oct, 2, 630}; //ACDT = UTC + 10.5 hours + tcrStandard = {First, Sun, Apr, 3, 570}; //ACST = UTC + 9.5 hours + break; + } + } -TimeChangeRule EDT = {Second, Sun, Mar, 2, -240 }; //Daylight time = UTC - 4 hours -TimeChangeRule EST = {First, Sun, Nov, 2, -300 }; //Standard time = UTC - 5 hours -Timezone tzUSEastern(EDT, EST); + tzCurrent = currentTimezone; -TimeChangeRule CDT = {Second, Sun, Mar, 2, -300 }; //Daylight time = UTC - 5 hours -TimeChangeRule CST = {First, Sun, Nov, 2, -360 }; //Standard time = UTC - 6 hours -Timezone tzUSCentral(CDT, CST); - -Timezone tzCASaskatchewan(CST, CST); //Central without DST - -TimeChangeRule MDT = {Second, Sun, Mar, 2, -360 }; //Daylight time = UTC - 6 hours -TimeChangeRule MST = {First, Sun, Nov, 2, -420 }; //Standard time = UTC - 7 hours -Timezone tzUSMountain(MDT, MST); - -Timezone tzUSArizona(MST, MST); //Mountain without DST - -TimeChangeRule PDT = {Second, Sun, Mar, 2, -420 }; //Daylight time = UTC - 7 hours -TimeChangeRule PST = {First, Sun, Nov, 2, -480 }; //Standard time = UTC - 8 hours -Timezone tzUSPacific(PDT, PST); - -TimeChangeRule ChST = {Last, Sun, Mar, 1, 480}; // China Standard Time = UTC + 8 hours -Timezone tzChina(ChST, ChST); - -TimeChangeRule JST = {Last, Sun, Mar, 1, 540}; // Japan Standard Time = UTC + 9 hours -Timezone tzJapan(JST, JST); - -TimeChangeRule AEDT = {Second, Sun, Oct, 2, 660 }; //Daylight time = UTC + 11 hours -TimeChangeRule AEST = {First, Sun, Apr, 3, 600 }; //Standard time = UTC + 10 hours -Timezone tzAUEastern(AEDT, AEST); - -TimeChangeRule NZDT = {Second, Sun, Sep, 2, 780 }; //Daylight time = UTC + 13 hours -TimeChangeRule NZST = {First, Sun, Apr, 3, 720 }; //Standard time = UTC + 12 hours -Timezone tzNZ(NZDT, NZST); - -TimeChangeRule NKST = {Last, Sun, Mar, 1, 510}; //Pyongyang Time = UTC + 8.5 hours -Timezone tzNK(NKST, NKST); - -TimeChangeRule IST = {Last, Sun, Mar, 1, 330}; // India Standard Time = UTC + 5.5 hours -Timezone tzIndia(IST, IST); - -TimeChangeRule ACST = {First, Sun, Apr, 3, 570}; //Australian Central Standard = UTC + 9.5 hours -TimeChangeRule ACDT = {First, Sun, Oct, 2, 630}; //Australian Central Daylight = UTC + 10.5 hours -Timezone tzAUNorthern(ACST, ACST); -Timezone tzAUSouthern(ACDT, ACST); - -// Pick your timezone from here. -Timezone* timezones[] = {&tzUTC, &tzUK, &tzEUCentral, &tzEUEastern, &tzUSEastern, &tzUSCentral, &tzUSMountain, &tzUSArizona, &tzUSPacific, &tzChina, &tzJapan, &tzAUEastern, &tzNZ, &tzNK, &tzIndia, &tzCASaskatchewan, &tzAUNorthern, &tzAUSouthern}; + tz = new Timezone(tcrDaylight, tcrStandard); +} void handleNetworkTime() { @@ -95,7 +153,7 @@ void sendNTPPacket() #endif } - DEBUG_PRINTLN("send NTP"); + DEBUG_PRINTLN(F("send NTP")); byte pbuf[NTP_PACKET_SIZE]; memset(pbuf, 0, NTP_PACKET_SIZE); @@ -118,7 +176,7 @@ bool checkNTPResponse() { int cb = ntpUdp.parsePacket(); if (cb) { - DEBUG_PRINT("NTP recv, l="); + DEBUG_PRINT(F("NTP recv, l=")); DEBUG_PRINTLN(cb); byte pbuf[NTP_PACKET_SIZE]; ntpUdp.read(pbuf, NTP_PACKET_SIZE); // read the packet into the buffer @@ -129,7 +187,7 @@ bool checkNTPResponse() unsigned long secsSince1900 = highWord << 16 | lowWord; - DEBUG_PRINT("Unix time = "); + DEBUG_PRINT(F("Unix time = ")); unsigned long epoch = secsSince1900 - 2208988799UL; //subtract 70 years -1sec (on avg. more precision) setTime(epoch); DEBUG_PRINTLN(epoch); @@ -141,8 +199,9 @@ bool checkNTPResponse() void updateLocalTime() { + if (currentTimezone != tzCurrent) updateTimezone(); unsigned long tmc = now()+ utcOffsetSecs; - localTime = timezones[currentTimezone]->toLocal(tmc); + localTime = tz->toLocal(tmc); } void getTimeString(char* out) @@ -165,7 +224,8 @@ void getTimeString(char* out) void setCountdown() { - countdownTime = timezones[currentTimezone]->toUTC(getUnixTime(countdownHour, countdownMin, countdownSec, countdownDay, countdownMonth, countdownYear)); + if (currentTimezone != tzCurrent) updateTimezone(); + countdownTime = tz->toUTC(getUnixTime(countdownHour, countdownMin, countdownSec, countdownDay, countdownMonth, countdownYear)); if (countdownTime - now() > 0) countdownOverTriggered = false; } diff --git a/wled00/set.cpp b/wled00/set.cpp index 4152583..33cf3a4 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -37,20 +37,20 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) //WIFI SETTINGS if (subPage == 1) { - strlcpy(clientSSID,request->arg("CS").c_str(), 33); + strlcpy(clientSSID,request->arg(F("CS")).c_str(), 33); - if (!isAsterisksOnly(request->arg("CP").c_str(), 65)) strlcpy(clientPass, request->arg("CP").c_str(), 65); + if (!isAsterisksOnly(request->arg(F("CP")).c_str(), 65)) strlcpy(clientPass, request->arg(F("CP")).c_str(), 65); - strlcpy(cmDNS, request->arg("CM").c_str(), 33); + strlcpy(cmDNS, request->arg(F("CM")).c_str(), 33); - apBehavior = request->arg("AB").toInt(); - strlcpy(apSSID, request->arg("AS").c_str(), 33); - apHide = request->hasArg("AH"); - int passlen = request->arg("AP").length(); - if (passlen == 0 || (passlen > 7 && !isAsterisksOnly(request->arg("AP").c_str(), 65))) strlcpy(apPass, request->arg("AP").c_str(), 65); - int t = request->arg("AC").toInt(); if (t > 0 && t < 14) apChannel = t; + apBehavior = request->arg(F("AB")).toInt(); + strlcpy(apSSID, request->arg(F("AS")).c_str(), 33); + apHide = request->hasArg(F("AH")); + int passlen = request->arg(F("AP")).length(); + if (passlen == 0 || (passlen > 7 && !isAsterisksOnly(request->arg(F("AP")).c_str(), 65))) strlcpy(apPass, request->arg(F("AP")).c_str(), 65); + int t = request->arg(F("AC")).toInt(); if (t > 0 && t < 14) apChannel = t; - noWifiSleep = request->hasArg("WS"); + noWifiSleep = request->hasArg(F("WS")); char k[3]; k[2] = 0; for (int i = 0; i<4; i++) @@ -71,110 +71,110 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) //LED SETTINGS if (subPage == 2) { - int t = request->arg("LC").toInt(); + int t = request->arg(F("LC")).toInt(); if (t > 0 && t <= MAX_LEDS) ledCount = t; #ifdef ESP8266 #if LEDPIN == 3 if (ledCount > MAX_LEDS_DMA) ledCount = MAX_LEDS_DMA; //DMA method uses too much ram #endif #endif - strip.ablMilliampsMax = request->arg("MA").toInt(); - strip.milliampsPerLed = request->arg("LA").toInt(); + strip.ablMilliampsMax = request->arg(F("MA")).toInt(); + strip.milliampsPerLed = request->arg(F("LA")).toInt(); - useRGBW = request->hasArg("EW"); - strip.colorOrder = request->arg("CO").toInt(); - strip.rgbwMode = request->arg("AW").toInt(); + useRGBW = request->hasArg(F("EW")); + strip.colorOrder = request->arg(F("CO")).toInt(); + strip.rgbwMode = request->arg(F("AW")).toInt(); - briS = request->arg("CA").toInt(); + briS = request->arg(F("CA")).toInt(); - saveCurrPresetCycConf = request->hasArg("PC"); - turnOnAtBoot = request->hasArg("BO"); - t = request->arg("BP").toInt(); + saveCurrPresetCycConf = request->hasArg(F("PC")); + turnOnAtBoot = request->hasArg(F("BO")); + t = request->arg(F("BP")).toInt(); if (t <= 25) bootPreset = t; - strip.gammaCorrectBri = request->hasArg("GB"); - strip.gammaCorrectCol = request->hasArg("GC"); + strip.gammaCorrectBri = request->hasArg(F("GB")); + strip.gammaCorrectCol = request->hasArg(F("GC")); - fadeTransition = request->hasArg("TF"); - t = request->arg("TD").toInt(); + fadeTransition = request->hasArg(F("TF")); + t = request->arg(F("TD")).toInt(); if (t > 0) transitionDelay = t; transitionDelayDefault = t; - strip.paletteFade = request->hasArg("PF"); + strip.paletteFade = request->hasArg(F("PF")); - nightlightTargetBri = request->arg("TB").toInt(); - t = request->arg("TL").toInt(); + nightlightTargetBri = request->arg(F("TB")).toInt(); + t = request->arg(F("TL")).toInt(); if (t > 0) nightlightDelayMinsDefault = t; nightlightDelayMins = nightlightDelayMinsDefault; - nightlightMode = request->arg("TW").toInt(); + nightlightMode = request->arg(F("TW")).toInt(); - t = request->arg("PB").toInt(); + t = request->arg(F("PB")).toInt(); if (t >= 0 && t < 4) strip.paletteBlend = t; - strip.reverseMode = request->hasArg("RV"); - skipFirstLed = request->hasArg("SL"); - t = request->arg("BF").toInt(); + strip.reverseMode = request->hasArg(F("RV")); + skipFirstLed = request->hasArg(F("SL")); + t = request->arg(F("BF")).toInt(); if (t > 0) briMultiplier = t; } //UI if (subPage == 3) { - strlcpy(serverDescription, request->arg("DS").c_str(), 33); - syncToggleReceive = request->hasArg("ST"); + strlcpy(serverDescription, request->arg(F("DS")).c_str(), 33); + syncToggleReceive = request->hasArg(F("ST")); } //SYNC if (subPage == 4) { - buttonEnabled = request->hasArg("BT"); - irEnabled = request->arg("IR").toInt(); - int t = request->arg("UP").toInt(); + buttonEnabled = request->hasArg(F("BT")); + irEnabled = request->arg(F("IR")).toInt(); + int t = request->arg(F("UP")).toInt(); if (t > 0) udpPort = t; - receiveNotificationBrightness = request->hasArg("RB"); - receiveNotificationColor = request->hasArg("RC"); - receiveNotificationEffects = request->hasArg("RX"); + receiveNotificationBrightness = request->hasArg(F("RB")); + receiveNotificationColor = request->hasArg(F("RC")); + receiveNotificationEffects = request->hasArg(F("RX")); receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects); - notifyDirectDefault = request->hasArg("SD"); + notifyDirectDefault = request->hasArg(F("SD")); notifyDirect = notifyDirectDefault; - notifyButton = request->hasArg("SB"); - notifyAlexa = request->hasArg("SA"); - notifyHue = request->hasArg("SH"); - notifyMacro = request->hasArg("SM"); - notifyTwice = request->hasArg("S2"); + notifyButton = request->hasArg(F("SB")); + notifyAlexa = request->hasArg(F("SA")); + notifyHue = request->hasArg(F("SH")); + notifyMacro = request->hasArg(F("SM")); + notifyTwice = request->hasArg(F("S2")); - receiveDirect = request->hasArg("RD"); - e131SkipOutOfSequence = request->hasArg("ES"); - e131Multicast = request->hasArg("EM"); - t = request->arg("EP").toInt(); + receiveDirect = request->hasArg(F("RD")); + e131SkipOutOfSequence = request->hasArg(F("ES")); + e131Multicast = request->hasArg(F("EM")); + t = request->arg(F("EP")).toInt(); if (t > 0) e131Port = t; - t = request->arg("EU").toInt(); + t = request->arg(F("EU")).toInt(); if (t >= 0 && t <= 63999) e131Universe = t; - t = request->arg("DA").toInt(); + t = request->arg(F("DA")).toInt(); if (t >= 0 && t <= 510) DMXAddress = t; - t = request->arg("DM").toInt(); + t = request->arg(F("DM")).toInt(); if (t >= DMX_MODE_DISABLED && t <= DMX_MODE_MULTIPLE_DRGB) DMXMode = t; - t = request->arg("ET").toInt(); + t = request->arg(F("ET")).toInt(); if (t > 99 && t <= 65000) realtimeTimeoutMs = t; - arlsForceMaxBri = request->hasArg("FB"); - arlsDisableGammaCorrection = request->hasArg("RG"); - t = request->arg("WO").toInt(); + arlsForceMaxBri = request->hasArg(F("FB")); + arlsDisableGammaCorrection = request->hasArg(F("RG")); + t = request->arg(F("WO")).toInt(); if (t >= -255 && t <= 255) arlsOffset = t; - alexaEnabled = request->hasArg("AL"); - strlcpy(alexaInvocationName, request->arg("AI").c_str(), 33); + alexaEnabled = request->hasArg(F("AL")); + strlcpy(alexaInvocationName, request->arg(F("AI")).c_str(), 33); - if (request->hasArg("BK") && !request->arg("BK").equals("Hidden")) { + if (request->hasArg("BK") && !request->arg("BK").equals(F("Hidden"))) { strlcpy(blynkApiKey, request->arg("BK").c_str(), 36); initBlynk(blynkApiKey); } #ifdef WLED_ENABLE_MQTT - mqttEnabled = request->hasArg("MQ"); - strlcpy(mqttServer, request->arg("MS").c_str(), 33); - t = request->arg("MQPORT").toInt(); + mqttEnabled = request->hasArg(F("MQ")); + strlcpy(mqttServer, request->arg(F("MS")).c_str(), 33); + t = request->arg(F("MQPORT")).toInt(); if (t > 0) mqttPort = t; - strlcpy(mqttUser, request->arg("MQUSER").c_str(), 41); - if (!isAsterisksOnly(request->arg("MQPASS").c_str(), 41)) strlcpy(mqttPass, request->arg("MQPASS").c_str(), 41); - strlcpy(mqttClientID, request->arg("MQCID").c_str(), 41); - strlcpy(mqttDeviceTopic, request->arg("MD").c_str(), 33); - strlcpy(mqttGroupTopic, request->arg("MG").c_str(), 33); + strlcpy(mqttUser, request->arg(F("MQUSER")).c_str(), 41); + if (!isAsterisksOnly(request->arg(F("MQPASS")).c_str(), 41)) strlcpy(mqttPass, request->arg(F("MQPASS")).c_str(), 41); + strlcpy(mqttClientID, request->arg(F("MQCID")).c_str(), 41); + strlcpy(mqttDeviceTopic, request->arg(F("MD")).c_str(), 33); + strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), 33); #endif #ifndef WLED_DISABLE_HUESYNC @@ -183,16 +183,16 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) hueIP[i] = request->arg(a).toInt(); } - t = request->arg("HL").toInt(); + t = request->arg(F("HL")).toInt(); if (t > 0) huePollLightId = t; - t = request->arg("HI").toInt(); + t = request->arg(F("HI")).toInt(); if (t > 50) huePollIntervalMs = t; - hueApplyOnOff = request->hasArg("HO"); - hueApplyBri = request->hasArg("HB"); - hueApplyColor = request->hasArg("HC"); - huePollingEnabled = request->hasArg("HP"); + hueApplyOnOff = request->hasArg(F("HO")); + hueApplyBri = request->hasArg(F("HB")); + hueApplyColor = request->hasArg(F("HC")); + huePollingEnabled = request->hasArg(F("HP")); hueStoreAllowed = true; reconnectHue(); #endif @@ -201,35 +201,35 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) //TIME if (subPage == 5) { - ntpEnabled = request->hasArg("NT"); - strlcpy(ntpServerName, request->arg("NS").c_str(), 33); - useAMPM = !request->hasArg("CF"); - currentTimezone = request->arg("TZ").toInt(); - utcOffsetSecs = request->arg("UO").toInt(); + ntpEnabled = request->hasArg(F("NT")); + strlcpy(ntpServerName, request->arg(F("NS")).c_str(), 33); + useAMPM = !request->hasArg(F("CF")); + currentTimezone = request->arg(F("TZ")).toInt(); + utcOffsetSecs = request->arg(F("UO")).toInt(); //start ntp if not already connected if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort); - if (request->hasArg("OL")){ - overlayDefault = request->arg("OL").toInt(); + if (request->hasArg(F("OL"))) { + overlayDefault = request->arg(F("OL")).toInt(); overlayCurrent = overlayDefault; } - overlayMin = request->arg("O1").toInt(); - overlayMax = request->arg("O2").toInt(); - analogClock12pixel = request->arg("OM").toInt(); - analogClock5MinuteMarks = request->hasArg("O5"); - analogClockSecondsTrail = request->hasArg("OS"); + overlayMin = request->arg(F("O1")).toInt(); + overlayMax = request->arg(F("O2")).toInt(); + analogClock12pixel = request->arg(F("OM")).toInt(); + analogClock5MinuteMarks = request->hasArg(F("O5")); + analogClockSecondsTrail = request->hasArg(F("OS")); - strcpy(cronixieDisplay,request->arg("CX").c_str()); - cronixieBacklight = request->hasArg("CB"); - countdownMode = request->hasArg("CE"); - countdownYear = request->arg("CY").toInt(); - countdownMonth = request->arg("CI").toInt(); - countdownDay = request->arg("CD").toInt(); - countdownHour = request->arg("CH").toInt(); - countdownMin = request->arg("CM").toInt(); - countdownSec = request->arg("CS").toInt(); + strcpy(cronixieDisplay,request->arg(F("CX")).c_str()); + cronixieBacklight = request->hasArg(F("CB")); + countdownMode = request->hasArg(F("CE")); + countdownYear = request->arg(F("CY")).toInt(); + countdownMonth = request->arg(F("CI")).toInt(); + countdownDay = request->arg(F("CD")).toInt(); + countdownHour = request->arg(F("CH")).toInt(); + countdownMin = request->arg(F("CM")).toInt(); + countdownSec = request->arg(F("CS")).toInt(); for (int i=1;i<17;i++) { @@ -237,14 +237,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) if (request->hasArg(a.c_str())) saveMacro(i,request->arg(a),false); } - macroBoot = request->arg("MB").toInt(); - macroAlexaOn = request->arg("A0").toInt(); - macroAlexaOff = request->arg("A1").toInt(); - macroButton = request->arg("MP").toInt(); - macroLongPress = request->arg("ML").toInt(); - macroCountdown = request->arg("MC").toInt(); - macroNl = request->arg("MN").toInt(); - macroDoublePress = request->arg("MD").toInt(); + macroBoot = request->arg(F("MB")).toInt(); + macroAlexaOn = request->arg(F("A0")).toInt(); + macroAlexaOff = request->arg(F("A1")).toInt(); + macroButton = request->arg(F("MP")).toInt(); + macroLongPress = request->arg(F("ML")).toInt(); + macroCountdown = request->arg(F("MC")).toInt(); + macroNl = request->arg(F("MN")).toInt(); + macroDoublePress = request->arg(F("MD")).toInt(); char k[3]; k[2] = 0; for (int i = 0; i<8; i++) @@ -268,52 +268,52 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) //SECURITY if (subPage == 6) { - if (request->hasArg("RS")) //complete factory reset + if (request->hasArg(F("RS"))) //complete factory reset { clearEEPROM(); - serveMessage(request, 200, "All Settings erased.", "Connect to WLED-AP to setup again",255); + serveMessage(request, 200, F("All Settings erased."), F("Connect to WLED-AP to setup again"),255); doReboot = true; } bool pwdCorrect = !otaLock; //always allow access if ota not locked - if (request->hasArg("OP")) + if (request->hasArg(F("OP"))) { - if (otaLock && strcmp(otaPass,request->arg("OP").c_str()) == 0) + if (otaLock && strcmp(otaPass,request->arg(F("OP")).c_str()) == 0) { pwdCorrect = true; } - if (!otaLock && request->arg("OP").length() > 0) + if (!otaLock && request->arg(F("OP")).length() > 0) { - strlcpy(otaPass,request->arg("OP").c_str(), 33); + strlcpy(otaPass,request->arg(F("OP")).c_str(), 33); } } if (pwdCorrect) //allow changes if correct pwd or no ota active { - otaLock = request->hasArg("NO"); - wifiLock = request->hasArg("OW"); - aOtaEnabled = request->hasArg("AO"); + otaLock = request->hasArg(F("NO")); + wifiLock = request->hasArg(F("OW")); + aOtaEnabled = request->hasArg(F("AO")); } } #ifdef WLED_ENABLE_DMX // include only if DMX is enabled if (subPage == 7) { - int t = request->arg("PU").toInt(); + int t = request->arg(F("PU")).toInt(); if (t >= 0 && t <= 63999) e131ProxyUniverse = t; - t = request->arg("CN").toInt(); + t = request->arg(F("CN")).toInt(); if (t>0 && t<16) { DMXChannels = t; } - t = request->arg("CS").toInt(); + t = request->arg(F("CS")).toInt(); if (t>0 && t<513) { DMXStart = t; } - t = request->arg("CG").toInt(); + t = request->arg(F("CG")).toInt(); if (t>0 && t<513) { DMXGap = t; } - t = request->arg("SL").toInt(); + t = request->arg(F("SL")).toInt(); if (t>=0 && t < MAX_LEDS) { DMXStartLED = t; } @@ -377,18 +377,18 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) if (!(req.indexOf("win") >= 0)) return false; int pos = 0; - DEBUG_PRINT("API req: "); + DEBUG_PRINT(F("API req: ")); DEBUG_PRINTLN(req); //write presets and macros saved to flash directly? bool persistSaves = true; - pos = req.indexOf("NP"); + pos = req.indexOf(F("NP")); if (pos > 0) { persistSaves = false; } //save macro, requires &MS=() format - pos = req.indexOf("&MS="); + pos = req.indexOf(F("&MS=")); if (pos > 0) { int i = req.substring(pos + 4).toInt(); pos = req.indexOf('(') +1; @@ -399,7 +399,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) saveMacro(i, mc, persistSaves); } - pos = req.indexOf("IN"); + pos = req.indexOf(F("IN")); if (pos < 1) XML_response(request); return true; //if you save a macro in one request, other commands in that request are ignored due to unwanted behavior otherwise @@ -409,21 +409,21 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) //segment select (sets main segment) byte prevMain = strip.getMainSegmentId(); - pos = req.indexOf("SM="); + pos = req.indexOf(F("SM=")); if (pos > 0) { strip.mainSegment = getNumVal(&req, pos); } byte main = strip.getMainSegmentId(); if (main != prevMain) setValuesFromMainSeg(); - pos = req.indexOf("SS="); + pos = req.indexOf(F("SS=")); if (pos > 0) { byte t = getNumVal(&req, pos); if (t < strip.getMaxSegments()) main = t; } WS2812FX::Segment& mainseg = strip.getSegment(main); - pos = req.indexOf("SV="); //segment selected + pos = req.indexOf(F("SV=")); //segment selected if (pos > 0) { byte t = getNumVal(&req, pos); if (t == 2) { @@ -439,20 +439,20 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) uint16_t stopI = mainseg.stop; uint8_t grpI = mainseg.grouping; uint16_t spcI = mainseg.spacing; - pos = req.indexOf("&S="); //segment start + pos = req.indexOf(F("&S=")); //segment start if (pos > 0) { startI = getNumVal(&req, pos); } - pos = req.indexOf("S2="); //segment stop + pos = req.indexOf(F("S2=")); //segment stop if (pos > 0) { stopI = getNumVal(&req, pos); } - pos = req.indexOf("GP="); //segment grouping + pos = req.indexOf(F("GP=")); //segment grouping if (pos > 0) { grpI = getNumVal(&req, pos); if (grpI == 0) grpI = 1; } - pos = req.indexOf("SP="); //segment spacing + pos = req.indexOf(F("SP=")); //segment spacing if (pos > 0) { spcI = getNumVal(&req, pos); } @@ -461,30 +461,32 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) main = strip.getMainSegmentId(); //set presets - pos = req.indexOf("P1="); //sets first preset for cycle + pos = req.indexOf(F("P1=")); //sets first preset for cycle if (pos > 0) presetCycleMin = getNumVal(&req, pos); - pos = req.indexOf("P2="); //sets last preset for cycle + pos = req.indexOf(F("P2=")); //sets last preset for cycle if (pos > 0) presetCycleMax = getNumVal(&req, pos); //preset cycle - pos = req.indexOf("CY="); + pos = req.indexOf(F("CY=")); if (pos > 0) { - presetCyclingEnabled = (req.charAt(pos+3) != '0'); + char cmd = req.charAt(pos+3); + if (cmd == '2') presetCyclingEnabled = !presetCyclingEnabled; + else presetCyclingEnabled = (cmd != '0'); presetCycCurr = presetCycleMin; } - pos = req.indexOf("PT="); //sets cycle time in ms + pos = req.indexOf(F("PT=")); //sets cycle time in ms if (pos > 0) { int v = getNumVal(&req, pos); if (v > 100) presetCycleTime = v/100; } - pos = req.indexOf("PA="); //apply brightness from preset + pos = req.indexOf(F("PA=")); //apply brightness from preset if (pos > 0) presetApplyBri = (req.charAt(pos+3) != '0'); - pos = req.indexOf("PS="); //saves current in preset + pos = req.indexOf(F("PS=")); //saves current in preset if (pos > 0) savePreset(getNumVal(&req, pos), persistSaves); //apply preset @@ -506,27 +508,27 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) updateVal(&req, "W2=", &colSec[3]); //set hue - pos = req.indexOf("HU="); + pos = req.indexOf(F("HU=")); if (pos > 0) { uint16_t temphue = getNumVal(&req, pos); byte tempsat = 255; - pos = req.indexOf("SA="); + pos = req.indexOf(F("SA=")); if (pos > 0) { tempsat = getNumVal(&req, pos); } - colorHStoRGB(temphue,tempsat,(req.indexOf("H2")>0)? colSec:col); + colorHStoRGB(temphue,tempsat,(req.indexOf(F("H2"))>0)? colSec:col); } //set color from HEX or 32bit DEC - pos = req.indexOf("CL="); + pos = req.indexOf(F("CL=")); if (pos > 0) { colorFromDecOrHexString(col, (char*)req.substring(pos + 3).c_str()); } - pos = req.indexOf("C2="); + pos = req.indexOf(F("C2=")); if (pos > 0) { colorFromDecOrHexString(colSec, (char*)req.substring(pos + 3).c_str()); } - pos = req.indexOf("C3="); + pos = req.indexOf(F("C3=")); if (pos > 0) { byte t[4]; colorFromDecOrHexString(t, (char*)req.substring(pos + 3).c_str()); @@ -534,13 +536,13 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) } //set to random hue SR=0->1st SR=1->2nd - pos = req.indexOf("SR"); + pos = req.indexOf(F("SR")); if (pos > 0) { _setRandomColor(getNumVal(&req, pos)); } //swap 2nd & 1st - pos = req.indexOf("SC"); + pos = req.indexOf(F("SC")); if (pos > 0) { byte temp; for (uint8_t i=0; i<4; i++) @@ -558,33 +560,33 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) updateVal(&req, "FP=", &effectPalette, 0, strip.getPaletteCount()-1); //set advanced overlay - pos = req.indexOf("OL="); + pos = req.indexOf(F("OL=")); if (pos > 0) { overlayCurrent = getNumVal(&req, pos); } //apply macro - pos = req.indexOf("&M="); + pos = req.indexOf(F("&M=")); if (pos > 0) { applyMacro(getNumVal(&req, pos)); } //toggle send UDP direct notifications - pos = req.indexOf("SN="); + pos = req.indexOf(F("SN=")); if (pos > 0) notifyDirect = (req.charAt(pos+3) != '0'); //toggle receive UDP direct notifications - pos = req.indexOf("RN="); + pos = req.indexOf(F("RN=")); if (pos > 0) receiveNotifications = (req.charAt(pos+3) != '0'); //receive live data via UDP/Hyperion - pos = req.indexOf("RD="); + pos = req.indexOf(F("RD=")); if (pos > 0) receiveDirect = (req.charAt(pos+3) != '0'); //toggle nightlight mode bool aNlDef = false; - if (req.indexOf("&ND") > 0) aNlDef = true; - pos = req.indexOf("NL="); + if (req.indexOf(F("&ND")) > 0) aNlDef = true; + pos = req.indexOf(F("NL=")); if (pos > 0) { if (req.charAt(pos+3) == '0') @@ -603,14 +605,14 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) } //set nightlight target brightness - pos = req.indexOf("NT="); + pos = req.indexOf(F("NT=")); if (pos > 0) { nightlightTargetBri = getNumVal(&req, pos); nightlightActiveOld = false; //re-init } //toggle nightlight fade - pos = req.indexOf("NF="); + pos = req.indexOf(F("NF=")); if (pos > 0) { nightlightMode = getNumVal(&req, pos); @@ -621,7 +623,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) #if AUXPIN >= 0 //toggle general purpose output - pos = req.indexOf("AX="); + pos = req.indexOf(F("AX=")); if (pos > 0) { auxTime = getNumVal(&req, pos); auxActive = true; @@ -629,11 +631,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) } #endif - pos = req.indexOf("TT="); + pos = req.indexOf(F("TT=")); if (pos > 0) transitionDelay = getNumVal(&req, pos); //main toggle on/off - pos = req.indexOf("&T="); + pos = req.indexOf(F("&T=")); if (pos > 0) { nightlightActive = false; //always disable nightlight when toggling switch (getNumVal(&req, pos)) @@ -645,15 +647,15 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) } //Segment reverse - pos = req.indexOf("RV="); + pos = req.indexOf(F("RV=")); if (pos > 0) strip.getSegment(main).setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0'); //Segment reverse - pos = req.indexOf("MI="); + pos = req.indexOf(F("MI=")); if (pos > 0) strip.getSegment(main).setOption(SEG_OPTION_MIRROR, req.charAt(pos+3) != '0'); //Segment brightness/opacity - pos = req.indexOf("SB="); + pos = req.indexOf(F("SB=")); if (pos > 0) { byte segbri = getNumVal(&req, pos); strip.getSegment(main).setOption(SEG_OPTION_ON, segbri); @@ -663,40 +665,40 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) } //set time (unix timestamp) - pos = req.indexOf("ST="); + pos = req.indexOf(F("ST=")); if (pos > 0) { setTime(getNumVal(&req, pos)); } //set countdown goal (unix timestamp) - pos = req.indexOf("CT="); + pos = req.indexOf(F("CT=")); if (pos > 0) { countdownTime = getNumVal(&req, pos); if (countdownTime - now() > 0) countdownOverTriggered = false; } - pos = req.indexOf("LO="); + pos = req.indexOf(F("LO=")); if (pos > 0) { realtimeOverride = getNumVal(&req, pos); if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS; } - pos = req.indexOf("RB"); + pos = req.indexOf(F("RB")); if (pos > 0) doReboot = true; //cronixie #ifndef WLED_DISABLE_CRONIXIE //mode, 1 countdown - pos = req.indexOf("NM="); + pos = req.indexOf(F("NM=")); if (pos > 0) countdownMode = (req.charAt(pos+3) != '0'); - pos = req.indexOf("NX="); //sets digits to code + pos = req.indexOf(F("NX=")); //sets digits to code if (pos > 0) { strlcpy(cronixieDisplay, req.substring(pos + 3, pos + 9).c_str(), 6); setCronixie(); } - pos = req.indexOf("NB="); + pos = req.indexOf(F("NB=")); if (pos > 0) //sets backlight { cronixieBacklight = (req.charAt(pos+3) != '0'); @@ -704,22 +706,22 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) } #endif - pos = req.indexOf("U0="); //user var 0 + pos = req.indexOf(F("U0=")); //user var 0 if (pos > 0) { userVar0 = getNumVal(&req, pos); } - pos = req.indexOf("U1="); //user var 1 + pos = req.indexOf(F("U1=")); //user var 1 if (pos > 0) { userVar1 = getNumVal(&req, pos); } //you can add more if you need //internal call, does not send XML response - pos = req.indexOf("IN"); + pos = req.indexOf(F("IN")); if (pos < 1) XML_response(request); - pos = req.indexOf("&NN"); //do not send UDP notifications this time + pos = req.indexOf(F("&NN")); //do not send UDP notifications this time colorUpdated((pos > 0) ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE); return true; diff --git a/wled00/src/dependencies/json/AsyncJson-v6.h b/wled00/src/dependencies/json/AsyncJson-v6.h index 9187a3e..7edab31 100644 --- a/wled00/src/dependencies/json/AsyncJson-v6.h +++ b/wled00/src/dependencies/json/AsyncJson-v6.h @@ -15,7 +15,11 @@ #include "ArduinoJson-v6.h" #include -#define DYNAMIC_JSON_DOCUMENT_SIZE 8192 +#ifdef ESP8266 + #define DYNAMIC_JSON_DOCUMENT_SIZE 8192 +#else + #define DYNAMIC_JSON_DOCUMENT_SIZE 16384 +#endif constexpr const char* JSON_MIMETYPE = "application/json"; diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 25c9f1d..0713310 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -94,8 +94,13 @@ void WLED::loop() } yield(); + if (!offMode) strip.service(); +#ifdef ESP8266 + else if (!noWifiSleep) + delay(1); //required to make sure ESP enters modem sleep (see #1184) +#endif } yield(); #ifdef ESP8266 @@ -168,7 +173,7 @@ void WLED::setup() strip.init(EEPROM.read(372), ledCount, EEPROM.read(2204)); // init LEDs quickly strip.setBrightness(0); - DEBUG_PRINT("LEDs inited. heap usage ~"); + DEBUG_PRINT(F("LEDs inited. heap usage ~")); DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap()); #ifndef WLED_DISABLE_FILESYSTEM @@ -178,7 +183,7 @@ void WLED::setup() WLED_FS.begin(); #endif - DEBUG_PRINTLN("Load EEPROM"); + DEBUG_PRINTLN(F("Load EEPROM")); loadSettingsFromEEPROM(true); beginStrip(); userSetup(); @@ -189,7 +194,7 @@ void WLED::setup() if (macroBoot > 0) applyMacro(macroBoot); - Serial.println("Ada"); + Serial.println(F("Ada")); // generate module IDs escapedMac = WiFi.macAddress(); @@ -197,15 +202,15 @@ void WLED::setup() escapedMac.toLowerCase(); if (strcmp(cmDNS, "x") == 0) // fill in unique mdns default { - strcpy(cmDNS, "wled-"); + strcpy_P(cmDNS, PSTR("wled-")); sprintf(cmDNS + 5, "%*s", 6, escapedMac.c_str() + 6); } if (mqttDeviceTopic[0] == 0) { - strcpy(mqttDeviceTopic, "wled/"); + strcpy_P(mqttDeviceTopic, PSTR("wled/")); sprintf(mqttDeviceTopic + 5, "%*s", 6, escapedMac.c_str() + 6); } if (mqttClientID[0] == 0) { - strcpy(mqttClientID, "WLED-"); + strcpy_P(mqttClientID, PSTR("WLED-")); sprintf(mqttClientID + 5, "%*s", 6, escapedMac.c_str() + 6); } @@ -217,7 +222,7 @@ void WLED::setup() #ifdef ESP8266 wifi_set_sleep_type(NONE_SLEEP_T); #endif - DEBUG_PRINTLN("Start ArduinoOTA"); + DEBUG_PRINTLN(F("Start ArduinoOTA")); }); if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(cmDNS); @@ -254,8 +259,8 @@ void WLED::beginStrip() #endif // disable button if it is "pressed" unintentionally -#ifdef BTNPIN - if (digitalRead(BTNPIN) == LOW) +#if defined(BTNPIN) || defined(TOUCHPIN) + if (isButtonPressed()) buttonEnabled = false; #else buttonEnabled = false; @@ -268,17 +273,17 @@ void WLED::initAP(bool resetAP) return; if (!apSSID[0] || resetAP) - strcpy(apSSID, "WLED-AP"); + strcpy(apSSID, (const char*)F("WLED-AP")); if (resetAP) strcpy(apPass, DEFAULT_AP_PASS); - DEBUG_PRINT("Opening access point "); + DEBUG_PRINT(F("Opening access point ")); DEBUG_PRINTLN(apSSID); WiFi.softAPConfig(IPAddress(4, 3, 2, 1), IPAddress(4, 3, 2, 1), IPAddress(255, 255, 255, 0)); WiFi.softAP(apSSID, apPass, apChannel, apHide); if (!apActive) // start captive portal if AP active { - DEBUG_PRINTLN("Init AP interfaces"); + DEBUG_PRINTLN(F("Init AP interfaces")); server.begin(); if (udpPort > 0 && udpPort != ntpLocalPort) { udpConnected = notifierUdp.begin(udpPort); @@ -313,7 +318,7 @@ void WLED::initConnection() lastReconnectAttempt = millis(); if (!WLED_WIFI_CONFIGURED) { - DEBUG_PRINT("No connection configured. "); + DEBUG_PRINT(F("No connection configured. ")); if (!apActive) initAP(); // instantly go to ap mode return; @@ -321,14 +326,14 @@ void WLED::initConnection() if (apBehavior == AP_BEHAVIOR_ALWAYS) { initAP(); } else { - DEBUG_PRINTLN("Access point disabled."); + DEBUG_PRINTLN(F("Access point disabled.")); WiFi.softAPdisconnect(true); WiFi.mode(WIFI_STA); } } showWelcomePage = false; - DEBUG_PRINT("Connecting to "); + DEBUG_PRINT(F("Connecting to ")); DEBUG_PRINT(clientSSID); DEBUG_PRINTLN("..."); @@ -374,7 +379,7 @@ void WLED::initConnection() void WLED::initInterfaces() { - DEBUG_PRINTLN("Init STA interfaces"); + DEBUG_PRINTLN(F("Init STA interfaces")); if (hueIP[0] == 0) { hueIP[0] = WiFi.localIP()[0]; @@ -401,7 +406,7 @@ void WLED::initInterfaces() MDNS.begin(cmDNS); #endif - DEBUG_PRINTLN("mDNS started"); + DEBUG_PRINTLN(F("mDNS started")); MDNS.addService("http", "tcp", 80); MDNS.addService("wled", "tcp", 80); MDNS.addServiceTxt("wled", "tcp", "mac", escapedMac.c_str()); @@ -439,7 +444,7 @@ void WLED::handleConnection() if (millis() - heapTime > 5000) { uint32_t heap = ESP.getFreeHeap(); if (heap < 9000 && lastHeap < 9000) { - DEBUG_PRINT("Heap too low! "); + DEBUG_PRINT(F("Heap too low! ")); DEBUG_PRINTLN(heap); forceReconnect = true; } @@ -458,7 +463,7 @@ void WLED::handleConnection() #endif if (stac != stacO) { stacO = stac; - DEBUG_PRINT("Connected AP clients: "); + DEBUG_PRINT(F("Connected AP clients: ")); DEBUG_PRINTLN(stac); if (!WLED_CONNECTED && WLED_WIFI_CONFIGURED) { // trying to connect, but not connected if (stac) @@ -469,7 +474,7 @@ void WLED::handleConnection() } } if (forceReconnect) { - DEBUG_PRINTLN("Forcing reconnect."); + DEBUG_PRINTLN(F("Forcing reconnect.")); initConnection(); interfacesInited = false; forceReconnect = false; @@ -478,7 +483,7 @@ void WLED::handleConnection() } if (!WLED_CONNECTED) { if (interfacesInited) { - DEBUG_PRINTLN("Disconnected!"); + DEBUG_PRINTLN(F("Disconnected!")); interfacesInited = false; initConnection(); } @@ -488,7 +493,7 @@ void WLED::handleConnection() initAP(); } else if (!interfacesInited) { // newly connected DEBUG_PRINTLN(""); - DEBUG_PRINT("Connected! IP address: "); + DEBUG_PRINT(F("Connected! IP address: ")); DEBUG_PRINTLN(WiFi.localIP()); initInterfaces(); userConnected(); @@ -499,7 +504,7 @@ void WLED::handleConnection() dnsServer.stop(); WiFi.softAPdisconnect(true); apActive = false; - DEBUG_PRINTLN("Access point disabled."); + DEBUG_PRINTLN(F("Access point disabled.")); } } } diff --git a/wled00/wled.h b/wled00/wled.h index d5a8114..29d77e4 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2009100 +#define VERSION 2009202 // ESP8266-01 (blue) got too little storage space to work with WLED. 0.10.2 is the last release supporting this unit. diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp index e8c9558..d64fb58 100644 --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -758,7 +758,7 @@ void applyMacro(byte index) } -void saveMacro(byte index, String mc, bool persist) //only commit on single save, not in settings +void saveMacro(byte index, const String& mc, bool persist) //only commit on single save, not in settings { index-=1; if (index > 15) return; diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 8a2094d..cff5a09 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -25,7 +25,7 @@ bool captivePortal(AsyncWebServerRequest *request) if (!isIp(hostH) && hostH.indexOf("wled.me") < 0 && hostH.indexOf(cmDNS) < 0) { DEBUG_PRINTLN("Captive portal"); AsyncWebServerResponse *response = request->beginResponse(302); - response->addHeader("Location", "http://4.3.2.1"); + response->addHeader(F("Location"), F("http://4.3.2.1")); request->send(response); return true; } @@ -35,9 +35,9 @@ bool captivePortal(AsyncWebServerRequest *request) void initServer() { //CORS compatiblity - DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*"); - DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods", "*"); - DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "*"); + DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Origin"), "*"); + DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Methods"), "*"); + DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Headers"), "*"); server.on("/liveview", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/html", PAGE_liveview); @@ -64,45 +64,12 @@ void initServer() }); server.on("/reset", HTTP_GET, [](AsyncWebServerRequest *request){ - serveMessage(request, 200,"Rebooting now...",F("Please wait ~10 seconds..."),129); + serveMessage(request, 200,F("Rebooting now..."),F("Please wait ~10 seconds..."),129); doReboot = true; }); - server.on("/settings/wifi", HTTP_POST, [](AsyncWebServerRequest *request){ - if (!(wifiLock && otaLock)) handleSettingsSet(request, 1); - serveMessage(request, 200,F("WiFi settings saved."),F("Please connect to the new IP (if changed)"),129); - forceReconnect = true; - }); - - server.on("/settings/leds", HTTP_POST, [](AsyncWebServerRequest *request){ - handleSettingsSet(request, 2); - serveMessage(request, 200,F("LED settings saved."),"Redirecting...",1); - }); - - server.on("/settings/ui", HTTP_POST, [](AsyncWebServerRequest *request){ - handleSettingsSet(request, 3); - serveMessage(request, 200,F("UI settings saved."),"Redirecting...",1); - }); - - server.on("/settings/dmx", HTTP_POST, [](AsyncWebServerRequest *request){ - handleSettingsSet(request, 7); - serveMessage(request, 200,F("UI settings saved."),"Redirecting...",1); - }); - - server.on("/settings/sync", HTTP_POST, [](AsyncWebServerRequest *request){ - handleSettingsSet(request, 4); - serveMessage(request, 200,F("Sync settings saved."),"Redirecting...",1); - }); - - server.on("/settings/time", HTTP_POST, [](AsyncWebServerRequest *request){ - handleSettingsSet(request, 5); - serveMessage(request, 200,F("Time settings saved."),"Redirecting...",1); - }); - - server.on("/settings/sec", HTTP_POST, [](AsyncWebServerRequest *request){ - handleSettingsSet(request, 6); - if (!doReboot) serveMessage(request, 200,F("Security settings saved."),F("Rebooting, please wait ~10 seconds..."),129); - doReboot = true; + server.on("/settings", HTTP_POST, [](AsyncWebServerRequest *request){ + serveSettings(request, true); }); server.on("/json", HTTP_GET, [](AsyncWebServerRequest *request){ @@ -112,18 +79,18 @@ void initServer() AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/json", [](AsyncWebServerRequest *request) { bool verboseResponse = false; { //scope JsonDocument so it releases its buffer - DynamicJsonDocument jsonBuffer(8192); + DynamicJsonDocument jsonBuffer(JSON_BUFFER_SIZE); DeserializationError error = deserializeJson(jsonBuffer, (uint8_t*)(request->_tempObject)); JsonObject root = jsonBuffer.as(); if (error || root.isNull()) { - request->send(400, "application/json", "{\"error\":10}"); return; + request->send(400, "application/json", F("{\"error\":9}")); return; } verboseResponse = deserializeState(root); } if (verboseResponse) { //if JSON contains "v" serveJson(request); return; } - request->send(200, "application/json", "{\"success\":true}"); + request->send(200, "application/json", F("{\"success\":true}")); }); server.addHandler(handler); @@ -181,7 +148,7 @@ void initServer() doReboot = true; },[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){ if(!index){ - DEBUG_PRINTLN("OTA Update Start"); + DEBUG_PRINTLN(F("OTA Update Start")); #ifdef ESP8266 Update.runAsync(true); #endif @@ -190,9 +157,9 @@ void initServer() if(!Update.hasError()) Update.write(data, len); if(final){ if(Update.end(true)){ - DEBUG_PRINTLN("Update Success"); + DEBUG_PRINTLN(F("Update Success")); } else { - DEBUG_PRINTLN("Update Failed"); + DEBUG_PRINTLN(F("Update Failed")); } } }); @@ -273,7 +240,7 @@ void serveIndex(AsyncWebServerRequest* request) AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", PAGE_index, PAGE_index_L); - response->addHeader("Content-Encoding","gzip"); + response->addHeader(F("Content-Encoding"),"gzip"); request->send(response); } @@ -283,19 +250,23 @@ String msgProcessor(const String& var) { if (var == "MSG") { String messageBody = messageHead; - messageBody += ""; + messageBody += F(""); messageBody += messageSub; uint32_t optt = optionType; if (optt < 60) //redirect to settings after optionType seconds { - messageBody += ""; + messageBody += F(""); } else if (optt < 120) //redirect back after optionType-60 seconds, unused { //messageBody += ""; } else if (optt < 180) //reload parent after optionType-120 seconds { - messageBody += ""; + messageBody += F(""); } else if (optt == 253) { messageBody += F("

"); //button to settings @@ -309,7 +280,7 @@ String msgProcessor(const String& var) } -void serveMessage(AsyncWebServerRequest* request, uint16_t code, String headl, String subl, byte optionT) +void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& headl, const String& subl, byte optionT) { messageHead = headl; messageSub = subl; @@ -359,7 +330,7 @@ String dmxProcessor(const String& var) } -void serveSettings(AsyncWebServerRequest* request) +void serveSettings(AsyncWebServerRequest* request, bool post) { byte subPage = 0; const String& url = request->url(); @@ -380,6 +351,31 @@ void serveSettings(AsyncWebServerRequest* request) { serveMessage(request, 500, "Access Denied", F("Please unlock OTA in security settings!"), 254); return; } + + if (post) { //settings/set POST request, saving + if (subPage != 1 || !(wifiLock && otaLock)) handleSettingsSet(request, subPage); + + char s[32]; + char s2[45] = ""; + + switch (subPage) { + case 1: strcpy_P(s, PSTR("WiFi")); strcpy_P(s2, PSTR("Please connect to the new IP (if changed)")); forceReconnect = true; break; + case 2: strcpy_P(s, PSTR("LED")); break; + case 3: strcpy_P(s, PSTR("UI")); break; + case 4: strcpy_P(s, PSTR("Sync")); break; + case 5: strcpy_P(s, PSTR("Time")); break; + case 6: strcpy_P(s, PSTR("Security")); strcpy_P(s2, PSTR("Rebooting, please wait ~10 seconds...")); break; + case 7: strcpy_P(s, PSTR("DMX")); break; + } + + strcat_P(s, PSTR(" settings saved.")); + if (!s2[0]) strcpy_P(s2, PSTR("Redirecting...")); + + if (!doReboot) serveMessage(request, 200, s, s2, (subPage == 1 || subPage == 6) ? 129 : 1); + if (subPage == 6) doReboot = true; + + return; + } #ifdef WLED_DISABLE_MOBILE_UI //disable welcome page if not enough storage if (subPage == 255) {serveIndex(request); return;} diff --git a/wled00/ws.cpp b/wled00/ws.cpp index affe043..2d17475 100644 --- a/wled00/ws.cpp +++ b/wled00/ws.cpp @@ -29,7 +29,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp { bool verboseResponse = false; { //scope JsonDocument so it releases its buffer - DynamicJsonDocument jsonBuffer(8192); + DynamicJsonDocument jsonBuffer(JSON_BUFFER_SIZE); DeserializationError error = deserializeJson(jsonBuffer, data, len); JsonObject root = jsonBuffer.as(); if (error || root.isNull()) return; @@ -57,7 +57,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp if((info->index + len) == info->len){ if(info->final){ if(info->message_opcode == WS_TEXT) { - client->text("{\"error\":10}"); //we do not handle split packets right now + client->text(F("{\"error\":9}")); //we do not handle split packets right now } } } @@ -77,7 +77,7 @@ void sendDataWs(AsyncWebSocketClient * client) AsyncWebSocketMessageBuffer * buffer; { //scope JsonDocument so it releases its buffer - DynamicJsonDocument doc(8192); + DynamicJsonDocument doc(JSON_BUFFER_SIZE); JsonObject state = doc.createNestedObject("state"); serializeState(state); JsonObject info = doc.createNestedObject("info"); diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 73c7b78..8db5c31 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -4,6 +4,9 @@ * Sending XML status files to client */ +//macro to convert F to const +#define SET_F(x) (const char*)F(x) + //build XML response to HTTP /win API request void XML_response(AsyncWebServerRequest *request, char* dest) { @@ -11,9 +14,9 @@ void XML_response(AsyncWebServerRequest *request, char* dest) obuf = (dest == nullptr)? sbuf:dest; olen = 0; - oappend((const char*)F("")); + oappend(SET_F("")); oappendi((nightlightActive && nightlightMode > NL_MODE_SET) ? briT : bri); - oappend(""); + oappend(SET_F("")); for (int i = 0; i < 3; i++) { @@ -27,47 +30,47 @@ void XML_response(AsyncWebServerRequest *request, char* dest) oappendi(colSec[i]); oappend(""); } - oappend(""); + oappend(SET_F("")); oappendi(notifyDirect); - oappend(""); + oappend(SET_F("")); oappendi(receiveNotifications); - oappend(""); + oappend(SET_F("")); oappendi(nightlightActive); - oappend(""); + oappend(SET_F("")); oappendi(nightlightMode > NL_MODE_SET); - oappend(""); + oappend(SET_F("")); oappendi(nightlightDelayMins); - oappend(""); + oappend(SET_F("")); oappendi(nightlightTargetBri); - oappend(""); + oappend(SET_F("")); oappendi(effectCurrent); - oappend(""); + oappend(SET_F("")); oappendi(effectSpeed); - oappend(""); + oappend(SET_F("")); oappendi(effectIntensity); - oappend(""); + oappend(SET_F("")); oappendi(effectPalette); - oappend(""); + oappend(SET_F("")); if (strip.rgbwMode) { oappendi(col[3]); } else { oappend("-1"); } - oappend(""); + oappend(SET_F("")); oappendi(colSec[3]); - oappend(""); + oappend(SET_F("")); oappendi((currentPreset < 1) ? 0:currentPreset); - oappend(""); + oappend(SET_F("")); oappendi(presetCyclingEnabled); - oappend(""); + oappend(SET_F("")); oappend(serverDescription); if (realtimeMode) { - oappend(" (live)"); + oappend(SET_F(" (live)")); } - oappend(""); + oappend(SET_F("")); oappendi(strip.getMainSegmentId()); - oappend(""); + oappend(SET_F("")); if (request != nullptr) request->send(200, "text/xml", obuf); } @@ -79,41 +82,41 @@ void URL_response(AsyncWebServerRequest *request) olen = 0; char s[16]; - oappend("http://"); + oappend(SET_F("http://")); IPAddress localIP = WiFi.localIP(); sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]); oappend(s); - oappend("/win&A="); + oappend(SET_F("/win&A=")); oappendi(bri); - oappend("&CL=h"); + oappend(SET_F("&CL=h")); for (int i = 0; i < 3; i++) { sprintf(s,"%02X", col[i]); oappend(s); } - oappend("&C2=h"); + oappend(SET_F("&C2=h")); for (int i = 0; i < 3; i++) { sprintf(s,"%02X", colSec[i]); oappend(s); } - oappend("&FX="); + oappend(SET_F("&FX=")); oappendi(effectCurrent); - oappend("&SX="); + oappend(SET_F("&SX=")); oappendi(effectSpeed); - oappend("&IX="); + oappend(SET_F("&IX=")); oappendi(effectIntensity); - oappend("&FP="); + oappend(SET_F("&FP=")); oappendi(effectPalette); obuf = sbuf; olen = 0; - oappend((const char*)F("")); + oappend(SET_F("\" target=\"_blank\">")); oappend(s2buf); - oappend((const char*)F("")); + oappend(SET_F("")); if (request != nullptr) request->send(200, "text/html", obuf); } @@ -142,7 +145,7 @@ void sappend(char stype, const char* key, int val) case 'i': //selectedIndex oappend(ds); oappend(key); - oappend(".selectedIndex="); + oappend(SET_F(".selectedIndex=")); oappendi(val); oappend(";"); break; @@ -162,9 +165,9 @@ void sappends(char stype, const char* key, char* val) oappend("\";"); break; case 'm': //message - oappend("d.getElementsByClassName"); + oappend(SET_F("d.getElementsByClassName")); oappend(key); - oappend(".innerHTML=\""); + oappend(SET_F(".innerHTML=\"")); oappend(val); oappend("\";"); break; @@ -176,7 +179,7 @@ void sappends(char stype, const char* key, char* val) void getSettingsJS(byte subPage, char* dest) { //0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec - DEBUG_PRINT("settings resp"); + DEBUG_PRINT(F("settings resp")); DEBUG_PRINTLN(subPage); obuf = dest; olen = 0; @@ -184,13 +187,13 @@ void getSettingsJS(byte subPage, char* dest) if (subPage <1 || subPage >7) return; if (subPage == 1) { - sappends('s',"CS",clientSSID); + sappends('s',SET_F("CS"),clientSSID); byte l = strlen(clientPass); char fpass[l+1]; //fill password field with *** fpass[l] = 0; memset(fpass,'*',l); - sappends('s',"CP",fpass); + sappends('s',SET_F("CP"),fpass); char k[3]; k[2] = 0; //IP addresses for (int i = 0; i<4; i++) @@ -201,19 +204,19 @@ void getSettingsJS(byte subPage, char* dest) k[0] = 'S'; sappend('v',k,staticSubnet[i]); } - sappends('s',"CM",cmDNS); - sappend('i',"AB",apBehavior); - sappends('s',"AS",apSSID); - sappend('c',"AH",apHide); + sappends('s',SET_F("CM"),cmDNS); + sappend('i',SET_F("AB"),apBehavior); + sappends('s',SET_F("AS"),apSSID); + sappend('c',SET_F("AH"),apHide); l = strlen(apPass); char fapass[l+1]; //fill password field with *** fapass[l] = 0; memset(fapass,'*',l); - sappends('s',"AP",fapass); + sappends('s',SET_F("AP"),fapass); - sappend('v',"AC",apChannel); - sappend('c',"WS",noWifiSleep); + sappend('v',SET_F("AC"),apChannel); + sappend('c',SET_F("WS"),noWifiSleep); if (WiFi.localIP()[0] != 0) //is connected @@ -221,10 +224,10 @@ void getSettingsJS(byte subPage, char* dest) char s[16]; IPAddress localIP = WiFi.localIP(); sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]); - sappends('m',"(\"sip\")[0]",s); + sappends('m',SET_F("(\"sip\")[0]"),s); } else { - sappends('m',"(\"sip\")[0]","Not connected"); + sappends('m',SET_F("(\"sip\")[0]"),(char*)F("Not connected")); } if (WiFi.softAPIP()[0] != 0) //is active @@ -232,114 +235,114 @@ void getSettingsJS(byte subPage, char* dest) char s[16]; IPAddress apIP = WiFi.softAPIP(); sprintf(s, "%d.%d.%d.%d", apIP[0], apIP[1], apIP[2], apIP[3]); - sappends('m',"(\"sip\")[1]",s); + sappends('m',SET_F("(\"sip\")[1]"),s); } else { - sappends('m',"(\"sip\")[1]","Not active"); + sappends('m',SET_F("(\"sip\")[1]"),(char*)F("Not active")); } } if (subPage == 2) { #ifdef ESP8266 #if LEDPIN == 3 - oappend("d.Sf.LC.max=500;"); + oappend(SET_F("d.Sf.LC.max=500;")); #endif #endif - sappend('v',"LC",ledCount); - sappend('v',"MA",strip.ablMilliampsMax); - sappend('v',"LA",strip.milliampsPerLed); + sappend('v',SET_F("LC"),ledCount); + sappend('v',SET_F("MA"),strip.ablMilliampsMax); + sappend('v',SET_F("LA"),strip.milliampsPerLed); if (strip.currentMilliamps) { - sappends('m',"(\"pow\")[0]",""); + sappends('m',SET_F("(\"pow\")[0]"),""); olen -= 2; //delete "; oappendi(strip.currentMilliamps); - oappend("mA\";"); + oappend(SET_F("mA\";")); } - sappend('v',"CA",briS); - sappend('c',"EW",useRGBW); - sappend('i',"CO",strip.colorOrder); - sappend('v',"AW",strip.rgbwMode); + sappend('v',SET_F("CA"),briS); + sappend('c',SET_F("EW"),useRGBW); + sappend('i',SET_F("CO"),strip.colorOrder); + sappend('v',SET_F("AW"),strip.rgbwMode); - sappend('c',"BO",turnOnAtBoot); - sappend('v',"BP",bootPreset); + sappend('c',SET_F("BO"),turnOnAtBoot); + sappend('v',SET_F("BP"),bootPreset); - sappend('c',"GB",strip.gammaCorrectBri); - sappend('c',"GC",strip.gammaCorrectCol); - sappend('c',"TF",fadeTransition); - sappend('v',"TD",transitionDelayDefault); - sappend('c',"PF",strip.paletteFade); - sappend('v',"BF",briMultiplier); - sappend('v',"TB",nightlightTargetBri); - sappend('v',"TL",nightlightDelayMinsDefault); - sappend('v',"TW",nightlightMode); - sappend('i',"PB",strip.paletteBlend); - sappend('c',"RV",strip.reverseMode); - sappend('c',"SL",skipFirstLed); + sappend('c',SET_F("GB"),strip.gammaCorrectBri); + sappend('c',SET_F("GC"),strip.gammaCorrectCol); + sappend('c',SET_F("TF"),fadeTransition); + sappend('v',SET_F("TD"),transitionDelayDefault); + sappend('c',SET_F("PF"),strip.paletteFade); + sappend('v',SET_F("BF"),briMultiplier); + sappend('v',SET_F("TB"),nightlightTargetBri); + sappend('v',SET_F("TL"),nightlightDelayMinsDefault); + sappend('v',SET_F("TW"),nightlightMode); + sappend('i',SET_F("PB"),strip.paletteBlend); + sappend('c',SET_F("RV"),strip.reverseMode); + sappend('c',SET_F("SL"),skipFirstLed); } if (subPage == 3) { - sappends('s',"DS",serverDescription); - sappend('c',"ST",syncToggleReceive); + sappends('s',SET_F("DS"),serverDescription); + sappend('c',SET_F("ST"),syncToggleReceive); } if (subPage == 4) { - sappend('c',"BT",buttonEnabled); - sappend('v',"IR",irEnabled); - sappend('v',"UP",udpPort); - sappend('c',"RB",receiveNotificationBrightness); - sappend('c',"RC",receiveNotificationColor); - sappend('c',"RX",receiveNotificationEffects); - sappend('c',"SD",notifyDirectDefault); - sappend('c',"SB",notifyButton); - sappend('c',"SH",notifyHue); - sappend('c',"SM",notifyMacro); - sappend('c',"S2",notifyTwice); - sappend('c',"RD",receiveDirect); - sappend('v',"EP",e131Port); - sappend('c',"ES",e131SkipOutOfSequence); - sappend('c',"EM",e131Multicast); - sappend('v',"EU",e131Universe); - sappend('v',"DA",DMXAddress); - sappend('v',"DM",DMXMode); - sappend('v',"ET",realtimeTimeoutMs); - sappend('c',"FB",arlsForceMaxBri); - sappend('c',"RG",arlsDisableGammaCorrection); - sappend('v',"WO",arlsOffset); - sappend('c',"AL",alexaEnabled); - sappends('s',"AI",alexaInvocationName); - sappend('c',"SA",notifyAlexa); - sappends('s',"BK",(char*)((blynkEnabled)?"Hidden":"")); + sappend('c',SET_F("BT"),buttonEnabled); + sappend('v',SET_F("IR"),irEnabled); + sappend('v',SET_F("UP"),udpPort); + sappend('c',SET_F("RB"),receiveNotificationBrightness); + sappend('c',SET_F("RC"),receiveNotificationColor); + sappend('c',SET_F("RX"),receiveNotificationEffects); + sappend('c',SET_F("SD"),notifyDirectDefault); + sappend('c',SET_F("SB"),notifyButton); + sappend('c',SET_F("SH"),notifyHue); + sappend('c',SET_F("SM"),notifyMacro); + sappend('c',SET_F("S2"),notifyTwice); + sappend('c',SET_F("RD"),receiveDirect); + sappend('v',SET_F("EP"),e131Port); + sappend('c',SET_F("ES"),e131SkipOutOfSequence); + sappend('c',SET_F("EM"),e131Multicast); + sappend('v',SET_F("EU"),e131Universe); + sappend('v',SET_F("DA"),DMXAddress); + sappend('v',SET_F("DM"),DMXMode); + sappend('v',SET_F("ET"),realtimeTimeoutMs); + sappend('c',SET_F("FB"),arlsForceMaxBri); + sappend('c',SET_F("RG"),arlsDisableGammaCorrection); + sappend('v',SET_F("WO"),arlsOffset); + sappend('c',SET_F("AL"),alexaEnabled); + sappends('s',SET_F("AI"),alexaInvocationName); + sappend('c',SET_F("SA"),notifyAlexa); + sappends('s',SET_F("BK"),(char*)((blynkEnabled)?SET_F("Hidden"):"")); #ifdef WLED_ENABLE_MQTT - sappend('c',"MQ",mqttEnabled); - sappends('s',"MS",mqttServer); - sappend('v',"MQPORT",mqttPort); - sappends('s',"MQUSER",mqttUser); - sappends('s',"MQPASS",mqttPass); + sappend('c',SET_F("MQ"),mqttEnabled); + sappends('s',SET_F("MS"),mqttServer); + sappend('v',SET_F("MQPORT"),mqttPort); + sappends('s',SET_F("MQUSER"),mqttUser); + sappends('s',SET_F("MQPASS"),mqttPass); byte l = strlen(mqttPass); char fpass[l+1]; //fill password field with *** fpass[l] = 0; memset(fpass,'*',l); - sappends('s',"MQPASS",fpass); - sappends('s',"MQCID",mqttClientID); - sappends('s',"MD",mqttDeviceTopic); - sappends('s',"MG",mqttGroupTopic); + sappends('s',SET_F("MQPASS"),fpass); + sappends('s',SET_F("MQCID"),mqttClientID); + sappends('s',SET_F("MD"),mqttDeviceTopic); + sappends('s',SET_F("MG"),mqttGroupTopic); #endif #ifndef WLED_DISABLE_HUESYNC - sappend('v',"H0",hueIP[0]); - sappend('v',"H1",hueIP[1]); - sappend('v',"H2",hueIP[2]); - sappend('v',"H3",hueIP[3]); - sappend('v',"HL",huePollLightId); - sappend('v',"HI",huePollIntervalMs); - sappend('c',"HP",huePollingEnabled); - sappend('c',"HO",hueApplyOnOff); - sappend('c',"HB",hueApplyBri); - sappend('c',"HC",hueApplyColor); + sappend('v',SET_F("H0"),hueIP[0]); + sappend('v',SET_F("H1"),hueIP[1]); + sappend('v',SET_F("H2"),hueIP[2]); + sappend('v',SET_F("H3"),hueIP[3]); + sappend('v',SET_F("HL"),huePollLightId); + sappend('v',SET_F("HI"),huePollIntervalMs); + sappend('c',SET_F("HP"),huePollingEnabled); + sappend('c',SET_F("HO"),hueApplyOnOff); + sappend('c',SET_F("HB"),hueApplyBri); + sappend('c',SET_F("HC"),hueApplyColor); char hueErrorString[25]; switch (hueError) { @@ -350,38 +353,38 @@ void getSettingsJS(byte subPage, char* dest) case HUE_ERROR_PUSHLINK : strcpy(hueErrorString,(char*)F("Link button not pressed")); break; case HUE_ERROR_JSON_PARSING : strcpy(hueErrorString,(char*)F("JSON parsing error")); break; case HUE_ERROR_TIMEOUT : strcpy(hueErrorString,(char*)F("Timeout")); break; - default: sprintf(hueErrorString,"Bridge Error %i",hueError); + default: sprintf(hueErrorString,(char*)F("Bridge Error %i"),hueError); } - sappends('m',"(\"sip\")[0]",hueErrorString); + sappends('m',SET_F("(\"sip\")[0]"),hueErrorString); #endif } if (subPage == 5) { - sappend('c',"NT",ntpEnabled); - sappends('s',"NS",ntpServerName); - sappend('c',"CF",!useAMPM); - sappend('i',"TZ",currentTimezone); - sappend('v',"UO",utcOffsetSecs); + sappend('c',SET_F("NT"),ntpEnabled); + sappends('s',SET_F("NS"),ntpServerName); + sappend('c',SET_F("CF"),!useAMPM); + sappend('i',SET_F("TZ"),currentTimezone); + sappend('v',SET_F("UO"),utcOffsetSecs); char tm[32]; getTimeString(tm); - sappends('m',"(\"times\")[0]",tm); - sappend('i',"OL",overlayCurrent); - sappend('v',"O1",overlayMin); - sappend('v',"O2",overlayMax); - sappend('v',"OM",analogClock12pixel); - sappend('c',"OS",analogClockSecondsTrail); - sappend('c',"O5",analogClock5MinuteMarks); - sappends('s',"CX",cronixieDisplay); - sappend('c',"CB",cronixieBacklight); - sappend('c',"CE",countdownMode); - sappend('v',"CY",countdownYear); - sappend('v',"CI",countdownMonth); - sappend('v',"CD",countdownDay); - sappend('v',"CH",countdownHour); - sappend('v',"CM",countdownMin); - sappend('v',"CS",countdownSec); + sappends('m',SET_F("(\"times\")[0]"),tm); + sappend('i',SET_F("OL"),overlayCurrent); + sappend('v',SET_F("O1"),overlayMin); + sappend('v',SET_F("O2"),overlayMax); + sappend('v',SET_F("OM"),analogClock12pixel); + sappend('c',SET_F("OS"),analogClockSecondsTrail); + sappend('c',SET_F("O5"),analogClock5MinuteMarks); + sappends('s',SET_F("CX"),cronixieDisplay); + sappend('c',SET_F("CB"),cronixieBacklight); + sappend('c',SET_F("CE"),countdownMode); + sappend('v',SET_F("CY"),countdownYear); + sappend('v',SET_F("CI"),countdownMonth); + sappend('v',SET_F("CD"),countdownDay); + sappend('v',SET_F("CH"),countdownHour); + sappend('v',SET_F("CM"),countdownMin); + sappend('v',SET_F("CS"),countdownSec); char k[4]; k[0]= 'M'; for (int i=1;i<17;i++) { @@ -391,14 +394,14 @@ void getSettingsJS(byte subPage, char* dest) sappends('s',k,m); } - sappend('v',"MB",macroBoot); - sappend('v',"A0",macroAlexaOn); - sappend('v',"A1",macroAlexaOff); - sappend('v',"MP",macroButton); - sappend('v',"ML",macroLongPress); - sappend('v',"MC",macroCountdown); - sappend('v',"MN",macroNl); - sappend('v',"MD",macroDoublePress); + sappend('v',SET_F("MB"),macroBoot); + sappend('v',SET_F("A0"),macroAlexaOn); + sappend('v',SET_F("A1"),macroAlexaOff); + sappend('v',SET_F("MP"),macroButton); + sappend('v',SET_F("ML"),macroLongPress); + sappend('v',SET_F("MC"),macroCountdown); + sappend('v',SET_F("MN"),macroNl); + sappend('v',SET_F("MD"),macroDoublePress); k[2] = 0; //Time macros for (int i = 0; i<8; i++) @@ -413,43 +416,43 @@ void getSettingsJS(byte subPage, char* dest) if (subPage == 6) { - sappend('c',"NO",otaLock); - sappend('c',"OW",wifiLock); - sappend('c',"AO",aOtaEnabled); - sappends('m',"(\"sip\")[0]","WLED "); + sappend('c',SET_F("NO"),otaLock); + sappend('c',SET_F("OW"),wifiLock); + sappend('c',SET_F("AO"),aOtaEnabled); + sappends('m',SET_F("(\"sip\")[0]"),(char*)F("WLED ")); olen -= 2; //delete "; oappend(versionString); - oappend(" (build "); + oappend(SET_F(" (build ")); oappendi(VERSION); - oappend(")\";"); + oappend(SET_F(")\";")); } #ifdef WLED_ENABLE_DMX // include only if DMX is enabled if (subPage == 7) { - sappend('v',"PU",e131ProxyUniverse); + sappend('v',SET_F("PU"),e131ProxyUniverse); - sappend('v',"CN",DMXChannels); - sappend('v',"CG",DMXGap); - sappend('v',"CS",DMXStart); - sappend('v',"SL",DMXStartLED); + sappend('v',SET_F("CN"),DMXChannels); + sappend('v',SET_F("CG"),DMXGap); + sappend('v',SET_F("CS"),DMXStart); + sappend('v',SET_F("SL"),DMXStartLED); - sappend('i',"CH1",DMXFixtureMap[0]); - sappend('i',"CH2",DMXFixtureMap[1]); - sappend('i',"CH3",DMXFixtureMap[2]); - sappend('i',"CH4",DMXFixtureMap[3]); - sappend('i',"CH5",DMXFixtureMap[4]); - sappend('i',"CH6",DMXFixtureMap[5]); - sappend('i',"CH7",DMXFixtureMap[6]); - sappend('i',"CH8",DMXFixtureMap[7]); - sappend('i',"CH9",DMXFixtureMap[8]); - sappend('i',"CH10",DMXFixtureMap[9]); - sappend('i',"CH11",DMXFixtureMap[10]); - sappend('i',"CH12",DMXFixtureMap[11]); - sappend('i',"CH13",DMXFixtureMap[12]); - sappend('i',"CH14",DMXFixtureMap[13]); - sappend('i',"CH15",DMXFixtureMap[14]); + sappend('i',SET_F("CH1"),DMXFixtureMap[0]); + sappend('i',SET_F("CH2"),DMXFixtureMap[1]); + sappend('i',SET_F("CH3"),DMXFixtureMap[2]); + sappend('i',SET_F("CH4"),DMXFixtureMap[3]); + sappend('i',SET_F("CH5"),DMXFixtureMap[4]); + sappend('i',SET_F("CH6"),DMXFixtureMap[5]); + sappend('i',SET_F("CH7"),DMXFixtureMap[6]); + sappend('i',SET_F("CH8"),DMXFixtureMap[7]); + sappend('i',SET_F("CH9"),DMXFixtureMap[8]); + sappend('i',SET_F("CH10"),DMXFixtureMap[9]); + sappend('i',SET_F("CH11"),DMXFixtureMap[10]); + sappend('i',SET_F("CH12"),DMXFixtureMap[11]); + sappend('i',SET_F("CH13"),DMXFixtureMap[12]); + sappend('i',SET_F("CH14"),DMXFixtureMap[13]); + sappend('i',SET_F("CH15"),DMXFixtureMap[14]); } #endif - oappend("}"); + oappend(SET_F("}")); }