From f7ce83ea34b8bb55dd503cfe98ee9427ddb5f48b Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sun, 27 Jun 2021 12:15:35 +0200 Subject: [PATCH] V2 of usermod configuration settings - added parsing of POST fields to use proper type - updated readFromConfig() to reflect parsing - added a possibility to use nested object in UM settings - internal changes and fixes --- .../Animated_Staircase/Animated_Staircase.h | 77 +++++++++---------- usermods/EXAMPLE_v2/usermod_v2_example.h | 21 +++-- .../usermod_Fix_unreachable_netservices.h | 1 + .../usermod_PIR_sensor_switch.h | 63 +++++---------- .../usermod_sn_photoresistor.h | 37 ++++----- usermods/Temperature/usermod_temperature.h | 75 +++++++----------- usermods/multi_relay/usermod_multi_relay.h | 56 +++++--------- .../usermod_v2_auto_save.h | 42 ++++------ .../usermod_v2_four_line_display.h | 59 +++++--------- wled00/data/settings_um.htm | 27 ++++--- wled00/data/style.css | 8 +- wled00/html_settings.h | 4 +- wled00/set.cpp | 25 +++--- 13 files changed, 204 insertions(+), 291 deletions(-) diff --git a/usermods/Animated_Staircase/Animated_Staircase.h b/usermods/Animated_Staircase/Animated_Staircase.h index e85db95b..af9e89dd 100644 --- a/usermods/Animated_Staircase/Animated_Staircase.h +++ b/usermods/Animated_Staircase/Animated_Staircase.h @@ -426,6 +426,8 @@ class Animated_Staircase : public Usermod { /* * Reads the configuration to internal flash memory before setup() is called. + * + * The function should return true if configuration was successfully loaded or false if there was no configuration. */ bool readFromConfig(JsonObject& root) { bool oldUseUSSensorTop = useUSSensorTop; @@ -435,49 +437,45 @@ 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()) { - enabled = staircase[FPSTR(_enabled)].as(); - } else { - String str = staircase[FPSTR(_enabled)]; // checkbox -> off or on - enabled = (bool)(str!="off"); // off is guaranteed to be present - } - segment_delay_ms = min(10000,max(10,staircase[FPSTR(_segmentDelay)].as())); // max delay 10s - on_time_ms = min(900,max(10,staircase[FPSTR(_onTime)].as())) * 1000; // min 10s, max 15min - - if (staircase[FPSTR(_useTopUltrasoundSensor)].is()) { - useUSSensorTop = staircase[FPSTR(_useTopUltrasoundSensor)].as(); - } else { - String str = staircase[FPSTR(_useTopUltrasoundSensor)]; // checkbox -> off or on - useUSSensorTop = (bool)(str!="off"); // off is guaranteed to be present - } - - topPIRorTriggerPin = min(39,max(-1,staircase[FPSTR(_topPIRorTrigger_pin)].as())); - topEchoPin = min(39,max(-1,staircase[FPSTR(_topEcho_pin)].as())); - - if (staircase[FPSTR(_useBottomUltrasoundSensor)].is()) { - useUSSensorBottom = staircase[FPSTR(_useBottomUltrasoundSensor)].as(); - } else { - String str = staircase[FPSTR(_useBottomUltrasoundSensor)]; // checkbox -> off or on - useUSSensorBottom = (bool)(str!="off"); // off is guaranteed to be present - } - bottomPIRorTriggerPin = min(39,max(-1,staircase[FPSTR(_bottomPIRorTrigger_pin)].as())); - bottomEchoPin = min(39,max(-1,staircase[FPSTR(_bottomEcho_pin)].as())); - topMaxDist = min(150,max(30,staircase[FPSTR(_topEchoCm)].as())); // max distnace ~1.5m (a lag of 9ms may be expected) - 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; + JsonObject top = root[FPSTR(_name)]; + if (top.isNull()) { + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); + return false; } + + enabled = top[FPSTR(_enabled)] | enabled; + + segment_delay_ms = top[FPSTR(_segmentDelay)] | segment_delay_ms; + segment_delay_ms = (unsigned long) min((unsigned long)10000,max((unsigned long)10,(unsigned long)segment_delay_ms)); // max delay 10s + + on_time_ms = top[FPSTR(_onTime)] | on_time_ms/1000; + on_time_ms = min(900,max(10,(int)on_time_ms)) * 1000; // min 10s, max 15min + + useUSSensorTop = top[FPSTR(_useTopUltrasoundSensor)] | useUSSensorTop; + topPIRorTriggerPin = top[FPSTR(_topPIRorTrigger_pin)] | topPIRorTriggerPin; +// topPIRorTriggerPin = min(33,max(-1,(int)topPIRorTriggerPin)); // bounds check + topEchoPin = top[FPSTR(_topEcho_pin)] | topEchoPin; +// topEchoPin = min(39,max(-1,(int)topEchoPin)); // bounds check + + useUSSensorBottom = top[FPSTR(_useBottomUltrasoundSensor)] | useUSSensorBottom; + bottomPIRorTriggerPin = top[FPSTR(_bottomPIRorTrigger_pin)] | bottomPIRorTriggerPin; +// bottomPIRorTriggerPin = min(33,max(-1,(int)bottomPIRorTriggerPin)); // bounds check + bottomEchoPin = top[FPSTR(_bottomEcho_pin)] | bottomEchoPin; +// bottomEchoPin = min(39,max(-1,(int)bottomEchoPin)); // bounds check + + topMaxDist = top[FPSTR(_topEchoCm)] | topMaxDist; + topMaxDist = min(150,max(30,(int)topMaxDist)); // max distnace ~1.5m (a lag of 9ms may be expected) + bottomMaxDist = top[FPSTR(_bottomEchoCm)] | bottomMaxDist; + bottomMaxDist = min(150,max(30,(int)bottomMaxDist)); // max distance ~1.5m (a lag of 9ms may be expected) + + DEBUG_PRINT(FPSTR(_name)); if (!initDone) { // first run: reading from cfg.json - DEBUG_PRINTLN(F("Staircase config loaded.")); + DEBUG_PRINTLN(F(" config loaded.")); } else { // changing paramters from settings page - DEBUG_PRINTLN(F("Staircase config (re)loaded.")); + DEBUG_PRINTLN(F(" config (re)loaded.")); bool changed = false; if ((oldUseUSSensorTop != useUSSensorTop) || (oldUseUSSensorBottom != useUSSensorBottom) || @@ -493,7 +491,8 @@ class Animated_Staircase : public Usermod { } if (changed) setup(); } - return configComplete; + // use "return !top["newestParameter"].isNull();" when updating Usermod with new features + return true; } /* diff --git a/usermods/EXAMPLE_v2/usermod_v2_example.h b/usermods/EXAMPLE_v2/usermod_v2_example.h index ac466935..3e1f8d3a 100644 --- a/usermods/EXAMPLE_v2/usermod_v2_example.h +++ b/usermods/EXAMPLE_v2/usermod_v2_example.h @@ -23,8 +23,12 @@ //class name. Use something descriptive and leave the ": public Usermod" part :) class MyExampleUsermod : public Usermod { private: + // sample usermod default value for variable (you can also use constructor) + int userVar0 = 42; + //Private class members. You can declare variables and functions only accessible to your usermod here unsigned long lastTime = 0; + public: //Functions called by WLED @@ -140,21 +144,14 @@ class MyExampleUsermod : public Usermod { */ bool readFromConfig(JsonObject& root) { - userVar0 = 42; //set your variables to their boot default value (this can also be done when declaring the variable) - + //set defaults for variables when declaring the variable (class definition or constructor) JsonObject top = root["exampleUsermod"]; - if (!top.isNull()) { - bool configComplete = true; + if (!top.isNull()) return false; - //check if value is there - if (top.containsKey("great")) { - //convert value to the correct type - userVar0 = top["great"].as(); - } else configComplete = false; + userVar0 = top["great"] | userVar0; - if (configComplete) return true; - } - return false; + // use "return !top["newestParameter"].isNull();" when updating Usermod with new features + return true; } 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 2e9f43c6..3d441e59 100644 --- a/usermods/Fix_unreachable_netservices_v2/usermod_Fix_unreachable_netservices.h +++ b/usermods/Fix_unreachable_netservices_v2/usermod_Fix_unreachable_netservices.h @@ -155,6 +155,7 @@ Delay ())); // check bounds + if (top.isNull()) { + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); + return false; } - if (top[FPSTR(_enabled)] != nullptr) { - if (top[FPSTR(_enabled)].is()) { - enabled = top[FPSTR(_enabled)].as(); // reading from cfg.json - } else { - // change from settings page - String str = top[FPSTR(_enabled)]; // checkbox -> off or on - enabled = (bool)(str!="off"); // off is guaranteed to be present - } - } + PIRsensorPin = top["pin"] | PIRsensorPin; +// PIRsensorPin = min(39,max(-1,(int)PIRsensorPin)); // check bounds - if (top[FPSTR(_switchOffDelay)] != nullptr) { - m_switchOffDelay = (top[FPSTR(_switchOffDelay)].as() * 1000); - } + enabled = top[FPSTR(_enabled)] | enabled; - if (top[FPSTR(_onPreset)] != nullptr) { - m_onPreset = max(0,min(250,top[FPSTR(_onPreset)].as())); - } + m_switchOffDelay = (top[FPSTR(_switchOffDelay)] | m_switchOffDelay/1000) * 1000; - if (top[FPSTR(_offPreset)] != nullptr) { - m_offPreset = max(0,min(250,top[FPSTR(_offPreset)].as())); - } + m_onPreset = top[FPSTR(_onPreset)] | m_onPreset; + m_onPreset = max(0,min(250,(int)m_onPreset)); - if (top[FPSTR(_nightTime)] != nullptr) { - if (top[FPSTR(_nightTime)].is()) { - m_nightTimeOnly = top[FPSTR(_nightTime)].as(); // reading from cfg.json - } else { - // change from settings page - String str = top[FPSTR(_nightTime)]; // checkbox -> off or on - m_nightTimeOnly = (bool)(str!="off"); // off is guaranteed to be present - } - } + m_offPreset = top[FPSTR(_offPreset)] | m_offPreset; + m_offPreset = max(0,min(250,(int)m_offPreset)); - if (top[FPSTR(_mqttOnly)] != nullptr) { - if (top[FPSTR(_mqttOnly)].is()) { - m_mqttOnly = top[FPSTR(_mqttOnly)].as(); // reading from cfg.json - } else { - // change from settings page - String str = top[FPSTR(_mqttOnly)]; // checkbox -> off or on - m_mqttOnly = (bool)(str!="off"); // off is guaranteed to be present - } - } + m_nightTimeOnly = top[FPSTR(_nightTime)] | m_nightTimeOnly; + m_mqttOnly = top[FPSTR(_mqttOnly)] | m_mqttOnly; + DEBUG_PRINT(FPSTR(_name)); if (!initDone) { // reading config prior to setup() - DEBUG_PRINTLN(F("PIR config loaded.")); + DEBUG_PRINTLN(F(" config loaded.")); } else { if (oldPin != PIRsensorPin || oldEnabled != enabled) { // check if pin is OK @@ -395,10 +372,10 @@ public: if (enabled) { sensorPinState = digitalRead(PIRsensorPin); } - DEBUG_PRINTLN(F("PIR config (re)loaded.")); } + DEBUG_PRINTLN(F(" config (re)loaded.")); } - + // use "return !top["newestParameter"].isNull();" when updating Usermod with new features return true; } diff --git a/usermods/SN_Photoresistor/usermod_sn_photoresistor.h b/usermods/SN_Photoresistor/usermod_sn_photoresistor.h index ac86f390..61490145 100644 --- a/usermods/SN_Photoresistor/usermod_sn_photoresistor.h +++ b/usermods/SN_Photoresistor/usermod_sn_photoresistor.h @@ -173,31 +173,22 @@ public: { // we look for JSON object. JsonObject top = root[FPSTR(_name)]; - - if (!top.isNull()) - { - if (top[FPSTR(_enabled)].is()) - { - disabled = !top[FPSTR(_enabled)].as(); - } - else - { - String str = top[FPSTR(_enabled)]; // checkbox -> off or on - disabled = (bool)(str == "off"); // off is guaranteed to be present - }; - - readingInterval = min(120, max(10, top[FPSTR(_readInterval)].as())) * 1000; // convert to ms - referenceVoltage = top[FPSTR(_referenceVoltage)].as(); - resistorValue = top[FPSTR(_resistorValue)].as(); - adcPrecision = top[FPSTR(_adcPrecision)].as(); - offset = top[FPSTR(_offset)].as(); - DEBUG_PRINTLN(F("Photoresistor config (re)loaded.")); - } - else - { - DEBUG_PRINTLN(F("No config found. (Using defaults.)")); + if (top.isNull()) { + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); return false; } + + disabled = !(top[FPSTR(_enabled)] | !disabled); + readingInterval = (top[FPSTR(_readInterval)] | readingInterval/1000) * 1000; // convert to ms + referenceVoltage = top[FPSTR(_referenceVoltage)] | referenceVoltage; + resistorValue = top[FPSTR(_resistorValue)] | resistorValue; + adcPrecision = top[FPSTR(_adcPrecision)] | adcPrecision; + offset = top[FPSTR(_offset)] | offset; + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(" config (re)loaded.")); + + // use "return !top["newestParameter"].isNull();" when updating Usermod with new features return true; } }; diff --git a/usermods/Temperature/usermod_temperature.h b/usermods/Temperature/usermod_temperature.h index 46cb9fa1..777a55b0 100644 --- a/usermods/Temperature/usermod_temperature.h +++ b/usermods/Temperature/usermod_temperature.h @@ -42,7 +42,7 @@ class UsermodTemperature : public Usermod { bool waitingForConversion = false; // flag set at startup if DS18B20 sensor not found, avoids trying to keep getting // temperature if flashed to a board without a sensor attached - bool disabled = false; + bool enabled = true; // strings to reduce flash memory usage (used more than twice) static const char _name[]; @@ -110,23 +110,23 @@ class UsermodTemperature : public Usermod { // pin retrieved from cfg.json (readFromConfig()) prior to running setup() if (!pinManager.allocatePin(temperaturePin,false)) { temperaturePin = -1; // allocation failed - disabled = true; + enabled = false; DEBUG_PRINTLN(F("Temperature pin allocation failed.")); } else { - if (!disabled) { + if (enabled) { // config says we are enabled oneWire = new OneWire(temperaturePin); if (!oneWire->reset()) - disabled = true; // resetting 1-Wire bus yielded an error + enabled = false; // resetting 1-Wire bus yielded an error else - while ((disabled=!findSensor()) && retries--) delay(25); // try to find sensor + while ((enabled=findSensor()) && retries--) delay(25); // try to find sensor } } initDone = true; } void loop() { - if (disabled || strip.isUpdating()) return; + if (!enabled || strip.isUpdating()) return; unsigned long now = millis(); @@ -181,7 +181,7 @@ class UsermodTemperature : public Usermod { */ void addToJsonInfo(JsonObject& root) { // dont add temperature to info if we are disabled - if (disabled) return; + if (!enabled) return; JsonObject user = root["u"]; if (user.isNull()) user = root.createNestedObject("u"); @@ -223,7 +223,7 @@ class UsermodTemperature : public Usermod { void addToConfig(JsonObject &root) { // we add JSON object: {"Temperature": {"pin": 0, "degC": true}} JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname - top[FPSTR(_enabled)] = !disabled; + top[FPSTR(_enabled)] = enabled; top["pin"] = temperaturePin; // usermodparam top["degC"] = degC; // usermodparam top[FPSTR(_readInterval)] = readingInterval / 1000; @@ -233,57 +233,34 @@ class UsermodTemperature : public Usermod { /** * readFromConfig() is called before setup() to populate properties from values stored in cfg.json + * + * The function should return true if configuration was successfully loaded or false if there was no configuration. */ bool readFromConfig(JsonObject &root) { // we look for JSON object: {"Temperature": {"pin": 0, "degC": true}} - JsonObject top = root[FPSTR(_name)]; int8_t newTemperaturePin = temperaturePin; - if (top.isNull()) return true; - bool configComplete = true; - if (top["pin"] != nullptr) { - if (top[FPSTR(_enabled)].is()) { - disabled = !top[FPSTR(_enabled)].as(); - } else { - String str = top[FPSTR(_enabled)]; // checkbox -> off or on - disabled = (bool)(str=="off"); // off is guaranteed to be present - } - newTemperaturePin = min(39,max(-1,top["pin"].as())); + JsonObject top = root[FPSTR(_name)]; + if (top.isNull()) { + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); + return false; } - if (top["degC"] != nullptr) { - if (top["degC"].is()) { - // reading from cfg.json - degC = top["degC"].as(); - } else { - // new configuration from set.cpp - String str = top["degC"]; // checkbox -> off or on - degC = (bool)(str!="off"); // off is guaranteed to be present - } - } - - if (top[FPSTR(_readInterval)] != nullptr) { - readingInterval = min(120,max(10,top[FPSTR(_readInterval)].as())) * 1000; // convert to ms - } - - if (top[FPSTR(_parasite)] != nullptr) { - if (top[FPSTR(_parasite)].is()) { - // reading from cfg.json - parasite = top[FPSTR(_parasite)].as(); - } else { - // new configuration from set.cpp - String str = top[FPSTR(_parasite)]; // checkbox -> off or on - parasite = (bool)(str!="off"); // off is guaranteed to be present - } - } + enabled = top[FPSTR(_enabled)] | enabled; + newTemperaturePin = top["pin"] | newTemperaturePin; +// newTemperaturePin = min(33,max(-1,(int)newTemperaturePin)); // bounds check + degC = top["degC"] | degC; + readingInterval = top[FPSTR(_readInterval)] | readingInterval/1000; + readingInterval = min(120,max(10,(int)readingInterval)) * 1000; // convert to ms + parasite = top[FPSTR(_parasite)] | parasite; + DEBUG_PRINT(FPSTR(_name)); if (!initDone) { // first run: reading from cfg.json temperaturePin = newTemperaturePin; - DEBUG_PRINTLN(F("Temperature config loaded.")); + DEBUG_PRINTLN(F(" config loaded.")); } else { - DEBUG_PRINTLN(F("Temperature config re-loaded.")); - configComplete = false; // changing paramters from settings page if (newTemperaturePin != temperaturePin) { // deallocate pin and release memory @@ -293,8 +270,10 @@ class UsermodTemperature : public Usermod { // initialise setup(); } + DEBUG_PRINTLN(F(" config (re)loaded.")); } - return configComplete; + // use "return !top["newestParameter"].isNull();" when updating Usermod with new features + return true; } uint16_t getId() diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/usermod_multi_relay.h index 426fe49b..0820cac3 100644 --- a/usermods/multi_relay/usermod_multi_relay.h +++ b/usermods/multi_relay/usermod_multi_relay.h @@ -347,55 +347,36 @@ class MultiRelay : public Usermod { /** * restore the changeable values * readFromConfig() is called before setup() to populate properties from values stored in cfg.json + * + * The function should return true if configuration was successfully loaded or false if there was no configuration. */ bool readFromConfig(JsonObject &root) { int8_t oldPin[MULTI_RELAY_MAX_RELAYS]; JsonObject top = root[FPSTR(_name)]; - if (top.isNull()) return false; - - if (top[FPSTR(_enabled)] != nullptr) { - if (top[FPSTR(_enabled)].is()) { - enabled = top[FPSTR(_enabled)].as(); // reading from cfg.json - } else { - // change from settings page - String str = top[FPSTR(_enabled)]; // checkbox -> off or on - enabled = (bool)(str!="off"); // off is guaranteed to be present - } + if (top.isNull()) { + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); + return false; } + enabled = top[FPSTR(_enabled)] | enabled; + for (uint8_t i=0; i())); - - if (top[parName+FPSTR(_activeHigh)] != nullptr) { - if (top[parName+FPSTR(_activeHigh)].is()) { - _relay[i].mode = top[parName+FPSTR(_activeHigh)].as(); // reading from cfg.json - } else { - // change from settings page - String str = top[parName+FPSTR(_activeHigh)]; // checkbox -> off or on - _relay[i].mode = (bool)(str!="off"); // off is guaranteed to be present - } - } - - if (top[parName+FPSTR(_external)] != nullptr) { - if (top[parName+FPSTR(_external)].is()) { - _relay[i].external = top[parName+FPSTR(_external)].as(); // reading from cfg.json - } else { - // change from settings page - String str = top[parName+FPSTR(_external)]; // checkbox -> off or on - _relay[i].external = (bool)(str!="off"); // off is guaranteed to be present - } - } - - _relay[i].delay = min(600,max(0,abs(top[parName+FPSTR(_delay_str)].as()))); + oldPin[i] = _relay[i].pin; + _relay[i].pin = top[parName+"pin"] | _relay[i].pin; +// _relay[i].pin = min(39,max(-1,(int)_relay[i].pin)); // bounds checking + _relay[i].mode = top[parName+FPSTR(_activeHigh)] | _relay[i].mode; + _relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external; + _relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay; + _relay[i].delay = min(600,max(0,abs((int)_relay[i].delay))); // bounds checking max 10min } + DEBUG_PRINT(FPSTR(_name)); if (!initDone) { // reading config prior to setup() - DEBUG_PRINTLN(F("MultiRelay config loaded.")); + DEBUG_PRINTLN(F(" config loaded.")); } else { // deallocate all pins 1st for (uint8_t i=0; i()) { - // reading from cfg.json - enabled = top[FPSTR(_autoSaveEnabled)].as(); - } else { - // reading from POST message - String str = top[FPSTR(_autoSaveEnabled)]; // checkbox -> off or on - enabled = (bool)(str!="off"); // off is guaranteed to be present - } - autoSaveAfterSec = min(3600,max(10,top[FPSTR(_autoSaveAfterSec)].as())); - autoSavePreset = min(250,max(100,top[FPSTR(_autoSavePreset)].as())); - if (top[FPSTR(_autoSaveApplyOnBoot)].is()) { - // reading from cfg.json - applyAutoSaveOnBoot = top[FPSTR(_autoSaveApplyOnBoot)].as(); - } else { - // reading from POST message - String str = top[FPSTR(_autoSaveApplyOnBoot)]; // checkbox -> off or on - applyAutoSaveOnBoot = (bool)(str!="off"); // off is guaranteed to be present - } - DEBUG_PRINTLN(F("Autosave config (re)loaded.")); + enabled = top[FPSTR(_autoSaveEnabled)] | enabled; + autoSaveAfterSec = top[FPSTR(_autoSaveAfterSec)] | autoSaveAfterSec; + autoSaveAfterSec = (uint16_t) min(3600,max(10,(int)autoSaveAfterSec)); // bounds checking + autoSavePreset = top[FPSTR(_autoSavePreset)] | autoSavePreset; + autoSavePreset = (uint8_t) min(250,max(100,(int)autoSavePreset)); // bounds checking + applyAutoSaveOnBoot = top[FPSTR(_autoSaveApplyOnBoot)] | applyAutoSaveOnBoot; + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(" config (re)loaded.")); + + // use "return !top["newestParameter"].isNull();" when updating Usermod with new features 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 7547ca61..1a8384d9 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 @@ -623,48 +623,30 @@ class FourLineDisplayUsermod : public Usermod { 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]; - newSda = top["pin"][1]; - newType = top["type"]; - if (top[FPSTR(_flip)].is()) { - flip = top[FPSTR(_flip)].as(); - } else { - String str = top[FPSTR(_flip)]; // checkbox -> off or on - flip = (bool)(str!="off"); // off is guaranteed to be present - needsRedraw |= true; - } - contrast = top[FPSTR(_contrast)].as(); - refreshRate = top[FPSTR(_refreshRate)].as() * 1000; - screenTimeout = top[FPSTR(_screenTimeOut)].as() * 1000; - if (top[FPSTR(_sleepMode)].is()) { - sleepMode = top[FPSTR(_sleepMode)].as(); - } else { - String str = top[FPSTR(_sleepMode)]; // checkbox -> off or on - sleepMode = (bool)(str!="off"); // off is guaranteed to be present - needsRedraw |= true; - } - if (top[FPSTR(_clockMode)].is()) { - clockMode = top[FPSTR(_clockMode)].as(); - } else { - String str = top[FPSTR(_clockMode)]; // checkbox -> off or on - clockMode = (bool)(str!="off"); // off is guaranteed to be present - needsRedraw |= true; - } - DEBUG_PRINTLN(F("4 Line Display config (re)loaded.")); - } else { - DEBUG_PRINTLN(F("No config found. (Using defaults.)")); - configComplete = false; + if (top.isNull()) { + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); + return false; } + newScl = top["pin"][0] | newScl; + newSda = top["pin"][1] | newSda; + newType = top["type"] | newType; + flip = top[FPSTR(_flip)] | flip; + contrast = top[FPSTR(_contrast)] | contrast; + refreshRate = (top[FPSTR(_refreshRate)] | refreshRate/1000) * 1000; + screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000; + sleepMode = top[FPSTR(_sleepMode)] | sleepMode; + clockMode = top[FPSTR(_clockMode)] | clockMode; + + DEBUG_PRINT(FPSTR(_name)); if (!initDone) { // first run: reading from cfg.json sclPin = newScl; sdaPin = newSda; type = newType; + DEBUG_PRINTLN(F(" config loaded.")); } else { // changing paramters from settings page if (sclPin!=newScl || sdaPin!=newSda || type!=newType) { @@ -675,17 +657,18 @@ class FourLineDisplayUsermod : public Usermod { sdaPin = newSda; if (newScl<0 || newSda<0) { type = NONE; - return configComplete; - } else - type = newType; + return true; + } else type = newType; setup(); needsRedraw |= true; } setContrast(contrast); setFlipMode(flip); if (needsRedraw && !wakeDisplay()) redraw(true); + DEBUG_PRINTLN(F(" config (re)loaded.")); } - return configComplete; + // use "return !top["newestParameter"].isNull();" when updating Usermod with new features + return true; } /* diff --git a/wled00/data/settings_um.htm b/wled00/data/settings_um.htm index e3c8e582..b0f46d48 100644 --- a/wled00/data/settings_um.htm +++ b/wled00/data/settings_um.htm @@ -65,7 +65,7 @@ if (isO(o)) { for (const [s,v] of Object.entries(o)) { // possibility to nest objects (only 1 level) - if (f!=='unknown' && !k.includes("_")) addField(k+"_"+f,s,v); + if (f!=='unknown' && !k.includes(":")) addField(k+":"+f,s,v); else addField(k,s,v); } } else if (Array.isArray(o)) { @@ -76,28 +76,31 @@ var t,c; switch (typeof o) { case "boolean": - t = "checkbox"; c = o ? `checked value="on"` : ""; break; + t = "checkbox"; c = o ? `checked value="true"` : ""; + break; case "number": + c = `value="${o}"`; if (isF(o)) { - c = `value="${parseFloat(o)}" step="0.01"`; + c += ` step="0.01" class="xxl"`; t = "float"; } else { - c = `value="${parseInt(o,10)}"`; - if (f==="pin") c += ' max="39" min="-1"'; + if (f.substr(-3)==="pin") c += ' max="39" min="-1" class="small"'; + else c += ` class="big"`; t = "int"; } break; - case "string": - t = "text"; c = `value="${o}"`; break; +// case "string": +// t = "text"; c = `value="${o}" style="width:150px;"`; break; default: - t = "text"; c = `value="${o}"`; break; + t = "text"; c = `value="${o}" style="width:150px;"`; + break; } - if (k.includes("_")) urows += k.substr(k.indexOf("_")+1); + if (k.includes(":")) urows += k.substr(k.indexOf(":")+1); urows += ` ${f}: `; // https://stackoverflow.com/questions/11657123/posting-both-checked-and-unchecked-checkboxes - if (t=="checkbox") urows += ``; - else if (!a) urows += ``; - urows += `
`; + if (t=="checkbox") urows += ``; + else if (!a) urows += ``; + urows += `
`; } } function ldS() { diff --git a/wled00/data/style.css b/wled00/data/style.css index a607a4a8..773031a9 100644 --- a/wled00/data/style.css +++ b/wled00/data/style.css @@ -39,13 +39,19 @@ input { font-family: Verdana, sans-serif; border: 0.5ch solid #333; } +input[type="text"] { + font-size: medium; +} input[type="number"] { width: 4em; font-size: medium; margin: 2px; } +input[type="number"].xxl { + width: 100px; +} input[type="number"].big { - width: 70px; + width: 85px; } input[type="number"].med { width: 55px; diff --git a/wled00/html_settings.h b/wled00/html_settings.h index 31a1159d..1c75cdc3 100644 --- a/wled00/html_settings.h +++ b/wled00/html_settings.h @@ -6,7 +6,7 @@ */ // Autogenerated from wled00/data/style.css, do not edit!! -const char PAGE_settingsCss[] PROGMEM = R"=====()====="; +const char PAGE_settingsCss[] PROGMEM = R"=====()====="; // Autogenerated from wled00/data/settings.htm, do not edit!! @@ -408,7 +408,7 @@ type="submit">Save & Reboot)====="; // Autogenerated from wled00/data/settings_um.htm, do not edit!! const char PAGE_settings_um[] PROGMEM = R"=====(Usermod Settings