diff --git a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h
index bd92b9d94..11277593a 100644
--- a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h
+++ b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h
@@ -33,9 +33,6 @@
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
*/
-// MQTT topic for sensor values
-const char MQTT_TOPIC[] = "/motion";
-
class PIRsensorSwitch : public Usermod
{
public:
@@ -76,15 +73,22 @@ private:
// notification mode for colorUpdated()
const byte NotifyUpdateMode = NOTIFIER_CALL_MODE_NO_NOTIFY; // NOTIFIER_CALL_MODE_DIRECT_CHANGE
// delay before switch off after the sensor state goes LOW
- uint32_t m_switchOffDelay = 600000;
+ uint32_t m_switchOffDelay = 600000; // 10min
// off timer start time
uint32_t m_offTimerStart = 0;
// current PIR sensor pin state
byte m_PIRsensorPinState = LOW;
// PIR sensor enabled - ISR attached
bool m_PIRenabled = true;
- // state if serializeConfig() should be called
- bool m_updateConfig = false;
+ // status of initialisation
+ bool initDone = false;
+
+ // strings to reduce flash memory usage (used more than twice)
+ static const char _name[];
+ static const char _switchOffDelay[];
+ static const char _enabled[];
+ static const char _active[];
+ static const char _inactive[];
/**
* return or change if new PIR sensor state is available
@@ -125,7 +129,7 @@ private:
if (mqtt != nullptr){
char subuf[64];
strcpy(subuf, mqttDeviceTopic);
- strcat(subuf, MQTT_TOPIC);
+ strcat_P(subuf, PSTR("/motion"));
mqtt->publish(subuf, 0, true, state);
}
}
@@ -192,12 +196,12 @@ public:
} else {
// PIR Sensor mode INPUT_PULLUP
pinMode(PIRsensorPin, INPUT_PULLUP);
- if (m_PIRenabled)
- {
+ if (m_PIRenabled) {
// assign interrupt function and set CHANGE mode
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
}
}
+ initDone = true;
}
/**
@@ -213,14 +217,8 @@ public:
*/
void loop()
{
- if (!updatePIRsensorState())
- {
+ if (!updatePIRsensorState()) {
handleOffTimer();
- if (m_updateConfig)
- {
- serializeConfig();
- m_updateConfig = false;
- }
}
}
@@ -237,33 +235,32 @@ public:
if (user.isNull())
user = root.createNestedObject("u");
- JsonArray infoArr = user.createNestedArray(" PIR sensor state"); //name
- String uiDomString = "");
infoArr.add(uiDomString); //value
if (m_PIRenabled)
{
//this code adds "u":{"⏲ switch off timer":uiDomString} to the info object
- uiDomString = " switch off timer\
-after switch off timerafter min";
+ uiDomString += F("\" onchange=\"requestJson({PIRoffSec:parseInt(this.value)*60});\">min");
infoArr = user.createNestedArray(uiDomString); //name
// off timer
@@ -274,7 +271,7 @@ after = 3600)
{
uiDomString += (offSeconds / 3600);
- uiDomString += " hours ";
+ uiDomString += F("h ");
offSeconds %= 3600;
}
if (offSeconds >= 60)
@@ -288,14 +285,14 @@ after 0)
{
- uiDomString += " min ";
+ uiDomString += F("min ");
}
uiDomString += (offSeconds);
- infoArr.add(uiDomString + " sec");
+ infoArr.add(uiDomString + F("s"));
}
else
{
- infoArr.add("inactive");
+ infoArr.add(FPSTR(_inactive));
}
}
}
@@ -308,8 +305,8 @@ after ())));
- m_updateConfig = true;
+ if (root[FPSTR(_switchOffDelay)] != nullptr) {
+ m_switchOffDelay = (1000 * max(60UL, min(43200UL, root[FPSTR(_switchOffDelay)].as())));
}
-
- if (root["pin"] != nullptr)
- {
+/*
+ if (root["pin"] != nullptr) {
int8_t pin = (int)root["pin"];
// check if pin is OK
if (pin != PIRsensorPin && pin>=0 && pinManager.allocatePin(pin,false)) {
@@ -344,23 +338,17 @@ after = 0) {
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
newPIRsensorState(true, true);
- }
- else if (m_PIRenabled)
- {
+ } else if (m_PIRenabled && PIRsensorPin >= 0) {
detachInterrupt(PIRsensorPin);
}
- m_PIRenabled = root[F("PIRenabled")];
- m_updateConfig = true;
+ m_PIRenabled = root[FPSTR(_enabled)];
}
}
@@ -369,10 +357,11 @@ after ())); // check bounds
+ }
+
+ if (top[FPSTR(_enabled)] != nullptr) {
+ if (top[FPSTR(_enabled)].is()) {
+ m_PIRenabled = top[FPSTR(_enabled)].as(); // reading from cfg.json
+ } else {
+ // change from settings page
+ String str = top[FPSTR(_enabled)]; // checkbox -> off or on
+ m_PIRenabled = (bool)(str!="off"); // off is guaranteed to be present
+ }
+ }
+
+ if (top[FPSTR(_switchOffDelay)] != nullptr) {
+ m_switchOffDelay = (top[FPSTR(_switchOffDelay)].as() * 1000);
+ }
+
+ if (!initDone) {
+ // reading config prior to setup()
+ DEBUG_PRINTLN(F("PIR config loaded."));
+ } else {
+ if (oldPin != PIRsensorPin || oldEnabled != m_PIRenabled) {
+ if (oldEnabled) {
+ // remove old ISR if disabling usermod
+ detachInterrupt(oldPin);
+ }
+ // check if pin is OK
+ if (oldPin != PIRsensorPin && oldPin >= 0) {
+ // if we are changing pin in settings page
+ // deallocate old pin
+ pinManager.deallocatePin(oldPin);
+ if (pinManager.allocatePin(PIRsensorPin,false)) {
+ pinMode(PIRsensorPin, INPUT_PULLUP);
+ } else {
+ // allocation failed
+ PIRsensorPin = -1;
+ m_PIRenabled = false;
+ }
+ }
+ if (m_PIRenabled) {
+ attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
+ newPIRsensorState(true, true);
+ }
+ DEBUG_PRINTLN(F("PIR config (re)loaded."));
+ }
}
- m_PIRenabled = (top[F("PIRenabled")] != nullptr ? top[F("PIRenabled")] : true);
- m_switchOffDelay = top[F("PIRoffSec")] | m_switchOffDelay;
}
/**
@@ -425,4 +461,11 @@ PIRsensorSwitch *PIRsensorSwitch::PIRsensorSwitchInstance(PIRsensorSwitch *pInst
s_pPIRsensorSwitch = pInstance;
}
return s_pPIRsensorSwitch;
-}
+};
+
+// strings to reduce flash memory usage (used more than twice)
+const char PIRsensorSwitch::_name[] PROGMEM = "PIRsensorSwitch";
+const char PIRsensorSwitch::_switchOffDelay[] PROGMEM = "PIRoffSec";
+const char PIRsensorSwitch::_enabled[] PROGMEM = "PIRenabled";
+const char PIRsensorSwitch::_active[] PROGMEM = "active";
+const char PIRsensorSwitch::_inactive[] PROGMEM = "inactive";
diff --git a/usermods/Temperature/usermod_temperature.h b/usermods/Temperature/usermod_temperature.h
index 3e756b690..176fc3dd2 100644
--- a/usermods/Temperature/usermod_temperature.h
+++ b/usermods/Temperature/usermod_temperature.h
@@ -23,9 +23,6 @@
#define USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT 20000
#endif
-// strings
-const char _um_Temperature[] PROGMEM = "Temperature";
-
class UsermodTemperature : public Usermod {
private:
@@ -54,6 +51,11 @@ class UsermodTemperature : public Usermod {
// temperature if flashed to a board without a sensor attached
bool disabled = false;
+ // strings to reduce flash memory usage (used more than twice)
+ static const char _name[];
+ static const char _enabled[];
+ static const char _readInterval[];
+
//Dallas sensor quick reading. Credit to - Author: Peter Scargill, August 17th, 2013
int16_t readDallas() {
byte i;
@@ -180,7 +182,7 @@ class UsermodTemperature : public Usermod {
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
- JsonArray temp = user.createNestedArray(FPSTR(_um_Temperature));
+ JsonArray temp = user.createNestedArray(FPSTR(_name));
//temp.add(F("Loaded."));
if (!getTemperatureComplete) {
@@ -215,20 +217,20 @@ class UsermodTemperature : public Usermod {
* Values in the state object may be modified by connected clients
* Read "_" from json state and and change settings (i.e. GPIO pin) used.
*/
- void readFromJsonState(JsonObject &root) {
- if (!initDone) return; // prevent crash on boot applyPreset()
- }
+ //void readFromJsonState(JsonObject &root) {
+ // if (!initDone) return; // prevent crash on boot applyPreset()
+ //}
/**
* addToConfig() (called from set.cpp) stores persistent properties to cfg.json
*/
void addToConfig(JsonObject &root) {
// we add JSON object: {"Temperature": {"pin": 0, "degC": true}}
- JsonObject top = root.createNestedObject(FPSTR(_um_Temperature)); // usermodname
- top[F("enabled")] = !disabled;
+ JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
+ top[FPSTR(_enabled)] = !disabled;
top["pin"] = temperaturePin; // usermodparam
top["degC"] = degC; // usermodparam
- top[F("read-interval-s")] = readingInterval / 1000;
+ top[FPSTR(_readInterval)] = readingInterval / 1000;
DEBUG_PRINTLN(F("Temperature config saved."));
}
@@ -237,27 +239,31 @@ class UsermodTemperature : public Usermod {
*/
void readFromConfig(JsonObject &root) {
// we look for JSON object: {"Temperature": {"pin": 0, "degC": true}}
- JsonObject top = root[FPSTR(_um_Temperature)];
+ JsonObject top = root[FPSTR(_name)];
int8_t newTemperaturePin = temperaturePin;
+
if (!top.isNull() && top["pin"] != nullptr) {
- if (top[F("enabled")].is()) {
- disabled = !top[F("enabled")].as();
+ if (top[FPSTR(_enabled)].is()) {
+ disabled = !top[FPSTR(_enabled)].as();
} else {
- String str = top[F("enabled")]; // checkbox -> off or on
+ 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()));
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
}
- readingInterval = min(120,max(10,top[F("read-interval-s")].as())) * 1000;
- DEBUG_PRINTLN(F("Temperature config loaded."));
+ readingInterval = min(120,max(10,top[FPSTR(_readInterval)].as())) * 1000; // convert to ms
+ DEBUG_PRINTLN(F("Temperature config (re)loaded."));
} else {
DEBUG_PRINTLN(F("No config found. (Using defaults.)"));
}
+
if (!initDone) {
// first run: reading from cfg.json
temperaturePin = newTemperaturePin;
@@ -279,3 +285,8 @@ class UsermodTemperature : public Usermod {
return USERMOD_ID_TEMPERATURE;
}
};
+
+// strings to reduce flash memory usage (used more than twice)
+const char UsermodTemperature::_name[] PROGMEM = "Temperature";
+const char UsermodTemperature::_enabled[] PROGMEM = "enabled";
+const char UsermodTemperature::_readInterval[] PROGMEM = "read-interval-s";
\ No newline at end of file
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 443fd4aab..63b32f7d2 100644
--- a/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h
+++ b/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h
@@ -1,226 +1,231 @@
-#pragma once
-
-#include "wled.h"
-
-// v2 Usermod to automatically save settings
-// to configurable preset after a change to any of
-//
-// * brightness
-// * effect speed
-// * effect intensity
-// * mode (effect)
-// * palette
-//
-// but it will wait for configurable number of seconds, a "settle"
-// period in case there are other changes (any change will
-// extend the "settle" window).
-//
-// It can be configured to load auto saved preset at startup,
-// during the first `loop()`.
-//
-// AutoSaveUsermod is standalone, but if FourLineDisplayUsermod
-// is installed, it will notify the user of the saved changes.
-
-// format: "~ MM-DD HH:MM:SS ~"
-#define PRESET_NAME_BUFFER_SIZE 25
-
-// strings
-const char _um_AutoSave[] PROGMEM = "Autosave";
-const char _autoSaveAfterSec[] PROGMEM = "autoSaveAfterSec";
-const char _autoSavePreset[] PROGMEM = "autoSavePreset";
-const char _autoSaveApplyOnBoot[] PROGMEM = "autoSaveApplyOnBoot";
-
-class AutoSaveUsermod : public Usermod {
-
- private:
-
- bool firstLoop = true;
- bool initDone = false;
-
- // configurable parameters
- unsigned long autoSaveAfterSec = 15; // 15s by default
- uint8_t autoSavePreset = 250; // last possible preset
- bool applyAutoSaveOnBoot = false; // do we load auto-saved preset on boot?
-
- // If we've detected the need to auto save, this will be non zero.
- unsigned long autoSaveAfter = 0;
-
- uint8_t knownBrightness = 0;
- uint8_t knownEffectSpeed = 0;
- uint8_t knownEffectIntensity = 0;
- uint8_t knownMode = 0;
- uint8_t knownPalette = 0;
-
- #ifdef USERMOD_FOUR_LINE_DISPLAY
- FourLineDisplayUsermod* display;
- #endif
-
- void inline saveSettings() {
- char presetNameBuffer[PRESET_NAME_BUFFER_SIZE];
- updateLocalTime();
- sprintf_P(presetNameBuffer,
- PSTR("~ %02d-%02d %02d:%02d:%02d ~"),
- month(localTime), day(localTime),
- hour(localTime), minute(localTime), second(localTime));
- savePreset(autoSavePreset, true, presetNameBuffer);
- }
-
- void inline displayOverlay() {
- #ifdef USERMOD_FOUR_LINE_DISPLAY
- if (display != nullptr) {
- display->wakeDisplay();
- display->overlay("Settings", "Auto Saved", 1500);
- }
- #endif
- }
-
- public:
-
- // gets called once at boot. Do all initialization that doesn't depend on
- // network here
- void setup() {
- #ifdef USERMOD_FOUR_LINE_DISPLAY
- // This Usermod has enhanced funcionality if
- // FourLineDisplayUsermod is available.
- display = (FourLineDisplayUsermod*) usermods.lookup(USERMOD_ID_FOUR_LINE_DISP);
- #endif
- initDone = true;
- }
-
- // gets called every time WiFi is (re-)connected. Initialize own network
- // interfaces here
- void connected() {}
-
- /*
- * Da loop.
- */
- void loop() {
- if (!autoSaveAfterSec) return; // setting 0 as autosave seconds disables autosave
-
- unsigned long now = millis();
- uint8_t currentMode = strip.getMode();
- uint8_t currentPalette = strip.getSegment(0).palette;
- if (firstLoop) {
- firstLoop = false;
- if (applyAutoSaveOnBoot) applyPreset(autoSavePreset);
- knownBrightness = bri;
- knownEffectSpeed = effectSpeed;
- knownEffectIntensity = effectIntensity;
- knownMode = currentMode;
- knownPalette = currentPalette;
- return;
- }
-
- unsigned long wouldAutoSaveAfter = now + autoSaveAfterSec*1000;
- if (knownBrightness != bri) {
- knownBrightness = bri;
- autoSaveAfter = wouldAutoSaveAfter;
- } else if (knownEffectSpeed != effectSpeed) {
- knownEffectSpeed = effectSpeed;
- autoSaveAfter = wouldAutoSaveAfter;
- } else if (knownEffectIntensity != effectIntensity) {
- knownEffectIntensity = effectIntensity;
- autoSaveAfter = wouldAutoSaveAfter;
- } else if (knownMode != currentMode) {
- knownMode = currentMode;
- autoSaveAfter = wouldAutoSaveAfter;
- } else if (knownPalette != currentPalette) {
- knownPalette = currentPalette;
- autoSaveAfter = wouldAutoSaveAfter;
- }
-
- if (autoSaveAfter && now > autoSaveAfter) {
- autoSaveAfter = 0;
- // Time to auto save. You may have some flickry?
- saveSettings();
- displayOverlay();
- }
- }
-
- /*
- * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
- * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
- * Below it is shown how this could be used for e.g. a light sensor
- */
- //void addToJsonInfo(JsonObject& root) {
- //JsonObject user = root["u"];
- //if (user.isNull()) user = root.createNestedObject("u");
- //JsonArray data = user.createNestedArray(F("Autosave"));
- //data.add(F("Loaded."));
- //}
-
- /*
- * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
- * Values in the state object may be modified by connected clients
- */
- //void addToJsonState(JsonObject& root) {
- //}
-
- /*
- * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
- * Values in the state object may be modified by connected clients
- */
- //void readFromJsonState(JsonObject& root) {
- // if (!initDone) return; // prevent crash on boot applyPreset()
- //}
-
- /*
- * addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
- * It will be called by WLED when settings are actually saved (for example, LED settings are saved)
- * If you want to force saving the current state, use serializeConfig() in your loop().
- *
- * CAUTION: serializeConfig() will initiate a filesystem write operation.
- * It might cause the LEDs to stutter and will cause flash wear if called too often.
- * Use it sparingly and always in the loop, never in network callbacks!
- *
- * addToConfig() will also not yet add your setting to one of the settings pages automatically.
- * To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually.
- *
- * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
- */
- void addToConfig(JsonObject& root) {
- // we add JSON object: {"Autosave": {"autoSaveAfterSec": 10, "autoSavePreset": 99}}
- JsonObject top = root.createNestedObject(FPSTR(_um_AutoSave)); // usermodname
- top[FPSTR(_autoSaveAfterSec)] = autoSaveAfterSec; // usermodparam
- top[FPSTR(_autoSavePreset)] = autoSavePreset; // usermodparam
- top[FPSTR(_autoSaveApplyOnBoot)] = applyAutoSaveOnBoot;
- DEBUG_PRINTLN(F("Autosave config saved."));
- }
-
- /*
- * readFromConfig() can be used to read back the custom settings you added with addToConfig().
- * This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
- *
- * 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 :)
- */
- void readFromConfig(JsonObject& root) {
- // we look for JSON object: {"Autosave": {"autoSaveAfterSec": 10, "autoSavePreset": 99}}
- JsonObject top = root[FPSTR(_um_AutoSave)];
- if (!top.isNull() && top[FPSTR(_autoSaveAfterSec)] != nullptr) {
- autoSaveAfterSec = top[FPSTR(_autoSaveAfterSec)].as();
- autoSavePreset = 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."));
- } else {
- DEBUG_PRINTLN(F("No config found. (Using defaults.)"));
- }
- }
-
- /*
- * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
- * This could be used in the future for the system to determine whether your usermod is installed.
- */
- uint16_t getId() {
- return USERMOD_ID_AUTO_SAVE;
- }
-
-};
+#pragma once
+
+#include "wled.h"
+
+// v2 Usermod to automatically save settings
+// to configurable preset after a change to any of
+//
+// * brightness
+// * effect speed
+// * effect intensity
+// * mode (effect)
+// * palette
+//
+// but it will wait for configurable number of seconds, a "settle"
+// period in case there are other changes (any change will
+// extend the "settle" window).
+//
+// It can be configured to load auto saved preset at startup,
+// during the first `loop()`.
+//
+// AutoSaveUsermod is standalone, but if FourLineDisplayUsermod
+// is installed, it will notify the user of the saved changes.
+
+// format: "~ MM-DD HH:MM:SS ~"
+#define PRESET_NAME_BUFFER_SIZE 25
+
+class AutoSaveUsermod : public Usermod {
+
+ private:
+
+ bool firstLoop = true;
+ bool initDone = false;
+
+ // configurable parameters
+ unsigned long autoSaveAfterSec = 15; // 15s by default
+ uint8_t autoSavePreset = 250; // last possible preset
+ bool applyAutoSaveOnBoot = false; // do we load auto-saved preset on boot?
+
+ // If we've detected the need to auto save, this will be non zero.
+ unsigned long autoSaveAfter = 0;
+
+ uint8_t knownBrightness = 0;
+ uint8_t knownEffectSpeed = 0;
+ uint8_t knownEffectIntensity = 0;
+ uint8_t knownMode = 0;
+ uint8_t knownPalette = 0;
+
+ #ifdef USERMOD_FOUR_LINE_DISPLAY
+ FourLineDisplayUsermod* display;
+ #endif
+
+ // strings to reduce flash memory usage (used more than twice)
+ static const char _name[];
+ static const char _autoSaveAfterSec[];
+ static const char _autoSavePreset[];
+ static const char _autoSaveApplyOnBoot[];
+
+ void inline saveSettings() {
+ char presetNameBuffer[PRESET_NAME_BUFFER_SIZE];
+ updateLocalTime();
+ sprintf_P(presetNameBuffer,
+ PSTR("~ %02d-%02d %02d:%02d:%02d ~"),
+ month(localTime), day(localTime),
+ hour(localTime), minute(localTime), second(localTime));
+ savePreset(autoSavePreset, true, presetNameBuffer);
+ }
+
+ void inline displayOverlay() {
+ #ifdef USERMOD_FOUR_LINE_DISPLAY
+ if (display != nullptr) {
+ display->wakeDisplay();
+ display->overlay("Settings", "Auto Saved", 1500);
+ }
+ #endif
+ }
+
+ public:
+
+ // gets called once at boot. Do all initialization that doesn't depend on
+ // network here
+ void setup() {
+ #ifdef USERMOD_FOUR_LINE_DISPLAY
+ // This Usermod has enhanced funcionality if
+ // FourLineDisplayUsermod is available.
+ display = (FourLineDisplayUsermod*) usermods.lookup(USERMOD_ID_FOUR_LINE_DISP);
+ #endif
+ initDone = true;
+ }
+
+ // gets called every time WiFi is (re-)connected. Initialize own network
+ // interfaces here
+ void connected() {}
+
+ /*
+ * Da loop.
+ */
+ void loop() {
+ if (!autoSaveAfterSec) return; // setting 0 as autosave seconds disables autosave
+
+ unsigned long now = millis();
+ uint8_t currentMode = strip.getMode();
+ uint8_t currentPalette = strip.getSegment(0).palette;
+ if (firstLoop) {
+ firstLoop = false;
+ if (applyAutoSaveOnBoot) applyPreset(autoSavePreset);
+ knownBrightness = bri;
+ knownEffectSpeed = effectSpeed;
+ knownEffectIntensity = effectIntensity;
+ knownMode = currentMode;
+ knownPalette = currentPalette;
+ return;
+ }
+
+ unsigned long wouldAutoSaveAfter = now + autoSaveAfterSec*1000;
+ if (knownBrightness != bri) {
+ knownBrightness = bri;
+ autoSaveAfter = wouldAutoSaveAfter;
+ } else if (knownEffectSpeed != effectSpeed) {
+ knownEffectSpeed = effectSpeed;
+ autoSaveAfter = wouldAutoSaveAfter;
+ } else if (knownEffectIntensity != effectIntensity) {
+ knownEffectIntensity = effectIntensity;
+ autoSaveAfter = wouldAutoSaveAfter;
+ } else if (knownMode != currentMode) {
+ knownMode = currentMode;
+ autoSaveAfter = wouldAutoSaveAfter;
+ } else if (knownPalette != currentPalette) {
+ knownPalette = currentPalette;
+ autoSaveAfter = wouldAutoSaveAfter;
+ }
+
+ if (autoSaveAfter && now > autoSaveAfter) {
+ autoSaveAfter = 0;
+ // Time to auto save. You may have some flickry?
+ saveSettings();
+ displayOverlay();
+ }
+ }
+
+ /*
+ * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
+ * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
+ * Below it is shown how this could be used for e.g. a light sensor
+ */
+ //void addToJsonInfo(JsonObject& root) {
+ //JsonObject user = root["u"];
+ //if (user.isNull()) user = root.createNestedObject("u");
+ //JsonArray data = user.createNestedArray(F("Autosave"));
+ //data.add(F("Loaded."));
+ //}
+
+ /*
+ * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
+ * Values in the state object may be modified by connected clients
+ */
+ //void addToJsonState(JsonObject& root) {
+ //}
+
+ /*
+ * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
+ * Values in the state object may be modified by connected clients
+ */
+ //void readFromJsonState(JsonObject& root) {
+ // if (!initDone) return; // prevent crash on boot applyPreset()
+ //}
+
+ /*
+ * addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
+ * It will be called by WLED when settings are actually saved (for example, LED settings are saved)
+ * If you want to force saving the current state, use serializeConfig() in your loop().
+ *
+ * CAUTION: serializeConfig() will initiate a filesystem write operation.
+ * It might cause the LEDs to stutter and will cause flash wear if called too often.
+ * Use it sparingly and always in the loop, never in network callbacks!
+ *
+ * addToConfig() will also not yet add your setting to one of the settings pages automatically.
+ * To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually.
+ *
+ * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
+ */
+ void addToConfig(JsonObject& root) {
+ // we add JSON object: {"Autosave": {"autoSaveAfterSec": 10, "autoSavePreset": 99}}
+ JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
+ top[FPSTR(_autoSaveAfterSec)] = autoSaveAfterSec; // usermodparam
+ top[FPSTR(_autoSavePreset)] = autoSavePreset; // usermodparam
+ top[FPSTR(_autoSaveApplyOnBoot)] = applyAutoSaveOnBoot;
+ DEBUG_PRINTLN(F("Autosave config saved."));
+ }
+
+ /*
+ * readFromConfig() can be used to read back the custom settings you added with addToConfig().
+ * This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
+ *
+ * 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 :)
+ */
+ void readFromConfig(JsonObject& root) {
+ // we look for JSON object: {"Autosave": {"autoSaveAfterSec": 10, "autoSavePreset": 99}}
+ JsonObject top = root[FPSTR(_name)];
+ if (!top.isNull() && top[FPSTR(_autoSaveAfterSec)] != nullptr) {
+ autoSaveAfterSec = top[FPSTR(_autoSaveAfterSec)].as();
+ autoSavePreset = 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."));
+ } else {
+ DEBUG_PRINTLN(F("No config found. (Using defaults.)"));
+ }
+ }
+
+ /*
+ * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
+ * This could be used in the future for the system to determine whether your usermod is installed.
+ */
+ uint16_t getId() {
+ return USERMOD_ID_AUTO_SAVE;
+ }
+};
+
+// strings to reduce flash memory usage (used more than twice)
+const char AutoSaveUsermod::_name[] PROGMEM = "Autosave";
+const char AutoSaveUsermod::_autoSaveAfterSec[] PROGMEM = "autoSaveAfterSec";
+const char AutoSaveUsermod::_autoSavePreset[] PROGMEM = "autoSavePreset";
+const char AutoSaveUsermod::_autoSaveApplyOnBoot[] PROGMEM = "autoSaveApplyOnBoot";
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 14df1694e..445c7dba0 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
@@ -67,15 +67,6 @@ typedef enum {
SH1106 // U8X8_SH1106_128X64_WINSTAR_HW_I2C
} DisplayType;
-// strings
-const char _um_4LineDisplay[] PROGMEM = "4LineDisplay";
-const char _4LD_contrast[] PROGMEM = "contrast";
-const char _4LD_refreshRate[] PROGMEM = "refreshRate";
-const char _4LD_screenTimeOut[] PROGMEM = "screenTimeOut";
-const char _4LD_flip[] PROGMEM = "flip";
-const char _4LD_sleepMode[] PROGMEM = "sleepMode";
-const char _4LD_clockMode[] PROGMEM = "clockMode";
-
class FourLineDisplayUsermod : public Usermod {
private:
@@ -118,6 +109,15 @@ class FourLineDisplayUsermod : public Usermod {
// Set to 2 or 3 to mark lines 2 or 3. Other values ignored.
byte markLineNum = 0;
+ // strings to reduce flash memory usage (used more than twice)
+ static const char _name[];
+ static const char _contrast[];
+ static const char _refreshRate[];
+ static const char _screenTimeOut[];
+ static const char _flip[];
+ static const char _sleepMode[];
+ static const char _clockMode[];
+
// If display does not work or looks corrupted check the
// constructor reference:
// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
@@ -647,17 +647,17 @@ class FourLineDisplayUsermod : public Usermod {
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
*/
void addToConfig(JsonObject& root) {
- JsonObject top = root.createNestedObject(FPSTR(_um_4LineDisplay));
+ JsonObject top = root.createNestedObject(FPSTR(_name));
JsonArray i2c_pin = top.createNestedArray("pin");
i2c_pin.add(sclPin);
i2c_pin.add(sdaPin);
top["type"] = type;
- top[FPSTR(_4LD_flip)] = (bool) flip;
- top[FPSTR(_4LD_contrast)] = contrast;
- top[FPSTR(_4LD_refreshRate)] = refreshRate/1000;
- top[FPSTR(_4LD_screenTimeOut)] = screenTimeout/1000;
- top[FPSTR(_4LD_sleepMode)] = (bool) sleepMode;
- top[FPSTR(_4LD_clockMode)] = (bool) clockMode;
+ top[FPSTR(_flip)] = (bool) flip;
+ top[FPSTR(_contrast)] = contrast;
+ top[FPSTR(_refreshRate)] = refreshRate/1000;
+ top[FPSTR(_screenTimeOut)] = screenTimeout/1000;
+ top[FPSTR(_sleepMode)] = (bool) sleepMode;
+ top[FPSTR(_clockMode)] = (bool) clockMode;
DEBUG_PRINTLN(F("4 Line Display config saved."));
}
@@ -675,33 +675,33 @@ class FourLineDisplayUsermod : public Usermod {
int8_t newScl = sclPin;
int8_t newSda = sdaPin;
- JsonObject top = root[FPSTR(_um_4LineDisplay)];
+ JsonObject top = root[FPSTR(_name)];
if (!top.isNull() && top["pin"] != nullptr) {
newScl = top["pin"][0];
newSda = top["pin"][1];
newType = top["type"];
lineHeight = type==SH1106 ? 2 : 1;
- if (top[FPSTR(_4LD_flip)].is()) {
- flip = top[FPSTR(_4LD_flip)].as();
+ if (top[FPSTR(_flip)].is()) {
+ flip = top[FPSTR(_flip)].as();
} else {
- String str = top[FPSTR(_4LD_flip)]; // checkbox -> off or on
+ String str = top[FPSTR(_flip)]; // checkbox -> off or on
flip = (bool)(str!="off"); // off is guaranteed to be present
needRedraw |= true;
}
- contrast = top[FPSTR(_4LD_contrast)].as();
- refreshRate = top[FPSTR(_4LD_refreshRate)].as() * 1000;
- screenTimeout = top[FPSTR(_4LD_screenTimeOut)].as() * 1000;
- if (top[FPSTR(_4LD_sleepMode)].is()) {
- sleepMode = top[FPSTR(_4LD_sleepMode)].as();
+ 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(_4LD_sleepMode)]; // checkbox -> off or on
+ String str = top[FPSTR(_sleepMode)]; // checkbox -> off or on
sleepMode = (bool)(str!="off"); // off is guaranteed to be present
needRedraw |= true;
}
- if (top[FPSTR(_4LD_clockMode)].is()) {
- clockMode = top[FPSTR(_4LD_clockMode)].as();
+ if (top[FPSTR(_clockMode)].is()) {
+ clockMode = top[FPSTR(_clockMode)].as();
} else {
- String str = top[FPSTR(_4LD_clockMode)]; // checkbox -> off or on
+ String str = top[FPSTR(_clockMode)]; // checkbox -> off or on
clockMode = (bool)(str!="off"); // off is guaranteed to be present
needRedraw |= true;
}
@@ -746,4 +746,13 @@ class FourLineDisplayUsermod : public Usermod {
uint16_t getId() {
return USERMOD_ID_FOUR_LINE_DISP;
}
-};
\ No newline at end of file
+};
+
+// strings to reduce flash memory usage (used more than twice)
+const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay";
+const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast";
+const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRate";
+const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOut";
+const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip";
+const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode";
+const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode";
diff --git a/wled00/wled.h b/wled00/wled.h
index 0ec6dd4a4..4098ed2cd 100644
--- a/wled00/wled.h
+++ b/wled00/wled.h
@@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
-#define VERSION 2104210
+#define VERSION 2104221
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG