Merge branch 'dev' of https://github.com/aircoookie/WLED into dev
This commit is contained in:
commit
73a99a7dea
@ -164,10 +164,10 @@ build_flags = -w -g
|
|||||||
-DCONFIG_LITTLEFS_FOR_IDF_3_2
|
-DCONFIG_LITTLEFS_FOR_IDF_3_2
|
||||||
|
|
||||||
[scripts_defaults]
|
[scripts_defaults]
|
||||||
extra_scripts = pio/name-firmware.py
|
extra_scripts = pio-scripts/name-firmware.py
|
||||||
pio/gzip-firmware.py
|
pio-scripts/gzip-firmware.py
|
||||||
pio/strip-floats.py
|
pio-scripts/strip-floats.py
|
||||||
pio/user_config_copy.py
|
pio-scripts/user_config_copy.py
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# COMMON SETTINGS:
|
# COMMON SETTINGS:
|
||||||
|
427
usermods/Animated_Staircase/Animated_Staircase.h
Normal file
427
usermods/Animated_Staircase/Animated_Staircase.h
Normal file
@ -0,0 +1,427 @@
|
|||||||
|
/*
|
||||||
|
* Usermod for detecting people entering/leaving a staircase and switching the
|
||||||
|
* staircase on/off.
|
||||||
|
*
|
||||||
|
* Edit the Animated_Staircase_config.h file to compile this usermod for your
|
||||||
|
* specific configuration.
|
||||||
|
*
|
||||||
|
* See the accompanying README.md file for more info.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "wled.h"
|
||||||
|
#include "Animated_Staircase_config.h"
|
||||||
|
#define USERMOD_ID_ANIMATED_STAIRCASE 1011
|
||||||
|
|
||||||
|
/* Initial configuration (available in API and stored in flash) */
|
||||||
|
bool enabled = true; // Enable this usermod
|
||||||
|
unsigned long segment_delay_ms = 150; // Time between switching each segment
|
||||||
|
unsigned long on_time_ms = 5 * 1000; // The time for the light to stay on
|
||||||
|
#ifndef TOP_PIR_PIN
|
||||||
|
unsigned int topMaxTimeUs = 1749; // default echo timout, top
|
||||||
|
#endif
|
||||||
|
#ifndef BOTTOM_PIR_PIN
|
||||||
|
unsigned int bottomMaxTimeUs = 1749; // default echo timout, bottom
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Time between checking of the sensors
|
||||||
|
const int scanDelay = 50;
|
||||||
|
|
||||||
|
class Animated_Staircase : public Usermod {
|
||||||
|
private:
|
||||||
|
// Lights on or off.
|
||||||
|
// Flipping this will start a transition.
|
||||||
|
bool on = false;
|
||||||
|
|
||||||
|
// Swipe direction for current transition
|
||||||
|
#define SWIPE_UP true
|
||||||
|
#define SWIPE_DOWN false
|
||||||
|
bool swipe = SWIPE_UP;
|
||||||
|
|
||||||
|
// Indicates which Sensor was seen last (to determine
|
||||||
|
// the direction when swiping off)
|
||||||
|
#define LOWER false
|
||||||
|
#define UPPER true
|
||||||
|
bool lastSensor = LOWER;
|
||||||
|
|
||||||
|
// Time of the last transition action
|
||||||
|
unsigned long lastTime = 0;
|
||||||
|
|
||||||
|
// Time of the last sensor check
|
||||||
|
unsigned long lastScanTime = 0;
|
||||||
|
|
||||||
|
// Last time the lights were switched on or off
|
||||||
|
unsigned long lastSwitchTime = 0;
|
||||||
|
|
||||||
|
// segment id between onIndex and offIndex are on.
|
||||||
|
// controll the swipe by setting/moving these indices around.
|
||||||
|
// onIndex must be less than or equal to offIndex
|
||||||
|
byte onIndex = 0;
|
||||||
|
byte offIndex = 0;
|
||||||
|
|
||||||
|
// The maximum number of configured segments.
|
||||||
|
// Dynamically updated based on user configuration.
|
||||||
|
byte maxSegmentId = 1;
|
||||||
|
byte mainSegmentId = 0;
|
||||||
|
|
||||||
|
bool saveState = false;
|
||||||
|
|
||||||
|
// These values are used by the API to read the
|
||||||
|
// last sensor state, or trigger a sensor
|
||||||
|
// through the API
|
||||||
|
bool topSensorRead = false;
|
||||||
|
bool topSensorWrite = false;
|
||||||
|
bool bottomSensorRead = false;
|
||||||
|
bool bottomSensorWrite = false;
|
||||||
|
|
||||||
|
void updateSegments() {
|
||||||
|
mainSegmentId = strip.getMainSegmentId();
|
||||||
|
WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
|
||||||
|
WS2812FX::Segment* segments = strip.getSegments();
|
||||||
|
for (int i = 0; i < MAX_NUM_SEGMENTS; i++, segments++) {
|
||||||
|
if (!segments->isActive()) {
|
||||||
|
maxSegmentId = i - 1;
|
||||||
|
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();
|
||||||
|
|
||||||
|
#ifdef BOTTOM_PIR_PIN
|
||||||
|
bottomSensorRead = bottomSensorWrite || (digitalRead(BOTTOM_PIR_PIN) == HIGH);
|
||||||
|
#else
|
||||||
|
bottomSensorRead = bottomSensorWrite || ultrasoundRead(BOTTOM_TRIGGER_PIN, BOTTOM_ECHO_PIN, bottomMaxTimeUs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TOP_PIR_PIN
|
||||||
|
topSensorRead = topSensorWrite || (digitalRead(TOP_PIR_PIN) == HIGH);
|
||||||
|
#else
|
||||||
|
topSensorRead = topSensorWrite || ultrasoundRead(TOP_TRIGGER_PIN, TOP_ECHO_PIN, topMaxTimeUs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
Serial.println("ON -> Swipe up.");
|
||||||
|
} else {
|
||||||
|
Serial.println("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() {
|
||||||
|
if (on && ((millis() - lastSwitchTime) > on_time_ms)) {
|
||||||
|
// Swipe OFF in the direction of the last sensor detection
|
||||||
|
swipe = lastSensor;
|
||||||
|
on = false;
|
||||||
|
|
||||||
|
if (swipe) {
|
||||||
|
Serial.println("OFF -> Swipe up.");
|
||||||
|
} else {
|
||||||
|
Serial.println("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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeSettingsToJson(JsonObject& root) {
|
||||||
|
JsonObject staircase = root["staircase"];
|
||||||
|
if (staircase.isNull()) {
|
||||||
|
staircase = root.createNestedObject("staircase");
|
||||||
|
}
|
||||||
|
staircase["enabled"] = enabled;
|
||||||
|
staircase["segment-delay-ms"] = segment_delay_ms;
|
||||||
|
staircase["on-time-s"] = on_time_ms / 1000;
|
||||||
|
|
||||||
|
#ifdef TOP_TRIGGER_PIN
|
||||||
|
staircase["top-echo-us"] = topMaxTimeUs;
|
||||||
|
#endif
|
||||||
|
#ifdef BOTTOM_TRIGGER_PIN
|
||||||
|
staircase["bottom-echo-us"] = bottomMaxTimeUs;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeSensorsToJson(JsonObject& root) {
|
||||||
|
JsonObject staircase = root["staircase"];
|
||||||
|
if (staircase.isNull()) {
|
||||||
|
staircase = root.createNestedObject("staircase");
|
||||||
|
}
|
||||||
|
staircase["top-sensor"] = topSensorRead;
|
||||||
|
staircase["bottom-sensor"] = bottomSensorRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readSettingsFromJson(JsonObject& root) {
|
||||||
|
JsonObject staircase = root["staircase"];
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
bool shouldEnable = staircase["enabled"] | enabled;
|
||||||
|
if (shouldEnable != enabled) {
|
||||||
|
enable(shouldEnable);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long c_segment_delay_ms = staircase["segment-delay-ms"] | segment_delay_ms;
|
||||||
|
if (c_segment_delay_ms != segment_delay_ms) {
|
||||||
|
segment_delay_ms = c_segment_delay_ms;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long c_on_time_ms = (staircase["on-time-s"] | (on_time_ms / 1000)) * 1000;
|
||||||
|
if (c_on_time_ms != on_time_ms) {
|
||||||
|
on_time_ms = c_on_time_ms;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TOP_TRIGGER_PIN
|
||||||
|
unsigned int c_topMaxTimeUs = staircase["top-echo-us"] | topMaxTimeUs;
|
||||||
|
if (c_topMaxTimeUs != topMaxTimeUs) {
|
||||||
|
topMaxTimeUs = c_topMaxTimeUs;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef BOTTOM_TRIGGER_PIN
|
||||||
|
unsigned int c_bottomMaxTimeUs = staircase["bottom-echo-us"] | bottomMaxTimeUs;
|
||||||
|
if (c_bottomMaxTimeUs != bottomMaxTimeUs) {
|
||||||
|
bottomMaxTimeUs = c_bottomMaxTimeUs;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readSensorsFromJson(JsonObject& root) {
|
||||||
|
JsonObject staircase = root["staircase"];
|
||||||
|
bottomSensorWrite = bottomSensorRead || (staircase["bottom-sensor"].as<bool>());
|
||||||
|
topSensorWrite = topSensorRead || (staircase["top-sensor"].as<bool>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable(bool enable) {
|
||||||
|
if (enable) {
|
||||||
|
Serial.println("Animated Staircase enabled.");
|
||||||
|
Serial.print("Delay between steps: ");
|
||||||
|
Serial.print(segment_delay_ms, DEC);
|
||||||
|
Serial.print(" milliseconds.\nStairs switch off after: ");
|
||||||
|
Serial.print(on_time_ms / 1000, DEC);
|
||||||
|
Serial.println(" seconds.");
|
||||||
|
|
||||||
|
#ifdef BOTTOM_PIR_PIN
|
||||||
|
pinMode(BOTTOM_PIR_PIN, INPUT);
|
||||||
|
#else
|
||||||
|
pinMode(BOTTOM_TRIGGER_PIN, OUTPUT);
|
||||||
|
pinMode(BOTTOM_ECHO_PIN, INPUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TOP_PIR_PIN
|
||||||
|
pinMode(TOP_PIR_PIN, INPUT);
|
||||||
|
#else
|
||||||
|
pinMode(TOP_TRIGGER_PIN, OUTPUT);
|
||||||
|
pinMode(TOP_ECHO_PIN, INPUT);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
// Restore segment options
|
||||||
|
WS2812FX::Segment mainsegment = strip.getSegment(mainSegmentId);
|
||||||
|
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);
|
||||||
|
Serial.println("Animated Staircase disabled.");
|
||||||
|
}
|
||||||
|
enabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setup() { enable(enabled); }
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Write changed settings from to flash (see readFromJsonState())
|
||||||
|
if (saveState) {
|
||||||
|
serializeConfig();
|
||||||
|
saveState = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkSensors();
|
||||||
|
autoPowerOff();
|
||||||
|
updateSwipe();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t getId() { return USERMOD_ID_ANIMATED_STAIRCASE; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shows configuration settings to the json API. This object looks like:
|
||||||
|
*
|
||||||
|
* "staircase" : {
|
||||||
|
* "enabled" : true
|
||||||
|
* "segment-delay-ms" : 150,
|
||||||
|
* "on-time-s" : 5
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void addToJsonState(JsonObject& root) {
|
||||||
|
writeSettingsToJson(root);
|
||||||
|
writeSensorsToJson(root);
|
||||||
|
Serial.println("Staircase config exposed in API.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reads configuration settings from the json API.
|
||||||
|
* See void addToJsonState(JsonObject& root)
|
||||||
|
*/
|
||||||
|
void readFromJsonState(JsonObject& root) {
|
||||||
|
// The call to serializeConfig() must be done in the main loop,
|
||||||
|
// so we set a flag to signal the main loop to save state.
|
||||||
|
saveState = readSettingsFromJson(root);
|
||||||
|
readSensorsFromJson(root);
|
||||||
|
Serial.println("Staircase config read from API.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes the configuration to internal flash memory.
|
||||||
|
*/
|
||||||
|
void addToConfig(JsonObject& root) {
|
||||||
|
writeSettingsToJson(root);
|
||||||
|
Serial.println("Staircase config saved.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reads the configuration to internal flash memory before setup() is called.
|
||||||
|
*/
|
||||||
|
void readFromConfig(JsonObject& root) {
|
||||||
|
readSettingsFromJson(root);
|
||||||
|
Serial.println("Staircase config loaded.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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) {
|
||||||
|
JsonArray usermodEnabled =
|
||||||
|
staircase.createNestedArray("Staircase enabled"); // name
|
||||||
|
usermodEnabled.add("yes"); // value
|
||||||
|
|
||||||
|
JsonArray segmentDelay =
|
||||||
|
staircase.createNestedArray("Delay between stairs"); // name
|
||||||
|
segmentDelay.add(segment_delay_ms); // value
|
||||||
|
segmentDelay.add(" milliseconds"); // unit
|
||||||
|
|
||||||
|
JsonArray onTime =
|
||||||
|
staircase.createNestedArray("Power-off stairs after"); // name
|
||||||
|
onTime.add(on_time_ms / 1000); // value
|
||||||
|
onTime.add(" seconds"); // unit
|
||||||
|
} else {
|
||||||
|
JsonArray usermodEnabled =
|
||||||
|
staircase.createNestedArray("Staircase enabled"); // name
|
||||||
|
usermodEnabled.add("no"); // value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
21
usermods/Animated_Staircase/Animated_Staircase_config.h
Normal file
21
usermods/Animated_Staircase/Animated_Staircase_config.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Animated_Staircase compiletime confguration.
|
||||||
|
*
|
||||||
|
* Please see README.md on how to change this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Please change the pin numbering below to match your board.
|
||||||
|
#define TOP_PIR_PIN D5
|
||||||
|
#define BOTTOM_PIR_PIN D6
|
||||||
|
|
||||||
|
// Or uncumment and a pir and use an ultrasound HC-SR04 sensor,
|
||||||
|
// see README.md for details
|
||||||
|
#ifndef TOP_PIR_PIN
|
||||||
|
#define TOP_TRIGGER_PIN D2
|
||||||
|
#define TOP_ECHO_PIN D3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BOTTOM_PIR_PIN
|
||||||
|
#define BOTTOM_TRIGGER_PIN D4
|
||||||
|
#define BOTTOM_ECHO_PIN D5
|
||||||
|
#endif
|
203
usermods/Animated_Staircase/README.md
Normal file
203
usermods/Animated_Staircase/README.md
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
# Usermod Animated Staircase
|
||||||
|
This usermod makes your staircase look cool by switching it on with an animation. It uses
|
||||||
|
PIR or ultrasonic sensors at the top and bottom of your stairs to:
|
||||||
|
|
||||||
|
- Light up the steps in your walking direction, leading the way.
|
||||||
|
- Switch off the steps after you, in the direction of the last detected movement.
|
||||||
|
- Always switch on when one of the sensors detects movement, even if an effect
|
||||||
|
is still running. It can therewith handle multiple people on the stairs gracefully.
|
||||||
|
|
||||||
|
The Animated Staircase can be controlled by the WLED API. Change settings such as
|
||||||
|
speed, on/off time and distance settings by sending an HTTP request, see below.
|
||||||
|
|
||||||
|
## WLED integration
|
||||||
|
To include this usermod in your WLED setup, you have to be able to [compile WLED from source](https://github.com/Aircoookie/WLED/wiki/Compiling-WLED).
|
||||||
|
|
||||||
|
Before compiling, you have to make the following modifications:
|
||||||
|
|
||||||
|
Edit `usermods_list.cpp`:
|
||||||
|
1. Open `wled00/usermods_list.cpp`
|
||||||
|
2. add `#include "../usermods/Animated_Staircase/Animated_Staircase.h"` to the top of the file
|
||||||
|
3. add `usermods.add(new Animated_Staircase());` to the end of the `void registerUsermods()` function.
|
||||||
|
|
||||||
|
Edit `Animated_Staircase_config.h`:
|
||||||
|
1. Open `usermods/Animated_Staircase/Animated_Staircase_config.h`
|
||||||
|
2. To use PIR sensors, change these lines to match your setup:
|
||||||
|
Using D7 and D6 pin notation as used on several boards:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define TOP_PIR_PIN D7
|
||||||
|
#define BOTTOM_PIR_PIN D6
|
||||||
|
```
|
||||||
|
|
||||||
|
Or using GPIO numbering for pins 25 and 26:
|
||||||
|
```cpp
|
||||||
|
#define TOP_PIR_PIN 26
|
||||||
|
#define BOTTOM_PIR_PIN 25
|
||||||
|
```
|
||||||
|
|
||||||
|
To use Ultrasonic HC-SR04 sensors instead of (one of the) PIR sensors,
|
||||||
|
uncomment one of the PIR sensor lines and adjust the pin numbers for the
|
||||||
|
connected Ultrasonic sensor. In the example below we use an Ultrasonic
|
||||||
|
sensor at the bottom of the stairs:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define TOP_PIR_PIN 32
|
||||||
|
//#define BOTTOM_PIR_PIN D6 /* This PIR sensor is disabled */
|
||||||
|
|
||||||
|
#ifndef TOP_PIR_PIN
|
||||||
|
#define TOP_SIGNAL_PIN D2
|
||||||
|
#define TOP_ECHO_PIN D3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BOTTOM_PIR_PIN /* If the bottom PIR is disabled, */
|
||||||
|
#define BOTTOM_SIGNAL_PIN 25 /* This Ultrasonic sensor is used */
|
||||||
|
#define BOTTOM_ECHO_PIN 26
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
After these modifications, compile and upload your WLED binary to your board
|
||||||
|
and check the WLED info page to see if this usermod is enabled.
|
||||||
|
|
||||||
|
## Hardware installation
|
||||||
|
1. Stick the LED strip under each step of the stairs.
|
||||||
|
2. Connect the ESP8266 pin D4 or ESP32 pin D2 to the first LED data pin at the bottom step
|
||||||
|
of your stairs.
|
||||||
|
3. Connect the data-out pin at the end of each strip per step to the data-in pin on the
|
||||||
|
other end of the next step, creating one large virtual LED strip.
|
||||||
|
4. Mount sensors of choice at the bottom and top of the stairs and connect them to the ESP.
|
||||||
|
5. To make sure all LEDs get enough power and have your staircase lighted evenly, power each
|
||||||
|
step from one side, using at least AWG14 or 2.5mm^2 cable. Don't connect them serial as you
|
||||||
|
do for the datacable!
|
||||||
|
|
||||||
|
You _may_ need to use 10k pull-down resistors on the selected PIR pins, depending on the sensor.
|
||||||
|
|
||||||
|
## WLED configuration
|
||||||
|
1. In the WLED UI, confgure a segment for each step. The lowest step of the stairs is the
|
||||||
|
lowest segment id.
|
||||||
|
2. Save your segments into a preset.
|
||||||
|
3. Ideally, add the preset in the config > LED setup menu to the "apply
|
||||||
|
preset **n** at boot" setting.
|
||||||
|
|
||||||
|
## Changing behavior through API
|
||||||
|
The Staircase settings can be changed through the WLED JSON api.
|
||||||
|
|
||||||
|
**NOTE:** We are using [curl](https://curl.se/) to send HTTP POSTs to the WLED API.
|
||||||
|
If you're using Windows and want to use the curl commands, replace the `\` with a `^`
|
||||||
|
or remove them and put everything on one line.
|
||||||
|
|
||||||
|
|
||||||
|
| Setting | Description | Default |
|
||||||
|
|------------------|---------------------------------------------------------------|---------|
|
||||||
|
| enabled | Enable or disable the usermod | true |
|
||||||
|
| segment-delay-ms | Delay (milliseconds) between switching on/off each step | 150 |
|
||||||
|
| on-time-s | Time (seconds) the stairs stay lit after last detection | 5 |
|
||||||
|
| bottom-echo-us | Detection range of ultrasonic sensor | 1749 |
|
||||||
|
| bottomsensor | Manually trigger a down to up animation via API | false |
|
||||||
|
| topsensor | Manually trigger an up to down animation via API | false |
|
||||||
|
|
||||||
|
|
||||||
|
To read the current settings, open a browser to `http://xxx.xxx.xxx.xxx/json/state` (use your WLED
|
||||||
|
device IP address). The device will respond with a json object containing all WLED settings.
|
||||||
|
The staircase settings and sensor states are inside the WLED status element:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"state": {
|
||||||
|
"staircase": {
|
||||||
|
"enabled": true,
|
||||||
|
"segment-delay-ms": 150,
|
||||||
|
"on-time-s": 5,
|
||||||
|
"bottomsensor": false,
|
||||||
|
"topsensor": false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enable/disable the usermod
|
||||||
|
By disabling the usermod you will be able to keep the LED's on, independent from the sensor
|
||||||
|
activity. This enables to play with the lights without the usermod switching them on or off.
|
||||||
|
|
||||||
|
To disable the usermod:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST -H "Content-Type: application/json" \
|
||||||
|
-d {"staircase":{"enabled":false}} \
|
||||||
|
xxx.xxx.xxx.xxx/json/state
|
||||||
|
```
|
||||||
|
|
||||||
|
To enable the usermod again, use `"enabled":true`.
|
||||||
|
|
||||||
|
### Changing animation parameters
|
||||||
|
To change the delay between the steps to (for example) 100 milliseconds and the on-time to
|
||||||
|
10 seconds:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST -H "Content-Type: application/json" \
|
||||||
|
-d '{"staircase":{"segment-delay-ms":100,"on-time-s":10}}' \
|
||||||
|
xxx.xxx.xxx.xxx/json/state
|
||||||
|
```
|
||||||
|
|
||||||
|
### Changing detection range of the ultrasonic HC-SR04 sensor
|
||||||
|
When an ultrasonic sensor is enabled in `Animated_Staircase_config.h`, you'll see a
|
||||||
|
`bottom-echo-us` setting appear in the json api:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"state": {
|
||||||
|
"staircase": {
|
||||||
|
"enabled": true,
|
||||||
|
"segment-delay-ms": 150,
|
||||||
|
"on-time-s": 5,
|
||||||
|
"bottom-echo-us": 1749
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If the HC-SR04 sensor detects an echo within 1749 microseconds (corresponding to ~30 cm
|
||||||
|
detection range from the sensor), it will trigger switching on the staircase. This setting
|
||||||
|
can be changed through the API with an HTTP POST:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST -H "Content-Type: application/json" \
|
||||||
|
-d '{"staircase":{"bottom-echo-us":1166}}' \
|
||||||
|
xxx.xxx.xxx.xxx/json/state
|
||||||
|
```
|
||||||
|
|
||||||
|
Calculating the detection range can be performed as follows: The speed of sound is 343m/s at 20
|
||||||
|
degrees Centigrade. Since the sound has to travel back and forth, the detection range for the
|
||||||
|
sensor in cm is (0.0343 * maxTimeUs) / 2. To get you started, please find delays and distances below:
|
||||||
|
|
||||||
|
| Distance | Detection time |
|
||||||
|
|---------:|----------------:|
|
||||||
|
| 5 cm | 292 uS |
|
||||||
|
| 10 cm | 583 uS |
|
||||||
|
| 20 cm | 1166 uS |
|
||||||
|
| 30 cm | 1749 uS |
|
||||||
|
| 50 cm | 2915 uS |
|
||||||
|
| 100 cm | 5831 uS |
|
||||||
|
|
||||||
|
**Please note:** that using an HC-SR04 sensor, particularly when detecting echos at longer
|
||||||
|
distances creates delays in the WLED software, and _might_ introduce timing hickups in your animations or
|
||||||
|
a less responsive web interface. It is therefore advised to keep the detection time as short as possible.
|
||||||
|
|
||||||
|
### Animation triggering through the API
|
||||||
|
Instead of stairs activation by one of the sensors, you can also trigger the animation through
|
||||||
|
the API. To simulate triggering the bottom sensor, use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST -H "Content-Type: application/json" \
|
||||||
|
-d '{"staircase":{"bottomsensor":true}}' \
|
||||||
|
xxx.xxx.xxx.xxx/json/state
|
||||||
|
```
|
||||||
|
|
||||||
|
Likewise, to trigger the top sensor, use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST -H "Content-Type: application/json" \
|
||||||
|
-d '{"staircase":{"topsensor":true}}' \
|
||||||
|
xxx.xxx.xxx.xxx/json/state
|
||||||
|
```
|
||||||
|
|
||||||
|
Have fun with this usermod.<br/>
|
||||||
|
www.rolfje.com
|
@ -87,4 +87,4 @@ void registerUsermods()
|
|||||||
#ifdef USERMOD_DHT
|
#ifdef USERMOD_DHT
|
||||||
usermods.add(new UsermodDHT());
|
usermods.add(new UsermodDHT());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user