diff --git a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h new file mode 100644 index 000000000..8d8bcf0b5 --- /dev/null +++ b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h @@ -0,0 +1,136 @@ +#include "wled.h" + +/* + * Usermods allow you to add own functionality to WLED more easily + * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality + * + * This is Stairway-Wipe as a v2 usermod. + * + * Using this usermod: + * 1. Copy the usermod into the sketch folder (same folder as wled00.ino) + * 2. Register the usermod by adding #include "stairway-wipe-usermod-v2.h" in the top and registerUsermod(new StairwayWipeUsermod()) in the bottom of usermods_list.cpp + */ + +class StairwayWipeUsermod : public Usermod { + private: + //Private class members. You can declare variables and functions only accessible to your usermod here + unsigned long lastTime = 0; + byte wipeState = 0; //0: inactive 1: wiping 2: solid + unsigned long timeStaticStart = 0; + uint16_t previousUserVar0 = 0; + +//comment this out if you want the turn off effect to be just fading out instead of reverse wipe +#define STAIRCASE_WIPE_OFF + public: + + void loop() { + //userVar0 (U0 in HTTP API): + //has to be set to 1 if movement is detected on the PIR that is the same side of the staircase as the ESP8266 + //has to be set to 2 if movement is detected on the PIR that is the opposite side + //can be set to 0 if no movement is detected. Otherwise LEDs will turn off after a configurable timeout (userVar1 seconds) + + if (userVar0 > 0) + { + if ((previousUserVar0 == 1 && userVar0 == 2) || (previousUserVar0 == 2 && userVar0 == 1)) wipeState = 3; //turn off if other PIR triggered + previousUserVar0 = userVar0; + + if (wipeState == 0) { + startWipe(); + wipeState = 1; + } else if (wipeState == 1) { //wiping + uint32_t cycleTime = 360 + (255 - effectSpeed)*75; //this is how long one wipe takes (minus 25 ms to make sure we switch in time) + if (millis() + strip.timebase > (cycleTime - 25)) { //wipe complete + effectCurrent = FX_MODE_STATIC; + timeStaticStart = millis(); + colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); + wipeState = 2; + } + } else if (wipeState == 2) { //static + if (userVar1 > 0) //if U1 is not set, the light will stay on until second PIR or external command is triggered + { + if (millis() - timeStaticStart > userVar1*1000) wipeState = 3; + } + } else if (wipeState == 3) { //switch to wipe off + #ifdef STAIRCASE_WIPE_OFF + effectCurrent = FX_MODE_COLOR_WIPE; + strip.timebase = 360 + (255 - effectSpeed)*75 - millis(); //make sure wipe starts fully lit + colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); + wipeState = 4; + #else + turnOff(); + #endif + } else { //wiping off + if (millis() + strip.timebase > (725 + (255 - effectSpeed)*150)) turnOff(); //wipe complete + } + } else { + wipeState = 0; //reset for next time + if (previousUserVar0) { + #ifdef STAIRCASE_WIPE_OFF + userVar0 = previousUserVar0; + wipeState = 3; + #else + turnOff(); + #endif + } + previousUserVar0 = 0; + } +} + + void readFromJsonState(JsonObject& root) + { + userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value + //if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!")); + } + + void addToConfig(JsonObject& root) + { + JsonObject top = root.createNestedObject("exampleUsermod"); + top["great"] = userVar0; //save this var persistently whenever settings are saved + } + + void readFromConfig(JsonObject& root) + { + JsonObject top = root["top"]; + userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot) + } + + uint16_t getId() + { + return USERMOD_ID_EXAMPLE; + } + + + void startWipe() + { + bri = briLast; //turn on + transitionDelayTemp = 0; //no transition + effectCurrent = FX_MODE_COLOR_WIPE; + resetTimebase(); //make sure wipe starts from beginning + + //set wipe direction + WS2812FX::Segment& seg = strip.getSegment(0); + bool doReverse = (userVar0 == 2); + seg.setOption(1, doReverse); + + colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); + } + + void turnOff() + { + #ifdef STAIRCASE_WIPE_OFF + transitionDelayTemp = 0; //turn off immediately after wipe completed + #else + transitionDelayTemp = 4000; //fade out slowly + #endif + bri = 0; + colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); + wipeState = 0; + userVar0 = 0; + previousUserVar0 = 0; + } + + + + //More methods can be added in the future, this example will then be extended. + //Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class! +};