Merge pull request #4609 from willmmiles/usermod-cfg-live

Use live cfg json instead of file for usermod settings page
This commit is contained in:
netmindz 2025-04-06 09:28:45 +00:00 committed by GitHub
commit e979c58c98
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 55 additions and 54 deletions

View File

@ -671,7 +671,7 @@ void deserializeConfigFromFS() {
// call readFromConfig() with an empty object so that usermods can initialize to defaults prior to saving
JsonObject empty = JsonObject();
UsermodManager::readFromConfig(empty);
serializeConfig();
serializeConfigToFS();
// init Ethernet (in case default type is set at compile time)
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET)
initEthernet();
@ -685,10 +685,10 @@ void deserializeConfigFromFS() {
bool needsSave = deserializeConfig(root, true);
releaseJSONBufferLock();
if (needsSave) serializeConfig(); // usermods required new parameters
if (needsSave) serializeConfigToFS(); // usermods required new parameters
}
void serializeConfig() {
void serializeConfigToFS() {
serializeConfigSec();
DEBUG_PRINTLN(F("Writing settings to /cfg.json..."));
@ -697,6 +697,17 @@ void serializeConfig() {
JsonObject root = pDoc->to<JsonObject>();
serializeConfig(root);
File f = WLED_FS.open(FPSTR(s_cfg_json), "w");
if (f) serializeJson(root, f);
f.close();
releaseJSONBufferLock();
configNeedsWrite = false;
}
void serializeConfig(JsonObject root) {
JsonArray rev = root.createNestedArray("rev");
rev.add(1); //major settings revision
rev.add(0); //minor settings revision
@ -1111,13 +1122,6 @@ void serializeConfig() {
JsonObject usermods_settings = root.createNestedObject("um");
UsermodManager::addToConfig(usermods_settings);
File f = WLED_FS.open(FPSTR(s_cfg_json), "w");
if (f) serializeJson(root, f);
f.close();
releaseJSONBufferLock();
doSerializeConfig = false;
}

View File

@ -13,7 +13,7 @@
function S() {
getLoc();
// load settings and insert values into DOM
fetch(getURL('/cfg.json'), {
fetch(getURL('/json/cfg'), {
method: 'get'
})
.then(res => {

View File

@ -22,7 +22,7 @@ void rdmPersonalityChangedCb(dmx_port_t dmxPort, const rdm_header_t *header,
if (header->cc == RDM_CC_SET_COMMAND_RESPONSE) {
const uint8_t personality = dmx_get_current_personality(dmx->inputPortNum);
DMXMode = std::min(DMX_MODE_PRESET, std::max(DMX_MODE_SINGLE_RGB, int(personality)));
doSerializeConfig = true;
configNeedsWrite = true;
DEBUG_PRINTF("DMX personality changed to to: %d\n", DMXMode);
}
}
@ -40,7 +40,7 @@ void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header,
if (header->cc == RDM_CC_SET_COMMAND_RESPONSE) {
const uint16_t addr = dmx_get_start_address(dmx->inputPortNum);
DMXAddress = std::min(512, int(addr));
doSerializeConfig = true;
configNeedsWrite = true;
DEBUG_PRINTF("DMX start addr changed to: %d\n", DMXAddress);
}
}

View File

@ -27,7 +27,8 @@ void IRAM_ATTR touchButtonISR();
bool deserializeConfig(JsonObject doc, bool fromFS = false);
void deserializeConfigFromFS();
bool deserializeConfigSec();
void serializeConfig();
void serializeConfig(JsonObject doc);
void serializeConfigToFS();
void serializeConfigSec();
template<typename DestType>

View File

@ -272,5 +272,5 @@ void parseWiFiCommand(char* rpcData) {
improvActive = 2;
forceReconnect = true;
serializeConfig();
serializeConfigToFS();
}

View File

@ -2,15 +2,6 @@
#include "palettes.h"
#define JSON_PATH_STATE 1
#define JSON_PATH_INFO 2
#define JSON_PATH_STATE_INFO 3
#define JSON_PATH_NODES 4
#define JSON_PATH_PALETTES 5
#define JSON_PATH_FXDATA 6
#define JSON_PATH_NETWORKS 7
#define JSON_PATH_EFFECTS 8
/*
* JSON API (De)serialization
*/
@ -1036,16 +1027,21 @@ class LockedJsonResponse: public AsyncJsonResponse {
void serveJson(AsyncWebServerRequest* request)
{
byte subJson = 0;
enum class json_target {
all, state, info, state_info, nodes, effects, palettes, fxdata, networks, config
};
json_target subJson = json_target::all;
const String& url = request->url();
if (url.indexOf("state") > 0) subJson = JSON_PATH_STATE;
else if (url.indexOf("info") > 0) subJson = JSON_PATH_INFO;
else if (url.indexOf("si") > 0) subJson = JSON_PATH_STATE_INFO;
else if (url.indexOf(F("nodes")) > 0) subJson = JSON_PATH_NODES;
else if (url.indexOf(F("eff")) > 0) subJson = JSON_PATH_EFFECTS;
else if (url.indexOf(F("palx")) > 0) subJson = JSON_PATH_PALETTES;
else if (url.indexOf(F("fxda")) > 0) subJson = JSON_PATH_FXDATA;
else if (url.indexOf(F("net")) > 0) subJson = JSON_PATH_NETWORKS;
if (url.indexOf("state") > 0) subJson = json_target::state;
else if (url.indexOf("info") > 0) subJson = json_target::info;
else if (url.indexOf("si") > 0) subJson = json_target::state_info;
else if (url.indexOf(F("nodes")) > 0) subJson = json_target::nodes;
else if (url.indexOf(F("eff")) > 0) subJson = json_target::effects;
else if (url.indexOf(F("palx")) > 0) subJson = json_target::palettes;
else if (url.indexOf(F("fxda")) > 0) subJson = json_target::fxdata;
else if (url.indexOf(F("net")) > 0) subJson = json_target::networks;
else if (url.indexOf(F("cfg")) > 0) subJson = json_target::config;
#ifdef WLED_ENABLE_JSONLIVE
else if (url.indexOf("live") > 0) {
serveLiveLeds(request);
@ -1056,9 +1052,6 @@ void serveJson(AsyncWebServerRequest* request)
request->send_P(200, FPSTR(CONTENT_TYPE_JSON), JSON_palette_names);
return;
}
else if (url.indexOf(F("cfg")) > 0 && handleFileRead(request, F("/cfg.json"))) {
return;
}
else if (url.length() > 6) { //not just /json
serveJsonError(request, 501, ERR_NOT_IMPL);
return;
@ -1070,32 +1063,35 @@ void serveJson(AsyncWebServerRequest* request)
}
// releaseJSONBufferLock() will be called when "response" is destroyed (from AsyncWebServer)
// make sure you delete "response" if no "request->send(response);" is made
LockedJsonResponse *response = new LockedJsonResponse(pDoc, subJson==JSON_PATH_FXDATA || subJson==JSON_PATH_EFFECTS); // will clear and convert JsonDocument into JsonArray if necessary
LockedJsonResponse *response = new LockedJsonResponse(pDoc, subJson==json_target::fxdata || subJson==json_target::effects); // will clear and convert JsonDocument into JsonArray if necessary
JsonVariant lDoc = response->getRoot();
switch (subJson)
{
case JSON_PATH_STATE:
case json_target::state:
serializeState(lDoc); break;
case JSON_PATH_INFO:
case json_target::info:
serializeInfo(lDoc); break;
case JSON_PATH_NODES:
case json_target::nodes:
serializeNodes(lDoc); break;
case JSON_PATH_PALETTES:
case json_target::palettes:
serializePalettes(lDoc, request->hasParam(F("page")) ? request->getParam(F("page"))->value().toInt() : 0); break;
case JSON_PATH_EFFECTS:
case json_target::effects:
serializeModeNames(lDoc); break;
case JSON_PATH_FXDATA:
case json_target::fxdata:
serializeModeData(lDoc); break;
case JSON_PATH_NETWORKS:
case json_target::networks:
serializeNetworks(lDoc); break;
default: //all
case json_target::config:
serializeConfig(lDoc); break;
case json_target::state_info:
case json_target::all:
JsonObject state = lDoc.createNestedObject("state");
serializeState(state);
JsonObject info = lDoc.createNestedObject("info");
serializeInfo(info);
if (subJson != JSON_PATH_STATE_INFO)
if (subJson == json_target::all)
{
JsonArray effects = lDoc.createNestedArray(F("effects"));
serializeModeNames(effects); // remove WLED-SR extensions from effect names

View File

@ -242,7 +242,7 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
if (!sObj[FPSTR(bootPS)].isNull()) {
bootPreset = sObj[FPSTR(bootPS)] | bootPreset;
sObj.remove(FPSTR(bootPS));
doSerializeConfig = true;
configNeedsWrite = true;
}
if (sObj.size()==0 || sObj["o"].isNull()) { // no "o" means not a playlist or custom API call, saving of state is async (not immediately)

View File

@ -805,8 +805,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
lastEditTime = millis();
// do not save if factory reset or LED settings (which are saved after LED re-init)
doSerializeConfig = subPage != SUBPAGE_LEDS && !(subPage == SUBPAGE_SEC && doReboot);
if (subPage == SUBPAGE_UM) doReboot = request->hasArg(F("RBT")); // prevent race condition on dual core system (set reboot here, after doSerializeConfig has been set)
configNeedsWrite = subPage != SUBPAGE_LEDS && !(subPage == SUBPAGE_SEC && doReboot);
if (subPage == SUBPAGE_UM) doReboot = request->hasArg(F("RBT")); // prevent race condition on dual core system (set reboot here, after configNeedsWrite has been set)
#ifndef WLED_DISABLE_ALEXA
if (subPage == SUBPAGE_SYNC) alexaInit();
#endif

View File

@ -193,14 +193,14 @@ void WLED::loop()
if (aligned) strip.makeAutoSegments();
else strip.fixInvalidSegments();
BusManager::setBrightness(bri); // fix re-initialised bus' brightness
doSerializeConfig = true;
configNeedsWrite = true;
}
if (loadLedmap >= 0) {
strip.deserializeMap(loadLedmap);
loadLedmap = -1;
}
yield();
if (doSerializeConfig) serializeConfig();
if (configNeedsWrite) serializeConfigToFS();
yield();
handleWs();
@ -223,7 +223,7 @@ void WLED::loop()
}
#endif
if (doReboot && (!doInitBusses || !doSerializeConfig)) // if busses have to be inited & saved, wait until next iteration
if (doReboot && (!doInitBusses || !configNeedsWrite)) // if busses have to be inited & saved, wait until next iteration
reset();
// DEBUG serial logging (every 30s)

View File

@ -877,7 +877,7 @@ WLED_GLOBAL byte errorFlag _INIT(0);
WLED_GLOBAL String messageHead, messageSub;
WLED_GLOBAL byte optionType;
WLED_GLOBAL bool doSerializeConfig _INIT(false); // flag to initiate saving of config
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
WLED_GLOBAL bool psramSafe _INIT(true); // is it safe to use PSRAM (on ESP32 rev.1; compiler fix used "-mfix-esp32-psram-cache-issue")

View File

@ -328,7 +328,7 @@ void initServer()
interfaceUpdateCallMode = CALL_MODE_WS_SEND; // schedule WS update
serveJson(request); return; //if JSON contains "v"
} else {
doSerializeConfig = true; //serializeConfig(); //Save new settings to FS
configNeedsWrite = true; //Save new settings to FS
}
}
request->send(200, CONTENT_TYPE_JSON, F("{\"success\":true}"));