From 1e5420e6a7582adb34f9953ae293e8907d3cdd59 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Fri, 25 Jun 2021 01:26:15 +0200 Subject: [PATCH] readFromConfig() update --- CHANGELOG.md | 6 ++++++ .../Animated_Staircase/Animated_Staircase.h | 6 +++++- usermods/EXAMPLE_v2/usermod_v2_example.h | 21 ++++++++++++++++--- .../usermod_Fix_unreachable_netservices.h | 4 +++- .../usermod_PIR_sensor_switch.h | 6 ++++-- .../usermod_sn_photoresistor.h | 4 +++- usermods/Temperature/usermod_temperature.h | 8 +++++-- usermods/multi_relay/usermod_multi_relay.h | 5 +++-- .../stairway-wipe-usermod-v2.h | 12 ----------- .../usermod_v2_auto_save.h | 5 +++-- .../usermod_v2_four_line_display.h | 7 ++++++- wled00/cfg.cpp | 10 +++++---- wled00/data/welcome.htm | 1 - wled00/fcn_declare.h | 4 ++-- wled00/html_other.h | 2 +- wled00/um_manager.cpp | 8 ++++++- wled00/usermods_list.cpp | 5 +++-- wled00/wled_eeprom.cpp | 4 ++++ 18 files changed, 80 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c2bb00c..8e6864f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ### Builds after release 0.12.0 +#### Build 2106241 + +- BREAKING: Added ability for usermods to force a config save if config incomplete. `readFromConfig()` needs to return a `bool` to indicate if the config is complete +- Updated usermods implementing `readFromConfig()` +- Auto-create segments based on configured busses + #### Build 2106200 - Added 2 Ethernet boards and split Ethernet configs into separate file diff --git a/usermods/Animated_Staircase/Animated_Staircase.h b/usermods/Animated_Staircase/Animated_Staircase.h index 696d33f3..e85db95b 100644 --- a/usermods/Animated_Staircase/Animated_Staircase.h +++ b/usermods/Animated_Staircase/Animated_Staircase.h @@ -427,7 +427,7 @@ class Animated_Staircase : public Usermod { /* * Reads the configuration to internal flash memory before setup() is called. */ - void readFromConfig(JsonObject& root) { + bool readFromConfig(JsonObject& root) { bool oldUseUSSensorTop = useUSSensorTop; bool oldUseUSSensorBottom = useUSSensorBottom; int8_t oldTopAPin = topPIRorTriggerPin; @@ -435,6 +435,8 @@ class Animated_Staircase : public Usermod { int8_t oldBottomAPin = bottomPIRorTriggerPin; int8_t oldBottomBPin = bottomEchoPin; + bool configComplete = true; + JsonObject staircase = root[FPSTR(_name)]; if (!staircase.isNull()) { if (staircase[FPSTR(_enabled)].is()) { @@ -468,6 +470,7 @@ class Animated_Staircase : public Usermod { bottomMaxDist = min(150,max(30,staircase[FPSTR(_bottomEchoCm)].as())); // max distance ~1.5m (a lag of 9ms may be expected) } else { DEBUG_PRINTLN(F("No config found. (Using defaults.)")); + configComplete = false; } if (!initDone) { // first run: reading from cfg.json @@ -490,6 +493,7 @@ class Animated_Staircase : public Usermod { } if (changed) setup(); } + return configComplete; } /* diff --git a/usermods/EXAMPLE_v2/usermod_v2_example.h b/usermods/EXAMPLE_v2/usermod_v2_example.h index db582a24..ac466935 100644 --- a/usermods/EXAMPLE_v2/usermod_v2_example.h +++ b/usermods/EXAMPLE_v2/usermod_v2_example.h @@ -133,13 +133,28 @@ class MyExampleUsermod : public Usermod { * readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes), * but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup. * If you don't know what that is, don't fret. It most likely doesn't affect your use case :) + * + * Return true in case your config was complete, or false if you'd like WLED to save your defaults to disk + * + * This function is guaranteed to be called on boot, but could also be called every time settings are updated */ - void readFromConfig(JsonObject& root) + bool readFromConfig(JsonObject& root) { - JsonObject top = root["top"]; + userVar0 = 42; //set your variables to their boot default value (this can also be done when declaring the variable) + + JsonObject top = root["exampleUsermod"]; if (!top.isNull()) { - userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot) + bool configComplete = true; + + //check if value is there + if (top.containsKey("great")) { + //convert value to the correct type + userVar0 = top["great"].as(); + } else configComplete = false; + + if (configComplete) return true; } + return false; } diff --git a/usermods/Fix_unreachable_netservices_v2/usermod_Fix_unreachable_netservices.h b/usermods/Fix_unreachable_netservices_v2/usermod_Fix_unreachable_netservices.h index cb2f1b0c..2e9f43c6 100644 --- a/usermods/Fix_unreachable_netservices_v2/usermod_Fix_unreachable_netservices.h +++ b/usermods/Fix_unreachable_netservices_v2/usermod_Fix_unreachable_netservices.h @@ -149,11 +149,13 @@ Delay ())); // check bounds @@ -399,6 +399,8 @@ public: DEBUG_PRINTLN(F("PIR config (re)loaded.")); } } + + return true; } /** diff --git a/usermods/SN_Photoresistor/usermod_sn_photoresistor.h b/usermods/SN_Photoresistor/usermod_sn_photoresistor.h index 3fd1fafa..ac86f390 100644 --- a/usermods/SN_Photoresistor/usermod_sn_photoresistor.h +++ b/usermods/SN_Photoresistor/usermod_sn_photoresistor.h @@ -169,7 +169,7 @@ public: /** * readFromConfig() is called before setup() to populate properties from values stored in cfg.json */ - void readFromConfig(JsonObject &root) + bool readFromConfig(JsonObject &root) { // we look for JSON object. JsonObject top = root[FPSTR(_name)]; @@ -196,7 +196,9 @@ public: else { DEBUG_PRINTLN(F("No config found. (Using defaults.)")); + return false; } + return true; } }; diff --git a/usermods/Temperature/usermod_temperature.h b/usermods/Temperature/usermod_temperature.h index 3a6bbfc4..8b418dc4 100644 --- a/usermods/Temperature/usermod_temperature.h +++ b/usermods/Temperature/usermod_temperature.h @@ -249,11 +249,13 @@ class UsermodTemperature : public Usermod { /** * readFromConfig() is called before setup() to populate properties from values stored in cfg.json */ - void readFromConfig(JsonObject &root) { + bool readFromConfig(JsonObject &root) { // we look for JSON object: {"Temperature": {"pin": 0, "degC": true}} JsonObject top = root[FPSTR(_name)]; int8_t newTemperaturePin = temperaturePin; + bool configComplete = true; + if (!top.isNull() && top["pin"] != nullptr) { if (top[FPSTR(_enabled)].is()) { disabled = !top[FPSTR(_enabled)].as(); @@ -274,13 +276,14 @@ class UsermodTemperature : public Usermod { DEBUG_PRINTLN(F("Temperature config (re)loaded.")); } else { DEBUG_PRINTLN(F("No config found. (Using defaults.)")); + configComplete = false; } if (!initDone) { // first run: reading from cfg.json temperaturePin = newTemperaturePin; } else { - // changing paramters from settings page + // changing parameters from settings page if (newTemperaturePin != temperaturePin) { // deallocate pin and release memory delete oneWire; @@ -290,6 +293,7 @@ class UsermodTemperature : public Usermod { setup(); } } + return configComplete; } uint16_t getId() diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/usermod_multi_relay.h index 42fe39e4..36e35ec4 100644 --- a/usermods/multi_relay/usermod_multi_relay.h +++ b/usermods/multi_relay/usermod_multi_relay.h @@ -348,11 +348,11 @@ class MultiRelay : public Usermod { * restore the changeable values * readFromConfig() is called before setup() to populate properties from values stored in cfg.json */ - void readFromConfig(JsonObject &root) { + bool readFromConfig(JsonObject &root) { int8_t oldPin[MULTI_RELAY_MAX_RELAYS]; JsonObject top = root[FPSTR(_name)]; - if (top.isNull()) return; + if (top.isNull()) return false; if (top[FPSTR(_enabled)] != nullptr) { if (top[FPSTR(_enabled)].is()) { @@ -413,6 +413,7 @@ class MultiRelay : public Usermod { } DEBUG_PRINTLN(F("MultiRelay config (re)loaded.")); } + return true; } /** diff --git a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h index 8d8bcf0b..816b6e8d 100644 --- a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h +++ b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h @@ -82,18 +82,6 @@ class StairwayWipeUsermod : public Usermod { //if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!")); } - void addToConfig(JsonObject& root) - { - JsonObject top = root.createNestedObject("exampleUsermod"); - top["great"] = userVar0; //save this var persistently whenever settings are saved - } - - void readFromConfig(JsonObject& root) - { - JsonObject top = root["top"]; - userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot) - } - uint16_t getId() { return USERMOD_ID_EXAMPLE; diff --git a/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h b/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h index caf542e5..e0f45da4 100644 --- a/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h +++ b/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h @@ -198,12 +198,12 @@ class AutoSaveUsermod : public Usermod { * but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup. * If you don't know what that is, don't fret. It most likely doesn't affect your use case :) */ - void readFromConfig(JsonObject& root) { + bool readFromConfig(JsonObject& root) { // we look for JSON object: {"Autosave": {"autoSaveAfterSec": 10, "autoSavePreset": 99}} JsonObject top = root[FPSTR(_name)]; if (top.isNull()) { DEBUG_PRINTLN(F("No config found. (Using defaults.)")); - return; + return false; } if (top[FPSTR(_autoSaveEnabled)].is()) { @@ -225,6 +225,7 @@ class AutoSaveUsermod : public Usermod { applyAutoSaveOnBoot = (bool)(str!="off"); // off is guaranteed to be present } DEBUG_PRINTLN(F("Autosave config (re)loaded.")); + return true; } /* diff --git a/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h b/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h index 999054e5..84593b38 100644 --- a/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h +++ b/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h @@ -615,12 +615,14 @@ class FourLineDisplayUsermod : public Usermod { * but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup. * If you don't know what that is, don't fret. It most likely doesn't affect your use case :) */ - void readFromConfig(JsonObject& root) { + bool readFromConfig(JsonObject& root) { bool needsRedraw = false; DisplayType newType = type; int8_t newScl = sclPin; int8_t newSda = sdaPin; + bool configComplete = true; + JsonObject top = root[FPSTR(_name)]; if (!top.isNull() && top["pin"] != nullptr) { newScl = top["pin"][0]; @@ -653,6 +655,7 @@ class FourLineDisplayUsermod : public Usermod { DEBUG_PRINTLN(F("4 Line Display config (re)loaded.")); } else { DEBUG_PRINTLN(F("No config found. (Using defaults.)")); + configComplete = false; } if (!initDone) { @@ -684,6 +687,8 @@ class FourLineDisplayUsermod : public Usermod { setFlipMode(flip); if (needsRedraw && !wakeDisplay()) redraw(true); } + + return configComplete; } /* diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index a65d0434..17047387 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -410,7 +410,10 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { DEBUG_PRINTLN(F("Starting usermod config.")); JsonObject usermods_settings = doc["um"]; - if (!usermods_settings.isNull()) usermods.readFromConfig(usermods_settings); + if (!usermods_settings.isNull()) { + bool allComplete = usermods.readFromConfig(usermods_settings); + if (!allComplete && fromFS) serializeConfig(); + } if (fromFS) return false; doReboot = doc[F("rb")] | doReboot; @@ -418,11 +421,10 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { } void deserializeConfigFromFS() { - bool fromeep = false; bool success = deserializeConfigSec(); if (!success) { //if file does not exist, try reading from EEPROM deEEPSettings(); - fromeep = true; + return; } DynamicJsonDocument doc(JSON_BUFFER_SIZE); @@ -431,7 +433,7 @@ void deserializeConfigFromFS() { success = readObjectFromFile("/cfg.json", nullptr, &doc); if (!success) { //if file does not exist, try reading from EEPROM - if (!fromeep) deEEPSettings(); + deEEPSettings(); return; } diff --git a/wled00/data/welcome.htm b/wled00/data/welcome.htm index 1b2bb60f..8d02e665 100644 --- a/wled00/data/welcome.htm +++ b/wled00/data/welcome.htm @@ -27,7 +27,6 @@ color: white; border: 0px solid white; border-radius: 25px; - filter: drop-shadow(0px 0px 1px #000); } img { diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index e624e524..405c14f2 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -189,7 +189,7 @@ class Usermod { virtual void addToJsonInfo(JsonObject& obj) {} virtual void readFromJsonState(JsonObject& obj) {} virtual void addToConfig(JsonObject& obj) {} - virtual void readFromConfig(JsonObject& obj) {} + virtual bool readFromConfig(JsonObject& obj) { return true; } //Heads up! readFromConfig() now needs to return a bool virtual void onMqttConnect(bool sessionPresent) {} virtual bool onMqttMessage(char* topic, char* payload) { return false; } virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;} @@ -211,7 +211,7 @@ class UsermodManager { void readFromJsonState(JsonObject& obj); void addToConfig(JsonObject& obj); - void readFromConfig(JsonObject& obj); + bool readFromConfig(JsonObject& obj); void onMqttConnect(bool sessionPresent); bool onMqttMessage(char* topic, char* payload); bool add(Usermod* um); diff --git a/wled00/html_other.h b/wled00/html_other.h index 19d6667e..ecc68af7 100644 --- a/wled00/html_other.h +++ b/wled00/html_other.h @@ -55,7 +55,7 @@ Please do not close or refresh the page :))====="; const char PAGE_welcome[] PROGMEM = R"=====(Welcome!

Welcome to WLED!

diff --git a/wled00/um_manager.cpp b/wled00/um_manager.cpp index e516be17..040a8450 100644 --- a/wled00/um_manager.cpp +++ b/wled00/um_manager.cpp @@ -13,7 +13,13 @@ void UsermodManager::addToJsonState(JsonObject& obj) { for (byte i = 0; i < n void UsermodManager::addToJsonInfo(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->addToJsonInfo(obj); } void UsermodManager::readFromJsonState(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->readFromJsonState(obj); } void UsermodManager::addToConfig(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->addToConfig(obj); } -void UsermodManager::readFromConfig(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->readFromConfig(obj); } +bool UsermodManager::readFromConfig(JsonObject& obj) { + bool allComplete = true; + for (byte i = 0; i < numMods; i++) { + if (!ums[i]->readFromConfig(obj)) allComplete = false; + } + return allComplete; +} void UsermodManager::onMqttConnect(bool sessionPresent) { for (byte i = 0; i < numMods; i++) ums[i]->onMqttConnect(sessionPresent); } bool UsermodManager::onMqttMessage(char* topic, char* payload) { for (byte i = 0; i < numMods; i++) if (ums[i]->onMqttMessage(topic, payload)) return true; diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index e1586a23..4f95dcdd 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -9,7 +9,8 @@ * || || || * \/ \/ \/ */ -//#include "usermod_v2_example.h" +#include "../usermods/EXAMPLE_v2/usermod_v2_example.h" + #ifdef USERMOD_DALLASTEMPERATURE #include "../usermods/Temperature/usermod_temperature.h" #endif @@ -80,7 +81,7 @@ void registerUsermods() * || || || * \/ \/ \/ */ - //usermods.add(new MyExampleUsermod()); + usermods.add(new MyExampleUsermod()); #ifdef USERMOD_DALLASTEMPERATURE usermods.add(new UsermodTemperature()); diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp index f1fd7b5a..bab8d305 100644 --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -479,5 +479,9 @@ void deEEPSettings() { loadSettingsFromEEPROM(); EEPROM.end(); + //call readFromConfig() with an empty object so that usermods can initialize to defaults prior to saving + JsonObject empty = JsonObject(); + usermods.readFromConfig(empty); + serializeConfig(); } \ No newline at end of file