diff --git a/wled00/presets.cpp b/wled00/presets.cpp index 9023baf344..e4c43c3695 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -160,9 +160,6 @@ void handlePresets() JsonObject fdo; - presetToApply = 0; //clear request for preset - callModeToApply = 0; - DEBUG_PRINTF_P(PSTR("Applying preset: %u\n"), (unsigned)tmpPreset); #if defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3) @@ -176,13 +173,31 @@ void handlePresets() } else #endif { - presetErrFlag = readObjectFromFileUsingId(getPresetsFileName(tmpPreset < 255), tmpPreset, pDoc) ? ERR_NONE : ERR_FS_PLOAD; + presetErrFlag = readObjectFromFileUsingId(getPresetsFileName(tmpPreset < 255), tmpPreset, pDoc) ? ERR_NONE : ERR_FS_PLOAD; } fdo = pDoc->as(); - // only reset errorflag if previous error was preset-related + // only reset error flag if previous error was preset-related if ((errorFlag == ERR_NONE) || (errorFlag == ERR_FS_PLOAD)) errorFlag = presetErrFlag; + // is this the boot preset and will the preset set lor + const bool isBootPreset = (tmpMode==CALL_MODE_INIT || tmpPreset==bootPreset); + const bool presetWillSetLor = (!fdo["lor"].isNull() && fdo["lor"].as() > REALTIME_OVERRIDE_NONE); + + // During setup, only allow the boot preset itself or safe boot-preset chains. + const bool shouldAllowPresetApply = ( + setupComplete || isBootPreset || + (currentPreset == bootPreset && realtimeOverride > REALTIME_OVERRIDE_NONE) || + (currentPreset == bootPreset && currentPlaylist > 0 && presetWillSetLor) + ); + if (shouldAllowPresetApply) { + presetToApply = 0; //clear request for preset + callModeToApply = 0; + } else { + releaseJSONBufferLock(); + return; + } + //HTTP API commands const char* httpwin = fdo["win"]; if (httpwin) { @@ -194,8 +209,11 @@ void handlePresets() changePreset = true; } else { if (!fdo["seg"].isNull() || !fdo["on"].isNull() || !fdo["bri"].isNull() || !fdo["nl"].isNull() || !fdo["ps"].isNull() || !fdo[F("playlist")].isNull()) changePreset = true; - if (!(tmpMode == CALL_MODE_BUTTON_PRESET && fdo["ps"].is() && strchr(fdo["ps"].as(),'~') != strrchr(fdo["ps"].as(),'~'))) - fdo.remove("ps"); // remove load request for presets to prevent recursive crash (if not called by button and contains preset cycling string "1~5~") + + // only allow load requests from boot presets that set lor or button calls + const bool isButtonException = (tmpMode == CALL_MODE_BUTTON_PRESET && fdo["ps"].is() && strchr(fdo["ps"].as(),'~') != strrchr(fdo["ps"].as(),'~')); + const bool shouldAllowLoadRequest = (isBootPreset && presetWillSetLor) || (tmpMode == CALL_MODE_BUTTON_PRESET && fdo["ps"].is() && strchr(fdo["ps"].as(),'~') != strrchr(fdo["ps"].as(),'~')); + if (!shouldAllowLoadRequest) fdo.remove("ps"); // remove load request for presets to prevent recursive crash deserializeState(fdo, CALL_MODE_NO_NOTIFY, tmpPreset); // may change presetToApply by calling applyPreset() } if (!errorFlag && tmpPreset < 255 && changePreset) currentPreset = tmpPreset; @@ -282,4 +300,4 @@ void deletePreset(byte index) { writeObjectToFileUsingId(getPresetsFileName(), index, &empty); presetsModifiedTime = toki.second(); //unix time updateFSInfo(); -} \ No newline at end of file +} diff --git a/wled00/wled.cpp b/wled00/wled.cpp index eb6019e6bf..67cb825ae1 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -364,6 +364,7 @@ void WLED::disableWatchdog() { void WLED::setup() { + setupComplete = false; // flag to indicate setup is in progress #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detection #endif @@ -503,6 +504,12 @@ void WLED::setup() if (needsCfgSave) serializeConfigToFS(); // usermods required new parameters; need to wait for strip to be initialised #4752 + if (bootPreset > 0) { + handlePresets(); // handle boot preset + handlePlaylist(); // handle playlist if preset queued one + handlePresets(); // handle presets again to give a chance for anything queued by the boot preset or playlist + } + if (strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) == 0 && !configBackupExists()) showWelcomePage = true; @@ -595,6 +602,8 @@ void WLED::setup() WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); //enable brownout detector #endif markOTAvalid(); + + setupComplete = true; // safety check setup function has completed } void WLED::beginStrip() diff --git a/wled00/wled.h b/wled00/wled.h index 1a5f1b143e..6ea137ced0 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -890,6 +890,9 @@ WLED_GLOBAL byte optionType; WLED_GLOBAL bool configNeedsWrite _INIT(false); // flag to initiate saving of config WLED_GLOBAL bool doReboot _INIT(false); // flag to initiate reboot from async handlers +// setup status +WLED_GLOBAL bool setupComplete _INIT(false); // flag for preset loading safety + // status led #if defined(STATUSLED) WLED_GLOBAL unsigned long ledStatusLastMillis _INIT(0);