mirror of
https://github.com/wled/WLED.git
synced 2025-07-27 04:36:33 +00:00
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"
|
#include "Animated_Staircase_config.h"
|
||||||
#define USERMOD_ID_ANIMATED_STAIRCASE 1011
|
#define USERMOD_ID_ANIMATED_STAIRCASE 1011
|
||||||
|
|
||||||
/* Initial configuration (available in API and stored in flash) */
|
class Animated_Staircase : public Usermod {
|
||||||
bool enabled = true; // Enable this 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 segment_delay_ms = 150; // Time between switching each segment
|
||||||
unsigned long on_time_ms = 5 * 1000; // The time for the light to stay on
|
unsigned long on_time_ms = 5 * 1000; // The time for the light to stay on
|
||||||
#ifndef TOP_PIR_PIN
|
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 topMaxTimeUs = 1749; // default echo timout, top
|
||||||
#endif
|
|
||||||
#ifndef BOTTOM_PIR_PIN
|
|
||||||
unsigned int bottomMaxTimeUs = 1749; // default echo timout, bottom
|
unsigned int bottomMaxTimeUs = 1749; // default echo timout, bottom
|
||||||
#endif
|
|
||||||
|
/* runtime variables */
|
||||||
|
bool initDone = false;
|
||||||
|
|
||||||
// Time between checking of the sensors
|
// Time between checking of the sensors
|
||||||
const int scanDelay = 50;
|
const int scanDelay = 50;
|
||||||
|
|
||||||
class Animated_Staircase : public Usermod {
|
|
||||||
private:
|
|
||||||
// Lights on or off.
|
// Lights on or off.
|
||||||
// Flipping this will start a transition.
|
// Flipping this will start a transition.
|
||||||
bool on = false;
|
bool on = false;
|
||||||
@ -63,8 +69,6 @@ class Animated_Staircase : public Usermod {
|
|||||||
byte maxSegmentId = 1;
|
byte maxSegmentId = 1;
|
||||||
byte mainSegmentId = 0;
|
byte mainSegmentId = 0;
|
||||||
|
|
||||||
bool saveState = false;
|
|
||||||
|
|
||||||
// These values are used by the API to read the
|
// These values are used by the API to read the
|
||||||
// last sensor state, or trigger a sensor
|
// last sensor state, or trigger a sensor
|
||||||
// through the API
|
// through the API
|
||||||
@ -74,8 +78,8 @@ class Animated_Staircase : public Usermod {
|
|||||||
bool bottomSensorWrite = false;
|
bool bottomSensorWrite = false;
|
||||||
|
|
||||||
void updateSegments() {
|
void updateSegments() {
|
||||||
mainSegmentId = strip.getMainSegmentId();
|
// mainSegmentId = strip.getMainSegmentId();
|
||||||
WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
|
// WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
|
||||||
WS2812FX::Segment* segments = strip.getSegments();
|
WS2812FX::Segment* segments = strip.getSegments();
|
||||||
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
||||||
if (!segments->isActive()) {
|
if (!segments->isActive()) {
|
||||||
@ -134,17 +138,15 @@ class Animated_Staircase : public Usermod {
|
|||||||
if ((millis() - lastScanTime) > scanDelay) {
|
if ((millis() - lastScanTime) > scanDelay) {
|
||||||
lastScanTime = millis();
|
lastScanTime = millis();
|
||||||
|
|
||||||
#ifdef BOTTOM_PIR_PIN
|
if (!useUSSensorBottom)
|
||||||
bottomSensorRead = bottomSensorWrite || (digitalRead(BOTTOM_PIR_PIN) == HIGH);
|
bottomSensorRead = bottomSensorWrite || (digitalRead(bottomPIRorTriggerPin) == HIGH);
|
||||||
#else
|
else
|
||||||
bottomSensorRead = bottomSensorWrite || ultrasoundRead(BOTTOM_TRIGGER_PIN, BOTTOM_ECHO_PIN, bottomMaxTimeUs);
|
bottomSensorRead = bottomSensorWrite || ultrasoundRead(bottomPIRorTriggerPin, bottomEchoPin, bottomMaxTimeUs);
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TOP_PIR_PIN
|
if (!useUSSensorTop)
|
||||||
topSensorRead = topSensorWrite || (digitalRead(TOP_PIR_PIN) == HIGH);
|
topSensorRead = topSensorWrite || (digitalRead(topPIRorTriggerPin) == HIGH);
|
||||||
#else
|
else
|
||||||
topSensorRead = topSensorWrite || ultrasoundRead(TOP_TRIGGER_PIN, TOP_ECHO_PIN, topMaxTimeUs);
|
topSensorRead = topSensorWrite || ultrasoundRead(topPIRorTriggerPin, topEchoPin, topMaxTimeUs);
|
||||||
#endif
|
|
||||||
|
|
||||||
// Values read, reset the flags for next API call
|
// Values read, reset the flags for next API call
|
||||||
topSensorWrite = false;
|
topSensorWrite = false;
|
||||||
@ -160,9 +162,9 @@ class Animated_Staircase : public Usermod {
|
|||||||
swipe = bottomSensorRead;
|
swipe = bottomSensorRead;
|
||||||
|
|
||||||
if (swipe) {
|
if (swipe) {
|
||||||
Serial.println("ON -> Swipe up.");
|
DEBUG_PRINTLN(F("ON -> Swipe up."));
|
||||||
} else {
|
} else {
|
||||||
Serial.println("ON -> Swipe down.");
|
DEBUG_PRINTLN(F("ON -> Swipe down."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onIndex == offIndex) {
|
if (onIndex == offIndex) {
|
||||||
@ -187,9 +189,9 @@ class Animated_Staircase : public Usermod {
|
|||||||
on = false;
|
on = false;
|
||||||
|
|
||||||
if (swipe) {
|
if (swipe) {
|
||||||
Serial.println("OFF -> Swipe up.");
|
DEBUG_PRINTLN(F("OFF -> Swipe up."));
|
||||||
} else {
|
} 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) {
|
if ((millis() - lastTime) > segment_delay_ms) {
|
||||||
lastTime = millis();
|
lastTime = millis();
|
||||||
|
|
||||||
byte oldOnIndex = onIndex;
|
// byte oldOnIndex = onIndex;
|
||||||
byte oldOffIndex = offIndex;
|
// byte oldOffIndex = offIndex;
|
||||||
|
|
||||||
if (on) {
|
if (on) {
|
||||||
// Turn on all segments
|
// 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) {
|
void writeSensorsToJson(JsonObject& root) {
|
||||||
JsonObject staircase = root["staircase"];
|
JsonObject staircase = root[F("staircase")];
|
||||||
if (staircase.isNull()) {
|
if (staircase.isNull()) {
|
||||||
staircase = root.createNestedObject("staircase");
|
staircase = root.createNestedObject(F("staircase"));
|
||||||
}
|
}
|
||||||
staircase["top-sensor"] = topSensorRead;
|
staircase[F("top-sensor")] = topSensorRead;
|
||||||
staircase["bottom-sensor"] = bottomSensorRead;
|
staircase[F("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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void readSensorsFromJson(JsonObject& root) {
|
void readSensorsFromJson(JsonObject& root) {
|
||||||
JsonObject staircase = root["staircase"];
|
JsonObject staircase = root[F("staircase")];
|
||||||
bottomSensorWrite = bottomSensorRead || (staircase["bottom-sensor"].as<bool>());
|
bottomSensorWrite = bottomSensorRead || (staircase[F("bottom-sensor")].as<bool>());
|
||||||
topSensorWrite = topSensorRead || (staircase["top-sensor"].as<bool>());
|
topSensorWrite = topSensorRead || (staircase[F("top-sensor")].as<bool>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void enable(bool enable) {
|
void enable(bool enable) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
Serial.println("Animated Staircase enabled.");
|
DEBUG_PRINTLN(F("Animated Staircase enabled."));
|
||||||
Serial.print("Delay between steps: ");
|
DEBUG_PRINT(F("Delay between steps: "));
|
||||||
Serial.print(segment_delay_ms, DEC);
|
DEBUG_PRINT(segment_delay_ms);
|
||||||
Serial.print(" milliseconds.\nStairs switch off after: ");
|
DEBUG_PRINT(F(" milliseconds.\nStairs switch off after: "));
|
||||||
Serial.print(on_time_ms / 1000, DEC);
|
DEBUG_PRINT(on_time_ms / 1000);
|
||||||
Serial.println(" seconds.");
|
DEBUG_PRINTLN(F(" seconds."));
|
||||||
|
|
||||||
#ifdef BOTTOM_PIR_PIN
|
if (!useUSSensorBottom)
|
||||||
pinMode(BOTTOM_PIR_PIN, INPUT);
|
pinMode(bottomPIRorTriggerPin, INPUT);
|
||||||
#else
|
else {
|
||||||
pinMode(BOTTOM_TRIGGER_PIN, OUTPUT);
|
pinMode(bottomPIRorTriggerPin, OUTPUT);
|
||||||
pinMode(BOTTOM_ECHO_PIN, INPUT);
|
pinMode(bottomEchoPin, INPUT);
|
||||||
#endif
|
}
|
||||||
|
|
||||||
#ifdef TOP_PIR_PIN
|
if (!useUSSensorTop)
|
||||||
pinMode(TOP_PIR_PIN, INPUT);
|
pinMode(topPIRorTriggerPin, INPUT);
|
||||||
#else
|
else {
|
||||||
pinMode(TOP_TRIGGER_PIN, OUTPUT);
|
pinMode(topPIRorTriggerPin, OUTPUT);
|
||||||
pinMode(TOP_ECHO_PIN, INPUT);
|
pinMode(topEchoPin, INPUT);
|
||||||
#endif
|
}
|
||||||
} else {
|
} else {
|
||||||
// Restore segment options
|
// Restore segment options
|
||||||
WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
|
// WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
|
||||||
WS2812FX::Segment* segments = strip.getSegments();
|
WS2812FX::Segment* segments = strip.getSegments();
|
||||||
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
||||||
if (!segments->isActive()) {
|
if (!segments->isActive()) {
|
||||||
@ -323,47 +268,53 @@ class Animated_Staircase : public Usermod {
|
|||||||
segments->setOption(SEG_OPTION_ON, 1, 1);
|
segments->setOption(SEG_OPTION_ON, 1, 1);
|
||||||
}
|
}
|
||||||
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||||
Serial.println("Animated Staircase disabled.");
|
DEBUG_PRINTLN(F("Animated Staircase disabled."));
|
||||||
}
|
}
|
||||||
enabled = enable;
|
enabled = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
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() {
|
void loop() {
|
||||||
// Write changed settings from to flash (see readFromJsonState())
|
if (!enabled) return;
|
||||||
if (saveState) {
|
|
||||||
serializeConfig();
|
|
||||||
saveState = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!enabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkSensors();
|
checkSensors();
|
||||||
autoPowerOff();
|
autoPowerOff();
|
||||||
updateSwipe();
|
updateSwipe();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t getId() { return USERMOD_ID_ANIMATED_STAIRCASE; }
|
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) {
|
void addToJsonState(JsonObject& root) {
|
||||||
writeSettingsToJson(root);
|
// writeSettingsToJson(root);
|
||||||
writeSensorsToJson(root);
|
// writeSensorsToJson(root);
|
||||||
Serial.println("Staircase config exposed in API.");
|
// DEBUG_PRINTLN(F("Staircase config exposed in API."));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -371,27 +322,103 @@ class Animated_Staircase : public Usermod {
|
|||||||
* See void addToJsonState(JsonObject& root)
|
* See void addToJsonState(JsonObject& root)
|
||||||
*/
|
*/
|
||||||
void readFromJsonState(JsonObject& root) {
|
void readFromJsonState(JsonObject& root) {
|
||||||
// The call to serializeConfig() must be done in the main loop,
|
if (!initDone) return; // prevent crash on boot applyPreset()
|
||||||
// so we set a flag to signal the main loop to save state.
|
JsonObject staircase = root[F("staircase")];
|
||||||
saveState = readSettingsFromJson(root);
|
if (!staircase.isNull()) {
|
||||||
readSensorsFromJson(root);
|
if (staircase[F("enabled")].is<bool>()) {
|
||||||
Serial.println("Staircase config read from API.");
|
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.
|
* Writes the configuration to internal flash memory.
|
||||||
*/
|
*/
|
||||||
void addToConfig(JsonObject& root) {
|
void addToConfig(JsonObject& root) {
|
||||||
writeSettingsToJson(root);
|
JsonObject staircase = root[F("staircase")];
|
||||||
Serial.println("Staircase config saved.");
|
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.
|
* Reads the configuration to internal flash memory before setup() is called.
|
||||||
*/
|
*/
|
||||||
void readFromConfig(JsonObject& root) {
|
void readFromConfig(JsonObject& root) {
|
||||||
readSettingsFromJson(root);
|
bool oldUseUSSensorTop = useUSSensorTop;
|
||||||
Serial.println("Staircase config loaded.");
|
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) {
|
if (enabled) {
|
||||||
JsonArray usermodEnabled =
|
JsonArray usermodEnabled = staircase.createNestedArray(F("Staircase enabled")); // name
|
||||||
staircase.createNestedArray("Staircase enabled"); // name
|
|
||||||
usermodEnabled.add("yes"); // value
|
usermodEnabled.add("yes"); // value
|
||||||
|
|
||||||
JsonArray segmentDelay =
|
JsonArray segmentDelay = staircase.createNestedArray(F("Delay between stairs")); // name
|
||||||
staircase.createNestedArray("Delay between stairs"); // name
|
|
||||||
segmentDelay.add(segment_delay_ms); // value
|
segmentDelay.add(segment_delay_ms); // value
|
||||||
segmentDelay.add(" milliseconds"); // unit
|
segmentDelay.add("ms"); // unit
|
||||||
|
|
||||||
JsonArray onTime =
|
JsonArray onTime = staircase.createNestedArray(F("Power-off stairs after")); // name
|
||||||
staircase.createNestedArray("Power-off stairs after"); // name
|
|
||||||
onTime.add(on_time_ms / 1000); // value
|
onTime.add(on_time_ms / 1000); // value
|
||||||
onTime.add(" seconds"); // unit
|
onTime.add("s"); // unit
|
||||||
} else {
|
} else {
|
||||||
JsonArray usermodEnabled =
|
JsonArray usermodEnabled = staircase.createNestedArray(F("Staircase enabled")); // name
|
||||||
staircase.createNestedArray("Staircase enabled"); // name
|
|
||||||
usermodEnabled.add("no"); // value
|
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;
|
bool initDone = false;
|
||||||
OneWire *oneWire;
|
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)
|
// GPIO pin used for sensor (with a default compile-time fallback)
|
||||||
int8_t temperaturePin = TEMPERATURE_PIN;
|
int8_t temperaturePin = TEMPERATURE_PIN;
|
||||||
// measurement unit (true==°C, false==°F)
|
// measurement unit (true==°C, false==°F)
|
||||||
bool degC = true;
|
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
|
// 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);
|
unsigned long lastMeasurement = UINT32_MAX - (USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL - USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT);
|
||||||
// last time requestTemperatures was called
|
// last time requestTemperatures was called
|
||||||
@ -59,51 +54,77 @@ class UsermodTemperature : public Usermod {
|
|||||||
// temperature if flashed to a board without a sensor attached
|
// temperature if flashed to a board without a sensor attached
|
||||||
bool disabled = false;
|
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() {
|
void requestTemperatures() {
|
||||||
// there is requestTemperaturesByAddress however it
|
readDallas();
|
||||||
// appears to do more work,
|
|
||||||
// TODO: measure exection time difference
|
|
||||||
sensor->requestTemperatures();
|
|
||||||
lastTemperaturesRequest = millis();
|
lastTemperaturesRequest = millis();
|
||||||
waitingForConversion = true;
|
waitingForConversion = true;
|
||||||
|
DEBUG_PRINTLN(F("Requested temperature."));
|
||||||
}
|
}
|
||||||
|
|
||||||
void getTemperature() {
|
void getTemperature() {
|
||||||
if (strip.isUpdating()) return;
|
temperature = readDallas()/10.0f;
|
||||||
|
if (!degC) temperature = temperature * 1.8f + 32;
|
||||||
if (degC) temperature = sensor->getTempC(sensorDeviceAddress);
|
|
||||||
else temperature = sensor->getTempF(sensorDeviceAddress);
|
|
||||||
|
|
||||||
lastMeasurement = millis();
|
lastMeasurement = millis();
|
||||||
waitingForConversion = false;
|
waitingForConversion = false;
|
||||||
getTemperatureComplete = true;
|
getTemperatureComplete = true;
|
||||||
|
DEBUG_PRINTF("Read temperature %2.1f.\n", temperature);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
|
//bool sensorFound = false;
|
||||||
|
|
||||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||||
if (!pinManager.allocatePin(temperaturePin,false)) {
|
if (!pinManager.allocatePin(temperaturePin,false)) {
|
||||||
temperaturePin = -1; // allocation failed
|
temperaturePin = -1; // allocation failed
|
||||||
DEBUG_PRINTLN(F("Temperature pin allocation failed."));
|
DEBUG_PRINTLN(F("Temperature pin allocation failed."));
|
||||||
} else {
|
} else {
|
||||||
|
//DeviceAddress deviceAddress;
|
||||||
oneWire = new OneWire(temperaturePin);
|
oneWire = new OneWire(temperaturePin);
|
||||||
sensor = new DallasTemperature(oneWire);
|
oneWire->reset();
|
||||||
if (sensor) sensor->begin();
|
/*
|
||||||
else
|
// find out if we have DS18xxx sensor attached
|
||||||
DEBUG_PRINTLN(F("Temperature sensor allocation failed."));
|
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) {
|
if (!disabled) {
|
||||||
DEBUG_PRINTLN(F("Dallas Temperature found"));
|
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 {
|
} else {
|
||||||
DEBUG_PRINTLN(F("Dallas Temperature not found"));
|
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
|
// check to see if we are due for taking a measurement
|
||||||
// lastMeasurement will not be updated until the conversion
|
// lastMeasurement will not be updated until the conversion
|
||||||
// is complete the the reading is finished
|
// 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
|
// we are due for a measurement, if we are not already waiting
|
||||||
// for a conversion to complete, then make a new request for temps
|
// 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?
|
// 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();
|
getTemperature();
|
||||||
|
|
||||||
if (WLED_MQTT_CONNECTED) {
|
if (WLED_MQTT_CONNECTED) {
|
||||||
@ -196,35 +217,6 @@ class UsermodTemperature : public Usermod {
|
|||||||
*/
|
*/
|
||||||
void readFromJsonState(JsonObject &root) {
|
void readFromJsonState(JsonObject &root) {
|
||||||
if (!initDone) return; // prevent crash on boot applyPreset()
|
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) {
|
void addToConfig(JsonObject &root) {
|
||||||
// we add JSON object: {"Temperature": {"pin": 0, "degC": true}}
|
// we add JSON object: {"Temperature": {"pin": 0, "degC": true}}
|
||||||
JsonObject top = root.createNestedObject(FPSTR(_um_Temperature)); // usermodname
|
JsonObject top = root.createNestedObject(FPSTR(_um_Temperature)); // usermodname
|
||||||
|
top[F("enabled")] = !disabled;
|
||||||
top["pin"] = temperaturePin; // usermodparam
|
top["pin"] = temperaturePin; // usermodparam
|
||||||
top["degC"] = degC; // 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) {
|
void readFromConfig(JsonObject &root) {
|
||||||
// we look for JSON object: {"Temperature": {"pin": 0, "degC": true}}
|
// we look for JSON object: {"Temperature": {"pin": 0, "degC": true}}
|
||||||
JsonObject top = root[FPSTR(_um_Temperature)];
|
JsonObject top = root[FPSTR(_um_Temperature)];
|
||||||
|
int8_t newTemperaturePin = temperaturePin;
|
||||||
if (!top.isNull() && top["pin"] != nullptr) {
|
if (!top.isNull() && top["pin"] != nullptr) {
|
||||||
temperaturePin = (int)top["pin"];
|
if (top[F("enabled")].is<bool>()) {
|
||||||
degC = top["degC"] != nullptr ? top["degC"] : true;
|
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 {
|
} else {
|
||||||
DEBUG_PRINTLN(F("No config found. (Using defaults.)"));
|
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()
|
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).
|
* 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
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
void readFromJsonState(JsonObject& root) {
|
//void readFromJsonState(JsonObject& root) {
|
||||||
if (!initDone) return; // prevent crash on boot applyPreset()
|
// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
|
* 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(_autoSaveAfterSec)] = autoSaveAfterSec; // usermodparam
|
||||||
top[FPSTR(_autoSavePreset)] = autoSavePreset; // usermodparam
|
top[FPSTR(_autoSavePreset)] = autoSavePreset; // usermodparam
|
||||||
top[FPSTR(_autoSaveApplyOnBoot)] = applyAutoSaveOnBoot;
|
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}}
|
// we look for JSON object: {"Autosave": {"autoSaveAfterSec": 10, "autoSavePreset": 99}}
|
||||||
JsonObject top = root[FPSTR(_um_AutoSave)];
|
JsonObject top = root[FPSTR(_um_AutoSave)];
|
||||||
if (!top.isNull() && top[FPSTR(_autoSaveAfterSec)] != nullptr) {
|
if (!top.isNull() && top[FPSTR(_autoSaveAfterSec)] != nullptr) {
|
||||||
autoSaveAfterSec = (int) top[FPSTR(_autoSaveAfterSec)];
|
autoSaveAfterSec = top[FPSTR(_autoSaveAfterSec)].as<int>();
|
||||||
autoSavePreset = (int) top[FPSTR(_autoSavePreset)];
|
autoSavePreset = top[FPSTR(_autoSavePreset)].as<int>();
|
||||||
applyAutoSaveOnBoot = (bool)top[FPSTR(_autoSaveApplyOnBoot)];
|
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 {
|
} else {
|
||||||
DEBUG_PRINTLN(F("No config found. (Using defaults.)"));
|
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).
|
* 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
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
void readFromJsonState(JsonObject& root) {
|
//void readFromJsonState(JsonObject& root) {
|
||||||
if (!initDone) return; // prevent crash on boot applyPreset()
|
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
|
* 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_screenTimeOut)] = screenTimeout/1000;
|
||||||
top[FPSTR(_4LD_sleepMode)] = (bool) sleepMode;
|
top[FPSTR(_4LD_sleepMode)] = (bool) sleepMode;
|
||||||
top[FPSTR(_4LD_clockMode)] = (bool) clockMode;
|
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 :)
|
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
|
||||||
*/
|
*/
|
||||||
void readFromConfig(JsonObject& root) {
|
void readFromConfig(JsonObject& root) {
|
||||||
|
bool needsRedraw = false;
|
||||||
|
DisplayType newType = type;
|
||||||
|
int8_t newScl = sclPin;
|
||||||
|
int8_t newSda = sdaPin;
|
||||||
|
|
||||||
JsonObject top = root[FPSTR(_um_4LineDisplay)];
|
JsonObject top = root[FPSTR(_um_4LineDisplay)];
|
||||||
if (!top.isNull() && top["pin"] != nullptr) {
|
if (!top.isNull() && top["pin"] != nullptr) {
|
||||||
sclPin = top["pin"][0];
|
newScl = top["pin"][0];
|
||||||
sdaPin = top["pin"][1];
|
newSda = top["pin"][1];
|
||||||
type = top["type"];
|
newType = top["type"];
|
||||||
lineHeight = type==SH1106 ? 2 : 1;
|
lineHeight = type==SH1106 ? 2 : 1;
|
||||||
flip = top[FPSTR(_4LD_flip)];
|
if (top[FPSTR(_4LD_flip)].is<bool>()) {
|
||||||
contrast = top[FPSTR(_4LD_contrast)];
|
flip = top[FPSTR(_4LD_flip)].as<bool>();
|
||||||
refreshRate = int(top[FPSTR(_4LD_refreshRate)])*1000;
|
} else {
|
||||||
screenTimeout = int(top[FPSTR(_4LD_screenTimeOut)])*1000;
|
String str = top[FPSTR(_4LD_flip)]; // checkbox -> off or on
|
||||||
sleepMode = top[FPSTR(_4LD_sleepMode)];
|
flip = (bool)(str!="off"); // off is guaranteed to be present
|
||||||
clockMode = top[FPSTR(_4LD_clockMode)];
|
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 {
|
} else {
|
||||||
DEBUG_PRINTLN(F("No config found. (Using defaults.)"));
|
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 name = request->argName(i);
|
||||||
String value = request->arg(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("[]")) {
|
if (name.endsWith("[]")) {
|
||||||
name.replace("[]","");
|
name.replace("[]","");
|
||||||
if (!um[name].is<JsonArray>()) {
|
if (!mod[name].is<JsonArray>()) {
|
||||||
JsonArray ar = um.createNestedArray(name);
|
JsonArray ar = mod.createNestedArray(name);
|
||||||
ar.add(value);
|
ar.add(value);
|
||||||
j=0;
|
j=0;
|
||||||
} else {
|
} else {
|
||||||
um[name].add(value);
|
mod[name].add(value);
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
DEBUG_PRINT(name);
|
DEBUG_PRINT(name);
|
||||||
@ -435,14 +448,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
DEBUG_PRINT("] = ");
|
DEBUG_PRINT("] = ");
|
||||||
DEBUG_PRINTLN(value);
|
DEBUG_PRINTLN(value);
|
||||||
} else {
|
} else {
|
||||||
um.remove(name); // checkboxes get two fields (first is always "off", existence of second depends on checkmark and may be "on")
|
mod.remove(name); // checkboxes get two fields (first is always "off", existence of second depends on checkmark and may be "on")
|
||||||
um[name] = value;
|
mod[name] = value;
|
||||||
DEBUG_PRINT(name);
|
DEBUG_PRINT(name);
|
||||||
DEBUG_PRINT(" = ");
|
DEBUG_PRINT(" = ");
|
||||||
DEBUG_PRINTLN(value);
|
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)
|
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"
|
#include "../usermods/VL53L0X_gestures/usermod_vl53l0x_gestures.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USERMOD_ANIMATED_STAIRCASE
|
||||||
|
#include "../usermods/Animated_Staircase/Animated_Staircase.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
void registerUsermods()
|
void registerUsermods()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -96,4 +100,8 @@ void registerUsermods()
|
|||||||
#ifdef USERMOD_VL53L0X_GESTURES
|
#ifdef USERMOD_VL53L0X_GESTURES
|
||||||
usermods.add(new UsermodVL53L0XGestures());
|
usermods.add(new UsermodVL53L0XGestures());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USERMOD_ANIMATED_STAIRCASE
|
||||||
|
usermods.add(new Animated_Staircase());
|
||||||
|
#endif
|
||||||
}
|
}
|
@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// version code in format yymmddb (b = daily build)
|
// 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
|
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||||
//#define WLED_USE_MY_CONFIG
|
//#define WLED_USE_MY_CONFIG
|
||||||
|
Loading…
x
Reference in New Issue
Block a user