Enhanced Animated Staircase usermod.
This commit is contained in:
parent
f6a5bc9b40
commit
3fde7365f9
@ -10,465 +10,508 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
|
||||||
#define USERMOD_ID_ANIMATED_STAIRCASE 1011
|
|
||||||
|
|
||||||
class Animated_Staircase : public Usermod {
|
class Animated_Staircase : public Usermod {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/* configuration (available in API and stored in flash) */
|
/* configuration (available in API and stored in flash) */
|
||||||
bool enabled = false; // Enable this usermod
|
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 = 30000; // The time for the light to stay on
|
||||||
int8_t topPIRorTriggerPin = -1; // disabled
|
int8_t topPIRorTriggerPin = -1; // disabled
|
||||||
int8_t bottomPIRorTriggerPin = -1; // disabled
|
int8_t bottomPIRorTriggerPin = -1; // disabled
|
||||||
int8_t topEchoPin = -1; // disabled
|
int8_t topEchoPin = -1; // disabled
|
||||||
int8_t bottomEchoPin = -1; // disabled
|
int8_t bottomEchoPin = -1; // disabled
|
||||||
bool useUSSensorTop = false; // using PIR or UltraSound sensor?
|
bool useUSSensorTop = false; // using PIR or UltraSound sensor?
|
||||||
bool useUSSensorBottom = false; // using PIR or UltraSound sensor?
|
bool useUSSensorBottom = false; // using PIR or UltraSound sensor?
|
||||||
unsigned int topMaxTimeUs = 1749; // default echo timout, top
|
unsigned int topMaxDist = 50; // default maximum measured distance in cm, top
|
||||||
unsigned int bottomMaxTimeUs = 1749; // default echo timout, bottom
|
unsigned int bottomMaxDist = 50; // default maximum measured distance in cm, bottom
|
||||||
|
|
||||||
/* runtime variables */
|
/* runtime variables */
|
||||||
bool initDone = false;
|
bool initDone = false;
|
||||||
|
|
||||||
// Time between checking of the sensors
|
// Time between checking of the sensors
|
||||||
const unsigned int scanDelay = 50;
|
const unsigned int scanDelay = 100;
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
||||||
// Swipe direction for current transition
|
// Swipe direction for current transition
|
||||||
#define SWIPE_UP true
|
#define SWIPE_UP true
|
||||||
#define SWIPE_DOWN false
|
#define SWIPE_DOWN false
|
||||||
bool swipe = SWIPE_UP;
|
bool swipe = SWIPE_UP;
|
||||||
|
|
||||||
// Indicates which Sensor was seen last (to determine
|
// Indicates which Sensor was seen last (to determine
|
||||||
// the direction when swiping off)
|
// the direction when swiping off)
|
||||||
#define LOWER false
|
#define LOWER false
|
||||||
#define UPPER true
|
#define UPPER true
|
||||||
bool lastSensor = LOWER;
|
bool lastSensor = LOWER;
|
||||||
|
|
||||||
// Time of the last transition action
|
// Time of the last transition action
|
||||||
unsigned long lastTime = 0;
|
unsigned long lastTime = 0;
|
||||||
|
|
||||||
// Time of the last sensor check
|
// Time of the last sensor check
|
||||||
unsigned long lastScanTime = 0;
|
unsigned long lastScanTime = 0;
|
||||||
|
|
||||||
// Last time the lights were switched on or off
|
// Last time the lights were switched on or off
|
||||||
unsigned long lastSwitchTime = 0;
|
unsigned long lastSwitchTime = 0;
|
||||||
|
|
||||||
// segment id between onIndex and offIndex are on.
|
// segment id between onIndex and offIndex are on.
|
||||||
// controll the swipe by setting/moving these indices around.
|
// controll the swipe by setting/moving these indices around.
|
||||||
// onIndex must be less than or equal to offIndex
|
// onIndex must be less than or equal to offIndex
|
||||||
byte onIndex = 0;
|
byte onIndex = 0;
|
||||||
byte offIndex = 0;
|
byte offIndex = 0;
|
||||||
|
|
||||||
// The maximum number of configured segments.
|
// The maximum number of configured segments.
|
||||||
// Dynamically updated based on user configuration.
|
// Dynamically updated based on user configuration.
|
||||||
byte maxSegmentId = 1;
|
byte maxSegmentId = 1;
|
||||||
byte mainSegmentId = 0;
|
byte mainSegmentId = 0;
|
||||||
|
|
||||||
// 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
|
||||||
bool topSensorRead = false;
|
bool topSensorRead = false;
|
||||||
bool topSensorWrite = false;
|
bool topSensorWrite = false;
|
||||||
bool bottomSensorRead = false;
|
bool bottomSensorRead = false;
|
||||||
bool bottomSensorWrite = false;
|
bool bottomSensorWrite = false;
|
||||||
|
bool topSensorState = false;
|
||||||
|
bool bottomSensorState = false;
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
static const char _name[];
|
static const char _name[];
|
||||||
static const char _enabled[];
|
static const char _enabled[];
|
||||||
static const char _segmentDelay[];
|
static const char _segmentDelay[];
|
||||||
static const char _onTime[];
|
static const char _onTime[];
|
||||||
static const char _useTopUltrasoundSensor[];
|
static const char _useTopUltrasoundSensor[];
|
||||||
static const char _topPIRorTrigger_pin[];
|
static const char _topPIRorTrigger_pin[];
|
||||||
static const char _topEcho_pin[];
|
static const char _topEcho_pin[];
|
||||||
static const char _useBottomUltrasoundSensor[];
|
static const char _useBottomUltrasoundSensor[];
|
||||||
static const char _bottomPIRorTrigger_pin[];
|
static const char _bottomPIRorTrigger_pin[];
|
||||||
static const char _bottomEcho_pin[];
|
static const char _bottomEcho_pin[];
|
||||||
static const char _topEchoTime[];
|
static const char _topEchoCm[];
|
||||||
static const char _bottomEchoTime[];
|
static const char _bottomEchoCm[];
|
||||||
static const char _[];
|
|
||||||
|
|
||||||
void updateSegments() {
|
void publishMqtt(bool bottom, const char* state)
|
||||||
// mainSegmentId = strip.getMainSegmentId();
|
{
|
||||||
// WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
|
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||||
WS2812FX::Segment* segments = strip.getSegments();
|
if (WLED_MQTT_CONNECTED){
|
||||||
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
char subuf[64];
|
||||||
if (!segments->isActive()) {
|
sprintf_P(subuf, PSTR("%s/motion/%d"), mqttDeviceTopic, (int)bottom);
|
||||||
maxSegmentId = i - 1;
|
mqtt->publish(subuf, 0, false, state);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i >= onIndex && i < offIndex) {
|
|
||||||
segments->setOption(SEG_OPTION_ON, 1, 1);
|
|
||||||
|
|
||||||
// We may need to copy mode and colors from segment 0 to make sure
|
|
||||||
// changes are propagated even when the config is changed during a wipe
|
|
||||||
// segments->mode = mainsegment.mode;
|
|
||||||
// segments->colors[0] = mainsegment.colors[0];
|
|
||||||
} else {
|
|
||||||
segments->setOption(SEG_OPTION_ON, 0, 1);
|
|
||||||
}
|
|
||||||
// Always mark segments as "transitional", we are animating the staircase
|
|
||||||
segments->setOption(SEG_OPTION_TRANSITIONAL, 1, 1);
|
|
||||||
}
|
|
||||||
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Detects if an object is within ultrasound range.
|
|
||||||
* signalPin: The pin where the pulse is sent
|
|
||||||
* echoPin: The pin where the echo is received
|
|
||||||
* maxTimeUs: Detection timeout in microseconds. If an echo is
|
|
||||||
* received within this time, an object is detected
|
|
||||||
* and the function will return true.
|
|
||||||
*
|
|
||||||
* The speed of sound is 343 meters per second at 20 degress Celcius.
|
|
||||||
* Since the sound has to travel back and forth, the detection
|
|
||||||
* distance for the sensor in cm is (0.0343 * maxTimeUs) / 2.
|
|
||||||
*
|
|
||||||
* For practical reasons, here are some useful distances:
|
|
||||||
*
|
|
||||||
* Distance = maxtime
|
|
||||||
* 5 cm = 292 uS
|
|
||||||
* 10 cm = 583 uS
|
|
||||||
* 20 cm = 1166 uS
|
|
||||||
* 30 cm = 1749 uS
|
|
||||||
* 50 cm = 2915 uS
|
|
||||||
* 100 cm = 5831 uS
|
|
||||||
*/
|
|
||||||
bool ultrasoundRead(uint8_t signalPin,
|
|
||||||
uint8_t echoPin,
|
|
||||||
unsigned int maxTimeUs) {
|
|
||||||
digitalWrite(signalPin, HIGH);
|
|
||||||
delayMicroseconds(10);
|
|
||||||
digitalWrite(signalPin, LOW);
|
|
||||||
return pulseIn(echoPin, HIGH, maxTimeUs) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkSensors() {
|
|
||||||
if ((millis() - lastScanTime) > scanDelay) {
|
|
||||||
lastScanTime = millis();
|
|
||||||
|
|
||||||
if (!useUSSensorBottom)
|
|
||||||
bottomSensorRead = bottomSensorWrite || (digitalRead(bottomPIRorTriggerPin) == HIGH);
|
|
||||||
else
|
|
||||||
bottomSensorRead = bottomSensorWrite || ultrasoundRead(bottomPIRorTriggerPin, bottomEchoPin, bottomMaxTimeUs);
|
|
||||||
|
|
||||||
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;
|
|
||||||
bottomSensorWrite = false;
|
|
||||||
|
|
||||||
if (topSensorRead != bottomSensorRead) {
|
|
||||||
lastSwitchTime = millis();
|
|
||||||
|
|
||||||
if (on) {
|
|
||||||
lastSensor = topSensorRead;
|
|
||||||
} else {
|
|
||||||
// If the bottom sensor triggered, we need to swipe up, ON
|
|
||||||
swipe = bottomSensorRead;
|
|
||||||
|
|
||||||
if (swipe) {
|
|
||||||
DEBUG_PRINTLN(F("ON -> Swipe up."));
|
|
||||||
} else {
|
|
||||||
DEBUG_PRINTLN(F("ON -> Swipe down."));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (onIndex == offIndex) {
|
|
||||||
// Position the indices for a correct on-swipe
|
|
||||||
if (swipe == SWIPE_UP) {
|
|
||||||
onIndex = mainSegmentId;
|
|
||||||
} else {
|
|
||||||
onIndex = maxSegmentId+1;
|
|
||||||
}
|
|
||||||
offIndex = onIndex;
|
|
||||||
}
|
|
||||||
on = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void autoPowerOff() {
|
void updateSegments() {
|
||||||
// TODO: add logic to wait until PIR sensor deactivates
|
mainSegmentId = strip.getMainSegmentId();
|
||||||
if (on && ((millis() - lastSwitchTime) > on_time_ms)) {
|
|
||||||
// Swipe OFF in the direction of the last sensor detection
|
|
||||||
swipe = lastSensor;
|
|
||||||
on = false;
|
|
||||||
|
|
||||||
if (swipe) {
|
|
||||||
DEBUG_PRINTLN(F("OFF -> Swipe up."));
|
|
||||||
} else {
|
|
||||||
DEBUG_PRINTLN(F("OFF -> Swipe down."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateSwipe() {
|
|
||||||
if ((millis() - lastTime) > segment_delay_ms) {
|
|
||||||
lastTime = millis();
|
|
||||||
|
|
||||||
// byte oldOnIndex = onIndex;
|
|
||||||
// byte oldOffIndex = offIndex;
|
|
||||||
|
|
||||||
if (on) {
|
|
||||||
// Turn on all segments
|
|
||||||
onIndex = MAX(mainSegmentId, onIndex - 1);
|
|
||||||
offIndex = MIN(maxSegmentId + 1, offIndex + 1);
|
|
||||||
} else {
|
|
||||||
if (swipe == SWIPE_UP) {
|
|
||||||
onIndex = MIN(offIndex, onIndex + 1);
|
|
||||||
} else {
|
|
||||||
offIndex = MAX(onIndex, offIndex - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateSegments();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// send sesnor values to JSON API
|
|
||||||
void writeSensorsToJson(JsonObject& staircase) {
|
|
||||||
staircase[F("top-sensor")] = topSensorRead;
|
|
||||||
staircase[F("bottom-sensor")] = bottomSensorRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
// allow overrides from JSON API
|
|
||||||
void readSensorsFromJson(JsonObject& staircase) {
|
|
||||||
bottomSensorWrite = bottomSensorRead || (staircase[F("bottom-sensor")].as<bool>());
|
|
||||||
topSensorWrite = topSensorRead || (staircase[F("top-sensor")].as<bool>());
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable(bool enable) {
|
|
||||||
if (enable) {
|
|
||||||
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."));
|
|
||||||
|
|
||||||
// TODO: attach interrupts
|
|
||||||
if (!useUSSensorBottom)
|
|
||||||
pinMode(bottomPIRorTriggerPin, INPUT);
|
|
||||||
else {
|
|
||||||
pinMode(bottomPIRorTriggerPin, OUTPUT);
|
|
||||||
pinMode(bottomEchoPin, INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!useUSSensorTop)
|
|
||||||
pinMode(topPIRorTriggerPin, INPUT);
|
|
||||||
else {
|
|
||||||
pinMode(topPIRorTriggerPin, OUTPUT);
|
|
||||||
pinMode(topEchoPin, INPUT);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Restore segment options
|
|
||||||
// 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()) {
|
||||||
maxSegmentId = i - 1;
|
maxSegmentId = i - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
segments->setOption(SEG_OPTION_ON, 1, 1);
|
|
||||||
|
if (i >= onIndex && i < offIndex) {
|
||||||
|
segments->setOption(SEG_OPTION_ON, 1, 1);
|
||||||
|
|
||||||
|
// We may need to copy mode and colors from segment 0 to make sure
|
||||||
|
// changes are propagated even when the config is changed during a wipe
|
||||||
|
// segments->mode = mainsegment.mode;
|
||||||
|
// segments->colors[0] = mainsegment.colors[0];
|
||||||
|
} else {
|
||||||
|
segments->setOption(SEG_OPTION_ON, 0, 1);
|
||||||
|
}
|
||||||
|
// Always mark segments as "transitional", we are animating the staircase
|
||||||
|
segments->setOption(SEG_OPTION_TRANSITIONAL, 1, 1);
|
||||||
}
|
}
|
||||||
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||||
DEBUG_PRINTLN(F("Animated Staircase disabled."));
|
|
||||||
}
|
}
|
||||||
enabled = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
/*
|
||||||
void setup() {
|
* Detects if an object is within ultrasound range.
|
||||||
// allocate pins
|
* signalPin: The pin where the pulse is sent
|
||||||
if (topPIRorTriggerPin >= 0) {
|
* echoPin: The pin where the echo is received
|
||||||
if (!pinManager.allocatePin(topPIRorTriggerPin,useUSSensorTop))
|
* maxTimeUs: Detection timeout in microseconds. If an echo is
|
||||||
topPIRorTriggerPin = -1;
|
* received within this time, an object is detected
|
||||||
|
* and the function will return true.
|
||||||
|
*
|
||||||
|
* The speed of sound is 343 meters per second at 20 degress Celcius.
|
||||||
|
* Since the sound has to travel back and forth, the detection
|
||||||
|
* distance for the sensor in cm is (0.0343 * maxTimeUs) / 2.
|
||||||
|
*
|
||||||
|
* For practical reasons, here are some useful distances:
|
||||||
|
*
|
||||||
|
* Distance = maxtime
|
||||||
|
* 5 cm = 292 uS
|
||||||
|
* 10 cm = 583 uS
|
||||||
|
* 20 cm = 1166 uS
|
||||||
|
* 30 cm = 1749 uS
|
||||||
|
* 50 cm = 2915 uS
|
||||||
|
* 100 cm = 5831 uS
|
||||||
|
*/
|
||||||
|
bool ultrasoundRead(int8_t signalPin, int8_t echoPin, unsigned int maxTimeUs) {
|
||||||
|
if (signalPin<0 || echoPin<0) return false;
|
||||||
|
digitalWrite(signalPin, LOW);
|
||||||
|
delayMicroseconds(2);
|
||||||
|
digitalWrite(signalPin, HIGH);
|
||||||
|
delayMicroseconds(10);
|
||||||
|
digitalWrite(signalPin, LOW);
|
||||||
|
return pulseIn(echoPin, HIGH, maxTimeUs) > 0;
|
||||||
}
|
}
|
||||||
if (topEchoPin >= 0) {
|
|
||||||
if (!pinManager.allocatePin(topEchoPin,false))
|
bool checkSensors() {
|
||||||
topEchoPin = -1;
|
bool sensorChanged = false;
|
||||||
|
|
||||||
|
if ((millis() - lastScanTime) > scanDelay) {
|
||||||
|
lastScanTime = millis();
|
||||||
|
|
||||||
|
bottomSensorRead = bottomSensorWrite ||
|
||||||
|
(!useUSSensorBottom ?
|
||||||
|
(bottomPIRorTriggerPin<0 ? false : digitalRead(bottomPIRorTriggerPin)) :
|
||||||
|
ultrasoundRead(bottomPIRorTriggerPin, bottomEchoPin, bottomMaxDist*59) // cm to us
|
||||||
|
);
|
||||||
|
topSensorRead = topSensorWrite ||
|
||||||
|
(!useUSSensorTop ?
|
||||||
|
(topPIRorTriggerPin<0 ? false : digitalRead(topPIRorTriggerPin)) :
|
||||||
|
ultrasoundRead(topPIRorTriggerPin, topEchoPin, topMaxDist*59) // cm to us
|
||||||
|
);
|
||||||
|
|
||||||
|
if (bottomSensorRead != bottomSensorState) {
|
||||||
|
bottomSensorState = bottomSensorRead; // change previous state
|
||||||
|
sensorChanged = true;
|
||||||
|
publishMqtt(true, bottomSensorState ? "on" : "off");
|
||||||
|
DEBUG_PRINTLN(F("Bottom sensor changed."));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (topSensorRead != topSensorState) {
|
||||||
|
topSensorState = topSensorRead; // change previous state
|
||||||
|
sensorChanged = true;
|
||||||
|
publishMqtt(false, topSensorState ? "on" : "off");
|
||||||
|
DEBUG_PRINTLN(F("Top sensor changed."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values read, reset the flags for next API call
|
||||||
|
topSensorWrite = false;
|
||||||
|
bottomSensorWrite = false;
|
||||||
|
|
||||||
|
if (topSensorRead != bottomSensorRead) {
|
||||||
|
lastSwitchTime = millis();
|
||||||
|
|
||||||
|
if (on) {
|
||||||
|
lastSensor = topSensorRead;
|
||||||
|
} else {
|
||||||
|
// If the bottom sensor triggered, we need to swipe up, ON
|
||||||
|
swipe = bottomSensorRead;
|
||||||
|
|
||||||
|
DEBUG_PRINT(F("ON -> Swipe "));
|
||||||
|
DEBUG_PRINTLN(swipe ? F("up.") : F("down."));
|
||||||
|
|
||||||
|
if (onIndex == offIndex) {
|
||||||
|
// Position the indices for a correct on-swipe
|
||||||
|
if (swipe == SWIPE_UP) {
|
||||||
|
onIndex = mainSegmentId;
|
||||||
|
} else {
|
||||||
|
onIndex = maxSegmentId+1;
|
||||||
|
}
|
||||||
|
offIndex = onIndex;
|
||||||
|
}
|
||||||
|
on = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sensorChanged;
|
||||||
}
|
}
|
||||||
if (bottomPIRorTriggerPin >= 0) {
|
|
||||||
if (!pinManager.allocatePin(bottomPIRorTriggerPin,useUSSensorBottom))
|
void autoPowerOff() {
|
||||||
bottomPIRorTriggerPin = -1;
|
if (on && ((millis() - lastSwitchTime) > on_time_ms)) {
|
||||||
|
// if sensors are still on, do nothing
|
||||||
|
if (bottomSensorState || topSensorState) return;
|
||||||
|
|
||||||
|
// Swipe OFF in the direction of the last sensor detection
|
||||||
|
swipe = lastSensor;
|
||||||
|
on = false;
|
||||||
|
|
||||||
|
DEBUG_PRINT(F("OFF -> Swipe "));
|
||||||
|
DEBUG_PRINTLN(swipe ? F("up.") : F("down."));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (bottomEchoPin >= 0) {
|
|
||||||
if (!pinManager.allocatePin(bottomPIRorTriggerPin,false))
|
void updateSwipe() {
|
||||||
bottomEchoPin = -1;
|
if ((millis() - lastTime) > segment_delay_ms) {
|
||||||
|
lastTime = millis();
|
||||||
|
|
||||||
|
if (on) {
|
||||||
|
// Turn on all segments
|
||||||
|
onIndex = MAX(mainSegmentId, onIndex - 1);
|
||||||
|
offIndex = MIN(maxSegmentId + 1, offIndex + 1);
|
||||||
|
} else {
|
||||||
|
if (swipe == SWIPE_UP) {
|
||||||
|
onIndex = MIN(offIndex, onIndex + 1);
|
||||||
|
} else {
|
||||||
|
offIndex = MAX(onIndex, offIndex - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateSegments();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// TODO: attach interrupts in enable()
|
|
||||||
|
|
||||||
// validate pins
|
// send sesnor values to JSON API
|
||||||
if ( topPIRorTriggerPin < 0 || bottomPIRorTriggerPin < 0 ||
|
void writeSensorsToJson(JsonObject& staircase) {
|
||||||
(useUSSensorTop && topEchoPin < 0) || (useUSSensorBottom && bottomEchoPin < 0) )
|
staircase[F("top-sensor")] = topSensorRead;
|
||||||
enabled = false;
|
staircase[F("bottom-sensor")] = bottomSensorRead;
|
||||||
|
|
||||||
enable(enabled);
|
|
||||||
initDone = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
if (!enabled) return;
|
|
||||||
checkSensors();
|
|
||||||
autoPowerOff();
|
|
||||||
updateSwipe();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t getId() { return USERMOD_ID_ANIMATED_STAIRCASE; }
|
|
||||||
|
|
||||||
void addToJsonState(JsonObject& root) {
|
|
||||||
JsonObject staircase = root[FPSTR(_name)];
|
|
||||||
if (staircase.isNull()) {
|
|
||||||
staircase = root.createNestedObject(FPSTR(_name));
|
|
||||||
}
|
}
|
||||||
writeSensorsToJson(staircase);
|
|
||||||
DEBUG_PRINTLN(F("Staircase sensor state exposed in API."));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
// allow overrides from JSON API
|
||||||
* Reads configuration settings from the json API.
|
void readSensorsFromJson(JsonObject& staircase) {
|
||||||
* See void addToJsonState(JsonObject& root)
|
bottomSensorWrite = bottomSensorState || (staircase[F("bottom-sensor")].as<bool>());
|
||||||
*/
|
topSensorWrite = topSensorState || (staircase[F("top-sensor")].as<bool>());
|
||||||
void readFromJsonState(JsonObject& root) {
|
}
|
||||||
if (!initDone) return; // prevent crash on boot applyPreset()
|
|
||||||
JsonObject staircase = root[FPSTR(_name)];
|
void enable(bool enable) {
|
||||||
if (!staircase.isNull()) {
|
if (enable) {
|
||||||
if (staircase[FPSTR(_enabled)].is<bool>()) {
|
DEBUG_PRINTLN(F("Animated Staircase enabled."));
|
||||||
enabled = staircase[FPSTR(_enabled)].as<bool>();
|
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."));
|
||||||
|
|
||||||
|
if (!useUSSensorBottom)
|
||||||
|
pinMode(bottomPIRorTriggerPin, INPUT_PULLUP);
|
||||||
|
else {
|
||||||
|
pinMode(bottomPIRorTriggerPin, OUTPUT);
|
||||||
|
pinMode(bottomEchoPin, INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!useUSSensorTop)
|
||||||
|
pinMode(topPIRorTriggerPin, INPUT_PULLUP);
|
||||||
|
else {
|
||||||
|
pinMode(topPIRorTriggerPin, OUTPUT);
|
||||||
|
pinMode(topEchoPin, INPUT);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
String str = staircase[FPSTR(_enabled)]; // checkbox -> off or on
|
// Restore segment options
|
||||||
enabled = (bool)(str!="off"); // off is guaranteed to be present
|
WS2812FX::Segment* segments = strip.getSegments();
|
||||||
|
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
||||||
|
if (!segments->isActive()) {
|
||||||
|
maxSegmentId = i - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
segments->setOption(SEG_OPTION_ON, 1, 1);
|
||||||
|
}
|
||||||
|
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||||
|
DEBUG_PRINTLN(F("Animated Staircase disabled."));
|
||||||
}
|
}
|
||||||
readSensorsFromJson(root);
|
enabled = enable;
|
||||||
DEBUG_PRINTLN(F("Staircase sensor state read from API."));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
public:
|
||||||
* Writes the configuration to internal flash memory.
|
void setup() {
|
||||||
*/
|
// allocate pins
|
||||||
void addToConfig(JsonObject& root) {
|
if (topPIRorTriggerPin >= 0) {
|
||||||
JsonObject staircase = root[FPSTR(_name)];
|
if (!pinManager.allocatePin(topPIRorTriggerPin,useUSSensorTop))
|
||||||
if (staircase.isNull()) {
|
topPIRorTriggerPin = -1;
|
||||||
staircase = root.createNestedObject(FPSTR(_name));
|
}
|
||||||
|
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(bottomEchoPin,false))
|
||||||
|
bottomEchoPin = -1;
|
||||||
|
}
|
||||||
|
enable(enabled);
|
||||||
|
initDone = true;
|
||||||
}
|
}
|
||||||
staircase[FPSTR(_enabled)] = enabled;
|
|
||||||
staircase[FPSTR(_segmentDelay)] = segment_delay_ms;
|
|
||||||
staircase[FPSTR(_onTime)] = on_time_ms / 1000;
|
|
||||||
staircase[FPSTR(_useTopUltrasoundSensor)] = useUSSensorTop;
|
|
||||||
staircase[FPSTR(_topPIRorTrigger_pin)] = topPIRorTriggerPin;
|
|
||||||
staircase[FPSTR(_topEcho_pin)] = useUSSensorTop ? topEchoPin : -1;
|
|
||||||
staircase[FPSTR(_useBottomUltrasoundSensor)] = useUSSensorBottom;
|
|
||||||
staircase[FPSTR(_bottomPIRorTrigger_pin)] = bottomPIRorTriggerPin;
|
|
||||||
staircase[FPSTR(_bottomEcho_pin)] = useUSSensorBottom ? bottomEchoPin : -1;
|
|
||||||
staircase[FPSTR(_topEchoTime)] = topMaxTimeUs;
|
|
||||||
staircase[FPSTR(_bottomEchoTime)] = bottomMaxTimeUs;
|
|
||||||
DEBUG_PRINTLN(F("Staircase config saved."));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
void loop() {
|
||||||
* Reads the configuration to internal flash memory before setup() is called.
|
if (!enabled || strip.isUpdating()) return;
|
||||||
*/
|
checkSensors();
|
||||||
void readFromConfig(JsonObject& root) {
|
autoPowerOff();
|
||||||
bool oldUseUSSensorTop = useUSSensorTop;
|
updateSwipe();
|
||||||
bool oldUseUSSensorBottom = useUSSensorBottom;
|
}
|
||||||
int8_t oldTopAPin = topPIRorTriggerPin;
|
|
||||||
int8_t oldTopBPin = topEchoPin;
|
|
||||||
int8_t oldBottomAPin = bottomPIRorTriggerPin;
|
|
||||||
int8_t oldBottomBPin = bottomEchoPin;
|
|
||||||
|
|
||||||
JsonObject staircase = root[FPSTR(_name)];
|
uint16_t getId() { return USERMOD_ID_ANIMATED_STAIRCASE; }
|
||||||
if (!staircase.isNull()) {
|
|
||||||
if (staircase[FPSTR(_enabled)].is<bool>()) {
|
/**
|
||||||
enabled = staircase[FPSTR(_enabled)].as<bool>();
|
* handling of MQTT message
|
||||||
|
* topic only contains stripped topic (part after /wled/MAC)
|
||||||
|
* topic should look like: /swipe with amessage of [up|down]
|
||||||
|
*/
|
||||||
|
bool onMqttMessage(char* topic, char* payload) {
|
||||||
|
if (strlen(topic) == 6 && strncmp_P(topic, PSTR("/swipe"), 6) == 0) {
|
||||||
|
String action = payload;
|
||||||
|
if (action == "up") {
|
||||||
|
bottomSensorWrite = true;
|
||||||
|
return true;
|
||||||
|
} else if (action == "down") {
|
||||||
|
topSensorWrite = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subscribe to MQTT topic for controlling usermod
|
||||||
|
*/
|
||||||
|
void onMqttConnect(bool sessionPresent) {
|
||||||
|
//(re)subscribe to required topics
|
||||||
|
char subuf[64];
|
||||||
|
if (mqttDeviceTopic[0] != 0) {
|
||||||
|
strcpy(subuf, mqttDeviceTopic);
|
||||||
|
strcat_P(subuf, PSTR("/swipe"));
|
||||||
|
mqtt->subscribe(subuf, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addToJsonState(JsonObject& root) {
|
||||||
|
JsonObject staircase = root[FPSTR(_name)];
|
||||||
|
if (staircase.isNull()) {
|
||||||
|
staircase = root.createNestedObject(FPSTR(_name));
|
||||||
|
}
|
||||||
|
writeSensorsToJson(staircase);
|
||||||
|
DEBUG_PRINTLN(F("Staircase sensor state exposed in API."));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reads configuration settings from the json API.
|
||||||
|
* See void addToJsonState(JsonObject& root)
|
||||||
|
*/
|
||||||
|
void readFromJsonState(JsonObject& root) {
|
||||||
|
if (!initDone) return; // prevent crash on boot applyPreset()
|
||||||
|
JsonObject staircase = root[FPSTR(_name)];
|
||||||
|
if (!staircase.isNull()) {
|
||||||
|
if (staircase[FPSTR(_enabled)].is<bool>()) {
|
||||||
|
enabled = staircase[FPSTR(_enabled)].as<bool>();
|
||||||
|
} else {
|
||||||
|
String str = staircase[FPSTR(_enabled)]; // checkbox -> off or on
|
||||||
|
enabled = (bool)(str!="off"); // off is guaranteed to be present
|
||||||
|
}
|
||||||
|
readSensorsFromJson(staircase);
|
||||||
|
DEBUG_PRINTLN(F("Staircase sensor state read from API."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes the configuration to internal flash memory.
|
||||||
|
*/
|
||||||
|
void addToConfig(JsonObject& root) {
|
||||||
|
JsonObject staircase = root[FPSTR(_name)];
|
||||||
|
if (staircase.isNull()) {
|
||||||
|
staircase = root.createNestedObject(FPSTR(_name));
|
||||||
|
}
|
||||||
|
staircase[FPSTR(_enabled)] = enabled;
|
||||||
|
staircase[FPSTR(_segmentDelay)] = segment_delay_ms;
|
||||||
|
staircase[FPSTR(_onTime)] = on_time_ms / 1000;
|
||||||
|
staircase[FPSTR(_useTopUltrasoundSensor)] = useUSSensorTop;
|
||||||
|
staircase[FPSTR(_topPIRorTrigger_pin)] = topPIRorTriggerPin;
|
||||||
|
staircase[FPSTR(_topEcho_pin)] = useUSSensorTop ? topEchoPin : -1;
|
||||||
|
staircase[FPSTR(_useBottomUltrasoundSensor)] = useUSSensorBottom;
|
||||||
|
staircase[FPSTR(_bottomPIRorTrigger_pin)] = bottomPIRorTriggerPin;
|
||||||
|
staircase[FPSTR(_bottomEcho_pin)] = useUSSensorBottom ? bottomEchoPin : -1;
|
||||||
|
staircase[FPSTR(_topEchoCm)] = topMaxDist;
|
||||||
|
staircase[FPSTR(_bottomEchoCm)] = bottomMaxDist;
|
||||||
|
DEBUG_PRINTLN(F("Staircase config saved."));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reads the configuration to internal flash memory before setup() is called.
|
||||||
|
*/
|
||||||
|
void readFromConfig(JsonObject& root) {
|
||||||
|
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[FPSTR(_name)];
|
||||||
|
if (!staircase.isNull()) {
|
||||||
|
if (staircase[FPSTR(_enabled)].is<bool>()) {
|
||||||
|
enabled = staircase[FPSTR(_enabled)].as<bool>();
|
||||||
|
} else {
|
||||||
|
String str = staircase[FPSTR(_enabled)]; // checkbox -> off or on
|
||||||
|
enabled = (bool)(str!="off"); // off is guaranteed to be present
|
||||||
|
}
|
||||||
|
segment_delay_ms = min(10000,max(10,staircase[FPSTR(_segmentDelay)].as<int>())); // max delay 10s
|
||||||
|
on_time_ms = min(900,max(10,staircase[FPSTR(_onTime)].as<int>())) * 1000; // min 10s, max 15min
|
||||||
|
|
||||||
|
if (staircase[FPSTR(_useTopUltrasoundSensor)].is<bool>()) {
|
||||||
|
useUSSensorTop = staircase[FPSTR(_useTopUltrasoundSensor)].as<bool>();
|
||||||
|
} else {
|
||||||
|
String str = staircase[FPSTR(_useTopUltrasoundSensor)]; // checkbox -> off or on
|
||||||
|
useUSSensorTop = (bool)(str!="off"); // off is guaranteed to be present
|
||||||
|
}
|
||||||
|
|
||||||
|
topPIRorTriggerPin = min(39,max(-1,staircase[FPSTR(_topPIRorTrigger_pin)].as<int>()));
|
||||||
|
topEchoPin = min(39,max(-1,staircase[FPSTR(_topEcho_pin)].as<int>()));
|
||||||
|
|
||||||
|
if (staircase[FPSTR(_useBottomUltrasoundSensor)].is<bool>()) {
|
||||||
|
useUSSensorBottom = staircase[FPSTR(_useBottomUltrasoundSensor)].as<bool>();
|
||||||
|
} else {
|
||||||
|
String str = staircase[FPSTR(_useBottomUltrasoundSensor)]; // checkbox -> off or on
|
||||||
|
useUSSensorBottom = (bool)(str!="off"); // off is guaranteed to be present
|
||||||
|
}
|
||||||
|
bottomPIRorTriggerPin = min(39,max(-1,staircase[FPSTR(_bottomPIRorTrigger_pin)].as<int>()));
|
||||||
|
bottomEchoPin = min(39,max(-1,staircase[FPSTR(_bottomEcho_pin)].as<int>()));
|
||||||
|
topMaxDist = min(150,max(30,staircase[FPSTR(_topEchoCm)].as<int>())); // max distnace ~1.5m (a lag of 9ms may be expected)
|
||||||
|
bottomMaxDist = min(150,max(30,staircase[FPSTR(_bottomEchoCm)].as<int>())); // max distance ~1.5m (a lag of 9ms may be expected)
|
||||||
} else {
|
} else {
|
||||||
String str = staircase[FPSTR(_enabled)]; // checkbox -> off or on
|
DEBUG_PRINTLN(F("No config found. (Using defaults.)"));
|
||||||
enabled = (bool)(str!="off"); // off is guaranteed to be present
|
|
||||||
}
|
}
|
||||||
segment_delay_ms = min(10000,max(10,staircase[FPSTR(_segmentDelay)].as<int>())); // max delay 10s
|
if (!initDone) {
|
||||||
on_time_ms = min(900,max(10,staircase[FPSTR(_onTime)].as<int>())) * 1000; // min 10s, max 15min
|
// first run: reading from cfg.json
|
||||||
|
DEBUG_PRINTLN(F("Staircase config loaded."));
|
||||||
if (staircase[FPSTR(_useTopUltrasoundSensor)].is<bool>()) {
|
|
||||||
useUSSensorTop = staircase[FPSTR(_useTopUltrasoundSensor)].as<bool>();
|
|
||||||
} else {
|
} else {
|
||||||
String str = staircase[FPSTR(_useTopUltrasoundSensor)]; // checkbox -> off or on
|
// changing paramters from settings page
|
||||||
useUSSensorTop = (bool)(str!="off"); // off is guaranteed to be present
|
DEBUG_PRINTLN(F("Staircase config (re)loaded."));
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
topPIRorTriggerPin = min(39,max(-1,staircase[FPSTR(_topPIRorTrigger_pin)].as<int>()));
|
|
||||||
topEchoPin = min(39,max(-1,staircase[FPSTR(_topEcho_pin)].as<int>()));
|
|
||||||
|
|
||||||
if (staircase[FPSTR(_useBottomUltrasoundSensor)].is<bool>()) {
|
|
||||||
useUSSensorBottom = staircase[FPSTR(_useBottomUltrasoundSensor)].as<bool>();
|
|
||||||
} else {
|
|
||||||
String str = staircase[FPSTR(_useBottomUltrasoundSensor)]; // checkbox -> off or on
|
|
||||||
useUSSensorBottom = (bool)(str!="off"); // off is guaranteed to be present
|
|
||||||
}
|
|
||||||
bottomPIRorTriggerPin = min(39,max(-1,staircase[FPSTR(_bottomPIRorTrigger_pin)].as<int>()));
|
|
||||||
bottomEchoPin = min(39,max(-1,staircase[FPSTR(_bottomEcho_pin)].as<int>()));
|
|
||||||
topMaxTimeUs = min(18000,max(300,staircase[FPSTR(_topEchoTime)].as<int>())); // max distnace ~3m (a noticable lag of 18ms may be expected)
|
|
||||||
bottomMaxTimeUs = min(18000,max(300,staircase[FPSTR(_bottomEchoTime)].as<int>())); // max distance ~3m (a noticable lag of 18ms may be expected)
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Shows the delay between steps and power-off time in the "info"
|
|
||||||
* tab of the web-UI.
|
|
||||||
*/
|
|
||||||
void addToJsonInfo(JsonObject& root) {
|
|
||||||
JsonObject staircase = root["u"];
|
|
||||||
if (staircase.isNull()) {
|
|
||||||
staircase = root.createNestedObject("u");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enabled) {
|
/*
|
||||||
|
* Shows the delay between steps and power-off time in the "info"
|
||||||
|
* tab of the web-UI.
|
||||||
|
*/
|
||||||
|
void addToJsonInfo(JsonObject& root) {
|
||||||
|
JsonObject staircase = root["u"];
|
||||||
|
if (staircase.isNull()) {
|
||||||
|
staircase = root.createNestedObject("u");
|
||||||
|
}
|
||||||
|
|
||||||
JsonArray usermodEnabled = staircase.createNestedArray(F("Staircase enabled")); // name
|
JsonArray usermodEnabled = staircase.createNestedArray(F("Staircase enabled")); // name
|
||||||
usermodEnabled.add("yes"); // value
|
if (enabled) {
|
||||||
|
usermodEnabled.add("yes"); // value
|
||||||
|
/*
|
||||||
|
JsonArray segmentDelay = staircase.createNestedArray(F("Delay between stairs")); // name
|
||||||
|
segmentDelay.add(segment_delay_ms); // value
|
||||||
|
segmentDelay.add("ms"); // unit
|
||||||
|
|
||||||
JsonArray segmentDelay = staircase.createNestedArray(F("Delay between stairs")); // name
|
JsonArray onTime = staircase.createNestedArray(F("Power-off stairs after")); // name
|
||||||
segmentDelay.add(segment_delay_ms); // value
|
onTime.add(on_time_ms / 1000); // value
|
||||||
segmentDelay.add("ms"); // unit
|
onTime.add("s"); // unit
|
||||||
|
*/
|
||||||
JsonArray onTime = staircase.createNestedArray(F("Power-off stairs after")); // name
|
} else {
|
||||||
onTime.add(on_time_ms / 1000); // value
|
usermodEnabled.add("no"); // value
|
||||||
onTime.add("s"); // unit
|
}
|
||||||
} else {
|
|
||||||
JsonArray usermodEnabled = staircase.createNestedArray(F("Staircase enabled")); // name
|
|
||||||
usermodEnabled.add("no"); // value
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
@ -482,5 +525,5 @@ const char Animated_Staircase::_topEcho_pin[] PROGMEM = "topEcho_p
|
|||||||
const char Animated_Staircase::_useBottomUltrasoundSensor[] PROGMEM = "useBottomUltrasoundSensor";
|
const char Animated_Staircase::_useBottomUltrasoundSensor[] PROGMEM = "useBottomUltrasoundSensor";
|
||||||
const char Animated_Staircase::_bottomPIRorTrigger_pin[] PROGMEM = "bottomPIRorTrigger_pin";
|
const char Animated_Staircase::_bottomPIRorTrigger_pin[] PROGMEM = "bottomPIRorTrigger_pin";
|
||||||
const char Animated_Staircase::_bottomEcho_pin[] PROGMEM = "bottomEcho_pin";
|
const char Animated_Staircase::_bottomEcho_pin[] PROGMEM = "bottomEcho_pin";
|
||||||
const char Animated_Staircase::_topEchoTime[] PROGMEM = "top-echo-us";
|
const char Animated_Staircase::_topEchoCm[] PROGMEM = "top-dist-cm";
|
||||||
const char Animated_Staircase::_bottomEchoTime[] PROGMEM = "bottom-echo-us";
|
const char Animated_Staircase::_bottomEchoCm[] PROGMEM = "bottom-dist-cm";
|
||||||
|
@ -32,35 +32,36 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
//Usermod IDs
|
//Usermod IDs
|
||||||
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
|
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
|
||||||
#define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID
|
#define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID
|
||||||
#define USERMOD_ID_EXAMPLE 2 //Usermod "usermod_v2_example.h"
|
#define USERMOD_ID_EXAMPLE 2 //Usermod "usermod_v2_example.h"
|
||||||
#define USERMOD_ID_TEMPERATURE 3 //Usermod "usermod_temperature.h"
|
#define USERMOD_ID_TEMPERATURE 3 //Usermod "usermod_temperature.h"
|
||||||
#define USERMOD_ID_FIXNETSERVICES 4 //Usermod "usermod_Fix_unreachable_netservices.h"
|
#define USERMOD_ID_FIXNETSERVICES 4 //Usermod "usermod_Fix_unreachable_netservices.h"
|
||||||
#define USERMOD_ID_PIRSWITCH 5 //Usermod "usermod_PIR_sensor_switch.h"
|
#define USERMOD_ID_PIRSWITCH 5 //Usermod "usermod_PIR_sensor_switch.h"
|
||||||
#define USERMOD_ID_IMU 6 //Usermod "usermod_mpu6050_imu.h"
|
#define USERMOD_ID_IMU 6 //Usermod "usermod_mpu6050_imu.h"
|
||||||
#define USERMOD_ID_FOUR_LINE_DISP 7 //Usermod "usermod_v2_four_line_display.h
|
#define USERMOD_ID_FOUR_LINE_DISP 7 //Usermod "usermod_v2_four_line_display.h
|
||||||
#define USERMOD_ID_ROTARY_ENC_UI 8 //Usermod "usermod_v2_rotary_encoder_ui.h"
|
#define USERMOD_ID_ROTARY_ENC_UI 8 //Usermod "usermod_v2_rotary_encoder_ui.h"
|
||||||
#define USERMOD_ID_AUTO_SAVE 9 //Usermod "usermod_v2_auto_save.h"
|
#define USERMOD_ID_AUTO_SAVE 9 //Usermod "usermod_v2_auto_save.h"
|
||||||
#define USERMOD_ID_DHT 10 //Usermod "usermod_dht.h"
|
#define USERMOD_ID_DHT 10 //Usermod "usermod_dht.h"
|
||||||
#define USERMOD_ID_MODE_SORT 11 //Usermod "usermod_v2_mode_sort.h"
|
#define USERMOD_ID_MODE_SORT 11 //Usermod "usermod_v2_mode_sort.h"
|
||||||
#define USERMOD_ID_VL53L0X 12 //Usermod "usermod_vl53l0x_gestures.h"
|
#define USERMOD_ID_VL53L0X 12 //Usermod "usermod_vl53l0x_gestures.h"
|
||||||
#define USERMOD_ID_MULTI_RELAY 101 //Usermod "usermod_multi_relay.h"
|
#define USERMOD_ID_MULTI_RELAY 13 //Usermod "usermod_multi_relay.h"
|
||||||
|
#define USERMOD_ID_ANIMATED_STAIRCASE 14 //Usermod "Animated_Staircase.h"
|
||||||
|
|
||||||
//Access point behavior
|
//Access point behavior
|
||||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||||
#define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost)
|
#define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost)
|
||||||
#define AP_BEHAVIOR_ALWAYS 2 //Always open
|
#define AP_BEHAVIOR_ALWAYS 2 //Always open
|
||||||
#define AP_BEHAVIOR_BUTTON_ONLY 3 //Only when button pressed for 6 sec
|
#define AP_BEHAVIOR_BUTTON_ONLY 3 //Only when button pressed for 6 sec
|
||||||
|
|
||||||
//Notifier callMode
|
//Notifier callMode
|
||||||
#define NOTIFIER_CALL_MODE_INIT 0 //no updates on init, can be used to disable updates
|
#define NOTIFIER_CALL_MODE_INIT 0 //no updates on init, can be used to disable updates
|
||||||
#define NOTIFIER_CALL_MODE_DIRECT_CHANGE 1
|
#define NOTIFIER_CALL_MODE_DIRECT_CHANGE 1
|
||||||
#define NOTIFIER_CALL_MODE_BUTTON 2
|
#define NOTIFIER_CALL_MODE_BUTTON 2
|
||||||
#define NOTIFIER_CALL_MODE_NOTIFICATION 3
|
#define NOTIFIER_CALL_MODE_NOTIFICATION 3
|
||||||
#define NOTIFIER_CALL_MODE_NIGHTLIGHT 4
|
#define NOTIFIER_CALL_MODE_NIGHTLIGHT 4
|
||||||
#define NOTIFIER_CALL_MODE_NO_NOTIFY 5
|
#define NOTIFIER_CALL_MODE_NO_NOTIFY 5
|
||||||
#define NOTIFIER_CALL_MODE_FX_CHANGED 6 //no longer used
|
#define NOTIFIER_CALL_MODE_FX_CHANGED 6 //no longer used
|
||||||
#define NOTIFIER_CALL_MODE_HUE 7
|
#define NOTIFIER_CALL_MODE_HUE 7
|
||||||
#define NOTIFIER_CALL_MODE_PRESET_CYCLE 8
|
#define NOTIFIER_CALL_MODE_PRESET_CYCLE 8
|
||||||
#define NOTIFIER_CALL_MODE_BLYNK 9
|
#define NOTIFIER_CALL_MODE_BLYNK 9
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// version code in format yymmddb (b = daily build)
|
// version code in format yymmddb (b = daily build)
|
||||||
#define VERSION 2105131
|
#define VERSION 2105151
|
||||||
|
|
||||||
//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…
Reference in New Issue
Block a user