Rewritten usermod config saving/reloading.
Changed temperature reading (to work on ESP32 more reliably). Added Animated staircase usermod to the collection.
This commit is contained in:
parent
585f8f4683
commit
1cd56decab
@ -12,22 +12,28 @@
|
||||
#include "Animated_Staircase_config.h"
|
||||
#define USERMOD_ID_ANIMATED_STAIRCASE 1011
|
||||
|
||||
/* Initial configuration (available in API and stored in flash) */
|
||||
bool enabled = true; // Enable this usermod
|
||||
unsigned long segment_delay_ms = 150; // Time between switching each segment
|
||||
unsigned long on_time_ms = 5 * 1000; // The time for the light to stay on
|
||||
#ifndef TOP_PIR_PIN
|
||||
unsigned int topMaxTimeUs = 1749; // default echo timout, top
|
||||
#endif
|
||||
#ifndef BOTTOM_PIR_PIN
|
||||
unsigned int bottomMaxTimeUs = 1749; // default echo timout, bottom
|
||||
#endif
|
||||
|
||||
// Time between checking of the sensors
|
||||
const int scanDelay = 50;
|
||||
|
||||
class Animated_Staircase : public Usermod {
|
||||
private:
|
||||
|
||||
/* configuration (available in API and stored in flash) */
|
||||
bool enabled = false; // Enable this usermod
|
||||
unsigned long segment_delay_ms = 150; // Time between switching each segment
|
||||
unsigned long on_time_ms = 5 * 1000; // The time for the light to stay on
|
||||
int8_t topPIRorTriggerPin = -1; // disabled
|
||||
int8_t bottomPIRorTriggerPin = -1; // disabled
|
||||
int8_t topEchoPin = -1; // disabled
|
||||
int8_t bottomEchoPin = -1; // disabled
|
||||
bool useUSSensorTop = false; // using PIR or UltraSound sensor?
|
||||
bool useUSSensorBottom = false; // using PIR or UltraSound sensor?
|
||||
unsigned int topMaxTimeUs = 1749; // default echo timout, top
|
||||
unsigned int bottomMaxTimeUs = 1749; // default echo timout, bottom
|
||||
|
||||
/* runtime variables */
|
||||
bool initDone = false;
|
||||
|
||||
// Time between checking of the sensors
|
||||
const int scanDelay = 50;
|
||||
|
||||
// Lights on or off.
|
||||
// Flipping this will start a transition.
|
||||
bool on = false;
|
||||
@ -63,8 +69,6 @@ class Animated_Staircase : public Usermod {
|
||||
byte maxSegmentId = 1;
|
||||
byte mainSegmentId = 0;
|
||||
|
||||
bool saveState = false;
|
||||
|
||||
// These values are used by the API to read the
|
||||
// last sensor state, or trigger a sensor
|
||||
// through the API
|
||||
@ -74,8 +78,8 @@ class Animated_Staircase : public Usermod {
|
||||
bool bottomSensorWrite = false;
|
||||
|
||||
void updateSegments() {
|
||||
mainSegmentId = strip.getMainSegmentId();
|
||||
WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
|
||||
// mainSegmentId = strip.getMainSegmentId();
|
||||
// WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
|
||||
WS2812FX::Segment* segments = strip.getSegments();
|
||||
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
||||
if (!segments->isActive()) {
|
||||
@ -134,17 +138,15 @@ class Animated_Staircase : public Usermod {
|
||||
if ((millis() - lastScanTime) > scanDelay) {
|
||||
lastScanTime = millis();
|
||||
|
||||
#ifdef BOTTOM_PIR_PIN
|
||||
bottomSensorRead = bottomSensorWrite || (digitalRead(BOTTOM_PIR_PIN) == HIGH);
|
||||
#else
|
||||
bottomSensorRead = bottomSensorWrite || ultrasoundRead(BOTTOM_TRIGGER_PIN, BOTTOM_ECHO_PIN, bottomMaxTimeUs);
|
||||
#endif
|
||||
if (!useUSSensorBottom)
|
||||
bottomSensorRead = bottomSensorWrite || (digitalRead(bottomPIRorTriggerPin) == HIGH);
|
||||
else
|
||||
bottomSensorRead = bottomSensorWrite || ultrasoundRead(bottomPIRorTriggerPin, bottomEchoPin, bottomMaxTimeUs);
|
||||
|
||||
#ifdef TOP_PIR_PIN
|
||||
topSensorRead = topSensorWrite || (digitalRead(TOP_PIR_PIN) == HIGH);
|
||||
#else
|
||||
topSensorRead = topSensorWrite || ultrasoundRead(TOP_TRIGGER_PIN, TOP_ECHO_PIN, topMaxTimeUs);
|
||||
#endif
|
||||
if (!useUSSensorTop)
|
||||
topSensorRead = topSensorWrite || (digitalRead(topPIRorTriggerPin) == HIGH);
|
||||
else
|
||||
topSensorRead = topSensorWrite || ultrasoundRead(topPIRorTriggerPin, topEchoPin, topMaxTimeUs);
|
||||
|
||||
// Values read, reset the flags for next API call
|
||||
topSensorWrite = false;
|
||||
@ -160,9 +162,9 @@ class Animated_Staircase : public Usermod {
|
||||
swipe = bottomSensorRead;
|
||||
|
||||
if (swipe) {
|
||||
Serial.println("ON -> Swipe up.");
|
||||
DEBUG_PRINTLN(F("ON -> Swipe up."));
|
||||
} else {
|
||||
Serial.println("ON -> Swipe down.");
|
||||
DEBUG_PRINTLN(F("ON -> Swipe down."));
|
||||
}
|
||||
|
||||
if (onIndex == offIndex) {
|
||||
@ -187,9 +189,9 @@ class Animated_Staircase : public Usermod {
|
||||
on = false;
|
||||
|
||||
if (swipe) {
|
||||
Serial.println("OFF -> Swipe up.");
|
||||
DEBUG_PRINTLN(F("OFF -> Swipe up."));
|
||||
} else {
|
||||
Serial.println("OFF -> Swipe down.");
|
||||
DEBUG_PRINTLN(F("OFF -> Swipe down."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,8 +200,8 @@ class Animated_Staircase : public Usermod {
|
||||
if ((millis() - lastTime) > segment_delay_ms) {
|
||||
lastTime = millis();
|
||||
|
||||
byte oldOnIndex = onIndex;
|
||||
byte oldOffIndex = offIndex;
|
||||
// byte oldOnIndex = onIndex;
|
||||
// byte oldOffIndex = offIndex;
|
||||
|
||||
if (on) {
|
||||
// Turn on all segments
|
||||
@ -217,103 +219,46 @@ class Animated_Staircase : public Usermod {
|
||||
}
|
||||
}
|
||||
|
||||
void writeSettingsToJson(JsonObject& root) {
|
||||
JsonObject staircase = root["staircase"];
|
||||
if (staircase.isNull()) {
|
||||
staircase = root.createNestedObject("staircase");
|
||||
}
|
||||
staircase["enabled"] = enabled;
|
||||
staircase["segment-delay-ms"] = segment_delay_ms;
|
||||
staircase["on-time-s"] = on_time_ms / 1000;
|
||||
|
||||
#ifdef TOP_TRIGGER_PIN
|
||||
staircase["top-echo-us"] = topMaxTimeUs;
|
||||
#endif
|
||||
#ifdef BOTTOM_TRIGGER_PIN
|
||||
staircase["bottom-echo-us"] = bottomMaxTimeUs;
|
||||
#endif
|
||||
}
|
||||
|
||||
void writeSensorsToJson(JsonObject& root) {
|
||||
JsonObject staircase = root["staircase"];
|
||||
JsonObject staircase = root[F("staircase")];
|
||||
if (staircase.isNull()) {
|
||||
staircase = root.createNestedObject("staircase");
|
||||
staircase = root.createNestedObject(F("staircase"));
|
||||
}
|
||||
staircase["top-sensor"] = topSensorRead;
|
||||
staircase["bottom-sensor"] = bottomSensorRead;
|
||||
}
|
||||
|
||||
bool readSettingsFromJson(JsonObject& root) {
|
||||
JsonObject staircase = root["staircase"];
|
||||
bool changed = false;
|
||||
|
||||
bool shouldEnable = staircase["enabled"] | enabled;
|
||||
if (shouldEnable != enabled) {
|
||||
enable(shouldEnable);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
unsigned long c_segment_delay_ms = staircase["segment-delay-ms"] | segment_delay_ms;
|
||||
if (c_segment_delay_ms != segment_delay_ms) {
|
||||
segment_delay_ms = c_segment_delay_ms;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
unsigned long c_on_time_ms = (staircase["on-time-s"] | (on_time_ms / 1000)) * 1000;
|
||||
if (c_on_time_ms != on_time_ms) {
|
||||
on_time_ms = c_on_time_ms;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
#ifdef TOP_TRIGGER_PIN
|
||||
unsigned int c_topMaxTimeUs = staircase["top-echo-us"] | topMaxTimeUs;
|
||||
if (c_topMaxTimeUs != topMaxTimeUs) {
|
||||
topMaxTimeUs = c_topMaxTimeUs;
|
||||
changed = true;
|
||||
}
|
||||
#endif
|
||||
#ifdef BOTTOM_TRIGGER_PIN
|
||||
unsigned int c_bottomMaxTimeUs = staircase["bottom-echo-us"] | bottomMaxTimeUs;
|
||||
if (c_bottomMaxTimeUs != bottomMaxTimeUs) {
|
||||
bottomMaxTimeUs = c_bottomMaxTimeUs;
|
||||
changed = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return changed;
|
||||
staircase[F("top-sensor")] = topSensorRead;
|
||||
staircase[F("bottom-sensor")] = bottomSensorRead;
|
||||
}
|
||||
|
||||
void readSensorsFromJson(JsonObject& root) {
|
||||
JsonObject staircase = root["staircase"];
|
||||
bottomSensorWrite = bottomSensorRead || (staircase["bottom-sensor"].as<bool>());
|
||||
topSensorWrite = topSensorRead || (staircase["top-sensor"].as<bool>());
|
||||
JsonObject staircase = root[F("staircase")];
|
||||
bottomSensorWrite = bottomSensorRead || (staircase[F("bottom-sensor")].as<bool>());
|
||||
topSensorWrite = topSensorRead || (staircase[F("top-sensor")].as<bool>());
|
||||
}
|
||||
|
||||
void enable(bool enable) {
|
||||
if (enable) {
|
||||
Serial.println("Animated Staircase enabled.");
|
||||
Serial.print("Delay between steps: ");
|
||||
Serial.print(segment_delay_ms, DEC);
|
||||
Serial.print(" milliseconds.\nStairs switch off after: ");
|
||||
Serial.print(on_time_ms / 1000, DEC);
|
||||
Serial.println(" seconds.");
|
||||
DEBUG_PRINTLN(F("Animated Staircase enabled."));
|
||||
DEBUG_PRINT(F("Delay between steps: "));
|
||||
DEBUG_PRINT(segment_delay_ms);
|
||||
DEBUG_PRINT(F(" milliseconds.\nStairs switch off after: "));
|
||||
DEBUG_PRINT(on_time_ms / 1000);
|
||||
DEBUG_PRINTLN(F(" seconds."));
|
||||
|
||||
#ifdef BOTTOM_PIR_PIN
|
||||
pinMode(BOTTOM_PIR_PIN, INPUT);
|
||||
#else
|
||||
pinMode(BOTTOM_TRIGGER_PIN, OUTPUT);
|
||||
pinMode(BOTTOM_ECHO_PIN, INPUT);
|
||||
#endif
|
||||
if (!useUSSensorBottom)
|
||||
pinMode(bottomPIRorTriggerPin, INPUT);
|
||||
else {
|
||||
pinMode(bottomPIRorTriggerPin, OUTPUT);
|
||||
pinMode(bottomEchoPin, INPUT);
|
||||
}
|
||||
|
||||
#ifdef TOP_PIR_PIN
|
||||
pinMode(TOP_PIR_PIN, INPUT);
|
||||
#else
|
||||
pinMode(TOP_TRIGGER_PIN, OUTPUT);
|
||||
pinMode(TOP_ECHO_PIN, INPUT);
|
||||
#endif
|
||||
if (!useUSSensorTop)
|
||||
pinMode(topPIRorTriggerPin, INPUT);
|
||||
else {
|
||||
pinMode(topPIRorTriggerPin, OUTPUT);
|
||||
pinMode(topEchoPin, INPUT);
|
||||
}
|
||||
} else {
|
||||
// Restore segment options
|
||||
WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
|
||||
// WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
|
||||
WS2812FX::Segment* segments = strip.getSegments();
|
||||
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
||||
if (!segments->isActive()) {
|
||||
@ -323,47 +268,53 @@ class Animated_Staircase : public Usermod {
|
||||
segments->setOption(SEG_OPTION_ON, 1, 1);
|
||||
}
|
||||
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
Serial.println("Animated Staircase disabled.");
|
||||
DEBUG_PRINTLN(F("Animated Staircase disabled."));
|
||||
}
|
||||
enabled = enable;
|
||||
}
|
||||
|
||||
public:
|
||||
void setup() { enable(enabled); }
|
||||
void setup() {
|
||||
// allocate pins
|
||||
if (topPIRorTriggerPin >= 0) {
|
||||
if (!pinManager.allocatePin(topPIRorTriggerPin,useUSSensorTop))
|
||||
topPIRorTriggerPin = -1;
|
||||
}
|
||||
if (topEchoPin >= 0) {
|
||||
if (!pinManager.allocatePin(topEchoPin,false))
|
||||
topEchoPin = -1;
|
||||
}
|
||||
if (bottomPIRorTriggerPin >= 0) {
|
||||
if (!pinManager.allocatePin(bottomPIRorTriggerPin,useUSSensorBottom))
|
||||
bottomPIRorTriggerPin = -1;
|
||||
}
|
||||
if (bottomEchoPin >= 0) {
|
||||
if (!pinManager.allocatePin(bottomPIRorTriggerPin,false))
|
||||
bottomEchoPin = -1;
|
||||
}
|
||||
|
||||
// validate pins
|
||||
if ( topPIRorTriggerPin < 0 || bottomPIRorTriggerPin < 0 ||
|
||||
(useUSSensorTop && topEchoPin < 0) || (useUSSensorBottom && bottomEchoPin < 0) )
|
||||
enabled = false;
|
||||
|
||||
enable(enabled);
|
||||
initDone = true;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Write changed settings from to flash (see readFromJsonState())
|
||||
if (saveState) {
|
||||
serializeConfig();
|
||||
saveState = false;
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!enabled) return;
|
||||
checkSensors();
|
||||
autoPowerOff();
|
||||
updateSwipe();
|
||||
|
||||
}
|
||||
|
||||
uint16_t getId() { return USERMOD_ID_ANIMATED_STAIRCASE; }
|
||||
|
||||
/*
|
||||
* Shows configuration settings to the json API. This object looks like:
|
||||
*
|
||||
* "staircase" : {
|
||||
* "enabled" : true
|
||||
* "segment-delay-ms" : 150,
|
||||
* "on-time-s" : 5
|
||||
* }
|
||||
*
|
||||
*/
|
||||
void addToJsonState(JsonObject& root) {
|
||||
writeSettingsToJson(root);
|
||||
writeSensorsToJson(root);
|
||||
Serial.println("Staircase config exposed in API.");
|
||||
// writeSettingsToJson(root);
|
||||
// writeSensorsToJson(root);
|
||||
// DEBUG_PRINTLN(F("Staircase config exposed in API."));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -371,27 +322,103 @@ class Animated_Staircase : public Usermod {
|
||||
* See void addToJsonState(JsonObject& root)
|
||||
*/
|
||||
void readFromJsonState(JsonObject& root) {
|
||||
// The call to serializeConfig() must be done in the main loop,
|
||||
// so we set a flag to signal the main loop to save state.
|
||||
saveState = readSettingsFromJson(root);
|
||||
readSensorsFromJson(root);
|
||||
Serial.println("Staircase config read from API.");
|
||||
if (!initDone) return; // prevent crash on boot applyPreset()
|
||||
JsonObject staircase = root[F("staircase")];
|
||||
if (!staircase.isNull()) {
|
||||
if (staircase[F("enabled")].is<bool>()) {
|
||||
enabled = staircase[F("enabled")].as<bool>();
|
||||
} else {
|
||||
String str = staircase[F("enabled")]; // checkbox -> off or on
|
||||
enabled = (bool)(str!="off"); // off is guaranteed to be present
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes the configuration to internal flash memory.
|
||||
*/
|
||||
void addToConfig(JsonObject& root) {
|
||||
writeSettingsToJson(root);
|
||||
Serial.println("Staircase config saved.");
|
||||
JsonObject staircase = root[F("staircase")];
|
||||
if (staircase.isNull()) {
|
||||
staircase = root.createNestedObject(F("staircase"));
|
||||
}
|
||||
staircase[F("enabled")] = enabled;
|
||||
staircase[F("segment-delay-ms")] = segment_delay_ms;
|
||||
staircase[F("on-time-s")] = on_time_ms / 1000;
|
||||
staircase[F("useTopUltrasoundSensor")] = useUSSensorTop;
|
||||
staircase[F("topPIRorTrigger_pin")] = topPIRorTriggerPin;
|
||||
staircase[F("topEcho_pin")] = topEchoPin;
|
||||
staircase[F("useBottomUltrasoundSensor")] = useUSSensorBottom;
|
||||
staircase[F("bottomPIRorTrigger_pin")] = bottomPIRorTriggerPin;
|
||||
staircase[F("bottomEcho_pin")] = bottomEchoPin;
|
||||
staircase[F("top-echo-us")] = topMaxTimeUs;
|
||||
staircase[F("bottom-echo-us")] = bottomMaxTimeUs;
|
||||
DEBUG_PRINTLN(F("Staircase config saved."));
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads the configuration to internal flash memory before setup() is called.
|
||||
*/
|
||||
void readFromConfig(JsonObject& root) {
|
||||
readSettingsFromJson(root);
|
||||
Serial.println("Staircase config loaded.");
|
||||
bool oldUseUSSensorTop = useUSSensorTop;
|
||||
bool oldUseUSSensorBottom = useUSSensorBottom;
|
||||
int8_t oldTopAPin = topPIRorTriggerPin;
|
||||
int8_t oldTopBPin = topEchoPin;
|
||||
int8_t oldBottomAPin = bottomPIRorTriggerPin;
|
||||
int8_t oldBottomBPin = bottomEchoPin;
|
||||
|
||||
JsonObject staircase = root[F("staircase")];
|
||||
if (!staircase.isNull()) {
|
||||
if (staircase[F("enabled")].is<bool>()) {
|
||||
enabled = staircase[F("enabled")].as<bool>();
|
||||
} else {
|
||||
String str = staircase[F("enabled")]; // checkbox -> off or on
|
||||
enabled = (bool)(str!="off"); // off is guaranteed to be present
|
||||
}
|
||||
segment_delay_ms = staircase[F("segment-delay-ms")];
|
||||
on_time_ms = (int)staircase[F("on-time-s")] * 1000;
|
||||
if (staircase[F("useTopUltrasoundSensor")].is<bool>()) {
|
||||
useUSSensorTop = staircase[F("useTopUltrasoundSensor")].as<bool>();
|
||||
} else {
|
||||
String str = staircase[F("useTopUltrasoundSensor")]; // checkbox -> off or on
|
||||
useUSSensorTop = (bool)(str!="off"); // off is guaranteed to be present
|
||||
}
|
||||
topPIRorTriggerPin = staircase[F("topPIRorTrigger_pin")];
|
||||
topEchoPin = staircase[F("topEcho_pin")];
|
||||
useUSSensorBottom = staircase[F("useBottomUltrasoundSensor")].as<bool>();
|
||||
if (staircase[F("useBottomUltrasoundSensor")].is<bool>()) {
|
||||
useUSSensorBottom = staircase[F("useBottomUltrasoundSensor")].as<bool>();
|
||||
} else {
|
||||
String str = staircase[F("useBottomUltrasoundSensor")]; // checkbox -> off or on
|
||||
useUSSensorBottom = (bool)(str!="off"); // off is guaranteed to be present
|
||||
}
|
||||
bottomPIRorTriggerPin = staircase[F("bottomPIRorTrigger_pin")];
|
||||
bottomEchoPin = staircase[F("bottomEcho_pin")];
|
||||
topMaxTimeUs = staircase[F("top-echo-us")];
|
||||
bottomMaxTimeUs = staircase[F("bottom-echo-us")];
|
||||
DEBUG_PRINTLN(F("Staircase config (re)loaded."));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("No config found. (Using defaults.)"));
|
||||
}
|
||||
if (!initDone) {
|
||||
// first run: reading from cfg.json
|
||||
} else {
|
||||
// changing paramters from settings page
|
||||
bool changed = false;
|
||||
if ((oldUseUSSensorTop != useUSSensorTop) ||
|
||||
(oldUseUSSensorBottom != useUSSensorBottom) ||
|
||||
(oldTopAPin != topPIRorTriggerPin) ||
|
||||
(oldTopBPin != topEchoPin) ||
|
||||
(oldBottomAPin != bottomPIRorTriggerPin) ||
|
||||
(oldBottomBPin != bottomEchoPin)) {
|
||||
changed = true;
|
||||
pinManager.deallocatePin(oldTopAPin);
|
||||
pinManager.deallocatePin(oldTopBPin);
|
||||
pinManager.deallocatePin(oldBottomAPin);
|
||||
pinManager.deallocatePin(oldBottomBPin);
|
||||
}
|
||||
if (changed) setup();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -405,23 +432,21 @@ class Animated_Staircase : public Usermod {
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
JsonArray usermodEnabled =
|
||||
staircase.createNestedArray("Staircase enabled"); // name
|
||||
JsonArray usermodEnabled = staircase.createNestedArray(F("Staircase enabled")); // name
|
||||
usermodEnabled.add("yes"); // value
|
||||
|
||||
JsonArray segmentDelay =
|
||||
staircase.createNestedArray("Delay between stairs"); // name
|
||||
JsonArray segmentDelay = staircase.createNestedArray(F("Delay between stairs")); // name
|
||||
segmentDelay.add(segment_delay_ms); // value
|
||||
segmentDelay.add(" milliseconds"); // unit
|
||||
segmentDelay.add("ms"); // unit
|
||||
|
||||
JsonArray onTime =
|
||||
staircase.createNestedArray("Power-off stairs after"); // name
|
||||
JsonArray onTime = staircase.createNestedArray(F("Power-off stairs after")); // name
|
||||
onTime.add(on_time_ms / 1000); // value
|
||||
onTime.add(" seconds"); // unit
|
||||
onTime.add("s"); // unit
|
||||
} else {
|
||||
JsonArray usermodEnabled =
|
||||
staircase.createNestedArray("Staircase enabled"); // name
|
||||
JsonArray usermodEnabled = staircase.createNestedArray(F("Staircase enabled")); // name
|
||||
usermodEnabled.add("no"); // value
|
||||
JsonArray topPin = staircase.createNestedArray(F("Top pin")); // name
|
||||
topPin.add(topPIRorTriggerPin); // value
|
||||
}
|
||||
}
|
||||
};
|
@ -32,16 +32,11 @@ class UsermodTemperature : public Usermod {
|
||||
|
||||
bool initDone = false;
|
||||
OneWire *oneWire;
|
||||
DallasTemperature *sensor;
|
||||
// The device's unique 64-bit serial code stored in on-board ROM.
|
||||
// Reading directly from the sensor device address is faster than
|
||||
// reading from index. When reading by index, DallasTemperature
|
||||
// must first look up the device address at the specified index.
|
||||
DeviceAddress sensorDeviceAddress;
|
||||
// GPIO pin used for sensor (with a default compile-time fallback)
|
||||
int8_t temperaturePin = TEMPERATURE_PIN;
|
||||
// measurement unit (true==°C, false==°F)
|
||||
bool degC = true;
|
||||
unsigned long readingInterval = USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL;
|
||||
// set last reading as "40 sec before boot", so first reading is taken after 20 sec
|
||||
unsigned long lastMeasurement = UINT32_MAX - (USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL - USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT);
|
||||
// last time requestTemperatures was called
|
||||
@ -59,51 +54,77 @@ class UsermodTemperature : public Usermod {
|
||||
// temperature if flashed to a board without a sensor attached
|
||||
bool disabled = false;
|
||||
|
||||
//Dallas sensor quick reading. Credit to - Author: Peter Scargill, August 17th, 2013
|
||||
int16_t readDallas() {
|
||||
byte i;
|
||||
byte data[2];
|
||||
int16_t result;
|
||||
oneWire->reset();
|
||||
oneWire->write(0xCC);
|
||||
oneWire->write(0xBE);
|
||||
for (i=0; i < 2; i++) data[i] = oneWire->read();
|
||||
result = (data[1]<<8) | data[0];
|
||||
result >>= 4;
|
||||
if (data[1]&0x80) result |= 61440;
|
||||
if (data[0]&0x08) ++result;
|
||||
oneWire->reset();
|
||||
oneWire->write(0xCC);
|
||||
oneWire->write(0x44,1);
|
||||
return result*10;
|
||||
}
|
||||
|
||||
void requestTemperatures() {
|
||||
// there is requestTemperaturesByAddress however it
|
||||
// appears to do more work,
|
||||
// TODO: measure exection time difference
|
||||
sensor->requestTemperatures();
|
||||
lastTemperaturesRequest = millis();
|
||||
waitingForConversion = true;
|
||||
readDallas();
|
||||
lastTemperaturesRequest = millis();
|
||||
waitingForConversion = true;
|
||||
DEBUG_PRINTLN(F("Requested temperature."));
|
||||
}
|
||||
|
||||
void getTemperature() {
|
||||
if (strip.isUpdating()) return;
|
||||
|
||||
if (degC) temperature = sensor->getTempC(sensorDeviceAddress);
|
||||
else temperature = sensor->getTempF(sensorDeviceAddress);
|
||||
|
||||
temperature = readDallas()/10.0f;
|
||||
if (!degC) temperature = temperature * 1.8f + 32;
|
||||
lastMeasurement = millis();
|
||||
waitingForConversion = false;
|
||||
getTemperatureComplete = true;
|
||||
DEBUG_PRINTF("Read temperature %2.1f.\n", temperature);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void setup() {
|
||||
//bool sensorFound = false;
|
||||
|
||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||
if (!pinManager.allocatePin(temperaturePin,false)) {
|
||||
temperaturePin = -1; // allocation failed
|
||||
DEBUG_PRINTLN(F("Temperature pin allocation failed."));
|
||||
} else {
|
||||
//DeviceAddress deviceAddress;
|
||||
oneWire = new OneWire(temperaturePin);
|
||||
sensor = new DallasTemperature(oneWire);
|
||||
if (sensor) sensor->begin();
|
||||
else
|
||||
DEBUG_PRINTLN(F("Temperature sensor allocation failed."));
|
||||
oneWire->reset();
|
||||
/*
|
||||
// find out if we have DS18xxx sensor attached
|
||||
oneWire->reset_search();
|
||||
while (oneWire->search(deviceAddress)) {
|
||||
if (oneWire->crc8(deviceAddress, 7) == deviceAddress[7]) {
|
||||
switch (deviceAddress[0]) {
|
||||
case 0x10: // DS18S20
|
||||
case 0x22: // DS18B20
|
||||
case 0x28: // DS1822
|
||||
case 0x3B: // DS1825
|
||||
case 0x42: // DS28EA00
|
||||
sensorFound = true; // sensor found;
|
||||
DEBUG_PRINTLN(F("Sensor found."));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// get the unique 64-bit serial code stored in on-board ROM
|
||||
// if getAddress returns false, the sensor was not found
|
||||
disabled = (temperaturePin==-1) || !sensor->getAddress(sensorDeviceAddress, 0);
|
||||
disabled = disabled || (temperaturePin==-1);
|
||||
|
||||
if (!disabled) {
|
||||
DEBUG_PRINTLN(F("Dallas Temperature found"));
|
||||
// set the resolution for this specific device
|
||||
sensor->setResolution(sensorDeviceAddress, 9, true);
|
||||
// do not block waiting for reading
|
||||
sensor->setWaitForConversion(false);
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("Dallas Temperature not found"));
|
||||
}
|
||||
@ -118,7 +139,7 @@ class UsermodTemperature : public Usermod {
|
||||
// check to see if we are due for taking a measurement
|
||||
// lastMeasurement will not be updated until the conversion
|
||||
// is complete the the reading is finished
|
||||
if (now - lastMeasurement < USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL) return;
|
||||
if (now - lastMeasurement < readingInterval) return;
|
||||
|
||||
// we are due for a measurement, if we are not already waiting
|
||||
// for a conversion to complete, then make a new request for temps
|
||||
@ -128,7 +149,7 @@ class UsermodTemperature : public Usermod {
|
||||
}
|
||||
|
||||
// we were waiting for a conversion to complete, have we waited log enough?
|
||||
if (now - lastTemperaturesRequest >= 95 /* 93.75ms per the datasheet */) {
|
||||
if (now - lastTemperaturesRequest >= 800 /* 93.75ms per the datasheet but can be up to 750ms*/) {
|
||||
getTemperature();
|
||||
|
||||
if (WLED_MQTT_CONNECTED) {
|
||||
@ -196,35 +217,6 @@ class UsermodTemperature : public Usermod {
|
||||
*/
|
||||
void readFromJsonState(JsonObject &root) {
|
||||
if (!initDone) return; // prevent crash on boot applyPreset()
|
||||
if (root[F("Temperature_pin")] != nullptr) {
|
||||
int8_t pin = min(39,max(0,(int)root[F("Temperature_pin")]));
|
||||
if (pin != temperaturePin) {
|
||||
// deallocate pin and release memory
|
||||
delete sensor;
|
||||
delete oneWire;
|
||||
pinManager.deallocatePin(temperaturePin);
|
||||
// disable usermod
|
||||
temperaturePin = -1;
|
||||
disabled = true;
|
||||
// check if pin is OK
|
||||
if (pin>=0 && pinManager.allocatePin(pin,false)) {
|
||||
// allocat memory
|
||||
oneWire = new OneWire(pin);
|
||||
sensor = new DallasTemperature(oneWire);
|
||||
if (sensor) {
|
||||
temperaturePin = pin;
|
||||
sensor->begin();
|
||||
disabled = !sensor->getAddress(sensorDeviceAddress, 0);
|
||||
} else {
|
||||
pinManager.deallocatePin(pin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (root[F("Temperature_degC")] != nullptr) {
|
||||
String strDegC = root[F("Temperature_degC")]; // checkbox -> off or on
|
||||
degC = (bool) (strDegC!="off"); // off is guaranteed to be present
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -233,8 +225,11 @@ class UsermodTemperature : public Usermod {
|
||||
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;
|
||||
top["pin"] = temperaturePin; // usermodparam
|
||||
top["degC"] = degC; // usermodparam
|
||||
top[F("read-interval-s")] = readingInterval / 1000;
|
||||
DEBUG_PRINTLN(F("Temperature config saved."));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -243,12 +238,40 @@ class UsermodTemperature : public Usermod {
|
||||
void readFromConfig(JsonObject &root) {
|
||||
// we look for JSON object: {"Temperature": {"pin": 0, "degC": true}}
|
||||
JsonObject top = root[FPSTR(_um_Temperature)];
|
||||
int8_t newTemperaturePin = temperaturePin;
|
||||
if (!top.isNull() && top["pin"] != nullptr) {
|
||||
temperaturePin = (int)top["pin"];
|
||||
degC = top["degC"] != nullptr ? top["degC"] : true;
|
||||
if (top[F("enabled")].is<bool>()) {
|
||||
disabled = !top[F("enabled")].as<bool>();
|
||||
} else {
|
||||
String str = top[F("enabled")]; // checkbox -> off or on
|
||||
disabled = (bool)(str=="off"); // off is guaranteed to be present
|
||||
}
|
||||
newTemperaturePin = min(39,max(-1,top["pin"].as<int>()));
|
||||
if (top["degC"].is<bool>()) {
|
||||
degC = top["degC"].as<bool>();
|
||||
} else {
|
||||
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<int>())) * 1000;
|
||||
DEBUG_PRINTLN(F("Temperature config loaded."));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("No config found. (Using defaults.)"));
|
||||
}
|
||||
if (!initDone) {
|
||||
// first run: reading from cfg.json
|
||||
temperaturePin = newTemperaturePin;
|
||||
} else {
|
||||
// changing paramters from settings page
|
||||
if (newTemperaturePin != temperaturePin) {
|
||||
// deallocate pin and release memory
|
||||
delete oneWire;
|
||||
pinManager.deallocatePin(temperaturePin);
|
||||
temperaturePin = newTemperaturePin;
|
||||
// initialise
|
||||
setup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t getId()
|
||||
|
@ -160,20 +160,9 @@ class AutoSaveUsermod : public Usermod {
|
||||
* 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()
|
||||
|
||||
if (root[F("Autosave_autoSaveAfterSec")] != nullptr) {
|
||||
autoSaveAfterSec = min(60,max(0,(int)root[F("Autosave_autoSaveAfterSec")]));
|
||||
}
|
||||
if (root[F("Autosave_autoSavePreset")] != nullptr) {
|
||||
autoSavePreset = min(250,max(0,(int)root[F("Autosave_autoSavePreset")]));
|
||||
}
|
||||
if (root[F("Autosave_autoSaveApplyOnBoot")] != nullptr) {
|
||||
String str = root[F("Autosave_autoSaveApplyOnBoot")]; // checkbox -> off or on
|
||||
applyAutoSaveOnBoot = (bool)(str!="off"); // off is guaranteed to be present
|
||||
}
|
||||
}
|
||||
//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.
|
||||
@ -195,6 +184,7 @@ class AutoSaveUsermod : public Usermod {
|
||||
top[FPSTR(_autoSaveAfterSec)] = autoSaveAfterSec; // usermodparam
|
||||
top[FPSTR(_autoSavePreset)] = autoSavePreset; // usermodparam
|
||||
top[FPSTR(_autoSaveApplyOnBoot)] = applyAutoSaveOnBoot;
|
||||
DEBUG_PRINTLN(F("Autosave config saved."));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -209,9 +199,17 @@ class AutoSaveUsermod : public Usermod {
|
||||
// we look for JSON object: {"Autosave": {"autoSaveAfterSec": 10, "autoSavePreset": 99}}
|
||||
JsonObject top = root[FPSTR(_um_AutoSave)];
|
||||
if (!top.isNull() && top[FPSTR(_autoSaveAfterSec)] != nullptr) {
|
||||
autoSaveAfterSec = (int) top[FPSTR(_autoSaveAfterSec)];
|
||||
autoSavePreset = (int) top[FPSTR(_autoSavePreset)];
|
||||
applyAutoSaveOnBoot = (bool)top[FPSTR(_autoSaveApplyOnBoot)];
|
||||
autoSaveAfterSec = top[FPSTR(_autoSaveAfterSec)].as<int>();
|
||||
autoSavePreset = top[FPSTR(_autoSavePreset)].as<int>();
|
||||
if (top[FPSTR(_autoSaveApplyOnBoot)].is<bool>()) {
|
||||
// reading from cfg.json
|
||||
applyAutoSaveOnBoot = top[FPSTR(_autoSaveApplyOnBoot)].as<bool>();
|
||||
} 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.)"));
|
||||
}
|
||||
|
@ -628,62 +628,9 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
* 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()
|
||||
|
||||
bool needsRedraw = false;
|
||||
DisplayType newType = type;
|
||||
int8_t newScl = sclPin;
|
||||
int8_t newSda = sdaPin;
|
||||
|
||||
if (root[F("4LineDisplay_type")] != nullptr) newType = (DisplayType)root[F("4LineDisplay_type")];
|
||||
if (root[F("4LineDisplay_pin")] != nullptr) {
|
||||
newScl = min(39,max(0,(int)root[F("4LineDisplay_pin")][0]));
|
||||
newSda = min(39,max(0,(int)root[F("4LineDisplay_pin")][1]));
|
||||
if (newScl==newSda) newScl = newSda = -1;
|
||||
}
|
||||
if (root[F("4LineDisplay_contrast")] != nullptr) {
|
||||
contrast = min(255,max(1,(int)root[F("4LineDisplay_contrast")]));
|
||||
setContrast(contrast);
|
||||
needsRedraw |= true;
|
||||
}
|
||||
if (root[F("4LineDisplay_refreshRate")] != nullptr) refreshRate = min(60,max(1,(int)root[F("4LineDisplay_refreshRate")]))*1000;
|
||||
if (root[F("4LineDisplay_screenTimeOut")] != nullptr) screenTimeout = min(900,max(0,(int)root[F("4LineDisplay_screenTimeOut")]))*1000;
|
||||
if (root[F("4LineDisplay_flip")] != nullptr) {
|
||||
String str = root[F("4LineDisplay_flip")]; // checkbox -> off or on
|
||||
flip = (bool)(str!="off"); // off is guaranteed to be present
|
||||
setFlipMode(flip);
|
||||
needsRedraw |= true;
|
||||
}
|
||||
if (root[F("4LineDisplay_sleepMode")] != nullptr) {
|
||||
String str = root[F("4LineDisplay_sleepMode")]; // checkbox -> off or on
|
||||
sleepMode = (bool)(str!="off"); // off is guaranteed to be present
|
||||
}
|
||||
if (root[F("4LineDisplay_clockMode")] != nullptr) {
|
||||
String str = root[F("4LineDisplay_clockMode")]; // checkbox -> off or on
|
||||
clockMode = (bool)(str!="off"); // off is guaranteed to be present
|
||||
setLineThreeType(clockMode ? FLD_LINE_3_MODE : FLD_LINE_3_BRIGHTNESS);
|
||||
needsRedraw |= true;
|
||||
}
|
||||
|
||||
if (sclPin!=newScl || sdaPin!=newSda || type!=newType) {
|
||||
if (type==SSD1306) delete (static_cast<U8X8_SSD1306_128X32_UNIVISION_HW_I2C*>(u8x8));
|
||||
if (type==SH1106) delete (static_cast<U8X8_SH1106_128X64_WINSTAR_HW_I2C*>(u8x8));
|
||||
pinManager.deallocatePin(sclPin);
|
||||
pinManager.deallocatePin(sdaPin);
|
||||
sclPin = newScl;
|
||||
sdaPin = newSda;
|
||||
if (newScl<0 || newSda<0) {
|
||||
type = NONE;
|
||||
return;
|
||||
} else
|
||||
type = newType;
|
||||
lineHeight = type==SH1106 ? 2 : 1;
|
||||
setup();
|
||||
needRedraw |= true;
|
||||
}
|
||||
if (needsRedraw && !wakeDisplay()) redraw(true);
|
||||
}
|
||||
//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.
|
||||
@ -711,6 +658,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
top[FPSTR(_4LD_screenTimeOut)] = screenTimeout/1000;
|
||||
top[FPSTR(_4LD_sleepMode)] = (bool) sleepMode;
|
||||
top[FPSTR(_4LD_clockMode)] = (bool) clockMode;
|
||||
DEBUG_PRINTLN(F("4 Line Display config saved."));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -722,21 +670,73 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
* 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 needsRedraw = false;
|
||||
DisplayType newType = type;
|
||||
int8_t newScl = sclPin;
|
||||
int8_t newSda = sdaPin;
|
||||
|
||||
JsonObject top = root[FPSTR(_um_4LineDisplay)];
|
||||
if (!top.isNull() && top["pin"] != nullptr) {
|
||||
sclPin = top["pin"][0];
|
||||
sdaPin = top["pin"][1];
|
||||
type = top["type"];
|
||||
newScl = top["pin"][0];
|
||||
newSda = top["pin"][1];
|
||||
newType = top["type"];
|
||||
lineHeight = type==SH1106 ? 2 : 1;
|
||||
flip = top[FPSTR(_4LD_flip)];
|
||||
contrast = top[FPSTR(_4LD_contrast)];
|
||||
refreshRate = int(top[FPSTR(_4LD_refreshRate)])*1000;
|
||||
screenTimeout = int(top[FPSTR(_4LD_screenTimeOut)])*1000;
|
||||
sleepMode = top[FPSTR(_4LD_sleepMode)];
|
||||
clockMode = top[FPSTR(_4LD_clockMode)];
|
||||
if (top[FPSTR(_4LD_flip)].is<bool>()) {
|
||||
flip = top[FPSTR(_4LD_flip)].as<bool>();
|
||||
} else {
|
||||
String str = top[FPSTR(_4LD_flip)]; // checkbox -> off or on
|
||||
flip = (bool)(str!="off"); // off is guaranteed to be present
|
||||
needRedraw |= true;
|
||||
}
|
||||
contrast = top[FPSTR(_4LD_contrast)].as<int>();
|
||||
refreshRate = top[FPSTR(_4LD_refreshRate)].as<int>() * 1000;
|
||||
screenTimeout = top[FPSTR(_4LD_screenTimeOut)].as<int>() * 1000;
|
||||
if (top[FPSTR(_4LD_sleepMode)].is<bool>()) {
|
||||
sleepMode = top[FPSTR(_4LD_sleepMode)].as<bool>();
|
||||
} else {
|
||||
String str = top[FPSTR(_4LD_sleepMode)]; // checkbox -> off or on
|
||||
sleepMode = (bool)(str!="off"); // off is guaranteed to be present
|
||||
needRedraw |= true;
|
||||
}
|
||||
if (top[FPSTR(_4LD_clockMode)].is<bool>()) {
|
||||
clockMode = top[FPSTR(_4LD_clockMode)].as<bool>();
|
||||
} else {
|
||||
String str = top[FPSTR(_4LD_clockMode)]; // checkbox -> off or on
|
||||
clockMode = (bool)(str!="off"); // off is guaranteed to be present
|
||||
needRedraw |= true;
|
||||
}
|
||||
DEBUG_PRINTLN(F("4 Line Display config (re)loaded."));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F("No config found. (Using defaults.)"));
|
||||
}
|
||||
|
||||
if (!initDone) {
|
||||
// first run: reading from cfg.json
|
||||
sclPin = newScl;
|
||||
sdaPin = newSda;
|
||||
type = newType;
|
||||
} else {
|
||||
// changing paramters from settings page
|
||||
if (sclPin!=newScl || sdaPin!=newSda || type!=newType) {
|
||||
if (type==SSD1306) delete (static_cast<U8X8_SSD1306_128X32_UNIVISION_HW_I2C*>(u8x8));
|
||||
if (type==SH1106) delete (static_cast<U8X8_SH1106_128X64_WINSTAR_HW_I2C*>(u8x8));
|
||||
pinManager.deallocatePin(sclPin);
|
||||
pinManager.deallocatePin(sdaPin);
|
||||
sclPin = newScl;
|
||||
sdaPin = newSda;
|
||||
if (newScl<0 || newSda<0) {
|
||||
type = NONE;
|
||||
return;
|
||||
} else
|
||||
type = newType;
|
||||
lineHeight = type==SH1106 ? 2 : 1;
|
||||
setup();
|
||||
needRedraw |= true;
|
||||
}
|
||||
setContrast(contrast);
|
||||
setFlipMode(flip);
|
||||
if (needsRedraw && !wakeDisplay()) redraw(true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -419,14 +419,27 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
String name = request->argName(i);
|
||||
String value = request->arg(i);
|
||||
|
||||
// POST request parameters are combined as <usermodname>_<usermodparameter>
|
||||
uint8_t umNameEnd = name.indexOf("_");
|
||||
if (!umNameEnd) break; // parameter does not contain "_" -> wrong
|
||||
|
||||
JsonObject mod = um[name.substring(0,umNameEnd)]; // get a usermod JSON object
|
||||
if (mod.isNull()) {
|
||||
mod = um.createNestedObject(name.substring(0,umNameEnd)); // if it does not exist create it
|
||||
}
|
||||
DEBUG_PRINT(name.substring(0,umNameEnd));
|
||||
DEBUG_PRINT(":");
|
||||
name = name.substring(umNameEnd+1); // remove mod name from string
|
||||
|
||||
// check if parameters represent array
|
||||
if (name.endsWith("[]")) {
|
||||
name.replace("[]","");
|
||||
if (!um[name].is<JsonArray>()) {
|
||||
JsonArray ar = um.createNestedArray(name);
|
||||
if (!mod[name].is<JsonArray>()) {
|
||||
JsonArray ar = mod.createNestedArray(name);
|
||||
ar.add(value);
|
||||
j=0;
|
||||
} else {
|
||||
um[name].add(value);
|
||||
mod[name].add(value);
|
||||
j++;
|
||||
}
|
||||
DEBUG_PRINT(name);
|
||||
@ -435,14 +448,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
DEBUG_PRINT("] = ");
|
||||
DEBUG_PRINTLN(value);
|
||||
} else {
|
||||
um.remove(name); // checkboxes get two fields (first is always "off", existence of second depends on checkmark and may be "on")
|
||||
um[name] = value;
|
||||
mod.remove(name); // checkboxes get two fields (first is always "off", existence of second depends on checkmark and may be "on")
|
||||
mod[name] = value;
|
||||
DEBUG_PRINT(name);
|
||||
DEBUG_PRINT(" = ");
|
||||
DEBUG_PRINTLN(value);
|
||||
}
|
||||
}
|
||||
usermods.readFromJsonState(um);
|
||||
usermods.readFromConfig(um); // force change of usermod parameters
|
||||
}
|
||||
|
||||
if (subPage != 2 && (subPage != 6 || !doReboot)) serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init)
|
||||
|
@ -50,6 +50,10 @@
|
||||
#include "../usermods/VL53L0X_gestures/usermod_vl53l0x_gestures.h"
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_ANIMATED_STAIRCASE
|
||||
#include "../usermods/Animated_Staircase/Animated_Staircase.h"
|
||||
#endif
|
||||
|
||||
void registerUsermods()
|
||||
{
|
||||
/*
|
||||
@ -96,4 +100,8 @@ void registerUsermods()
|
||||
#ifdef USERMOD_VL53L0X_GESTURES
|
||||
usermods.add(new UsermodVL53L0XGestures());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_ANIMATED_STAIRCASE
|
||||
usermods.add(new Animated_Staircase());
|
||||
#endif
|
||||
}
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2104151
|
||||
#define VERSION 2104171
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
|
Loading…
Reference in New Issue
Block a user