From c1243fda310aca0ca4e5c335f94e5d45ee351d06 Mon Sep 17 00:00:00 2001 From: DmitryBlinov Date: Thu, 14 Jan 2021 09:36:32 +0200 Subject: [PATCH] garland: updates (#2412) - Update README.md - add garland description - Add new animation - Dolphins --- README.md | 6 + code/espurna/garland.cpp | 13 +- .../garland/animations/anim_assemble.h | 2 +- code/espurna/garland/animations/anim_comets.h | 2 +- .../garland/animations/anim_dolphins.h | 118 ++++++++++++++++++ .../garland/animations/anim_pixiedust.h | 4 +- .../espurna/garland/animations/anim_randcyc.h | 4 +- code/espurna/garland/animations/anim_run.h | 2 +- code/espurna/garland/animations/anim_salut.h | 92 ++++++++++++++ code/espurna/garland/animations/anim_sparkr.h | 2 +- code/espurna/garland/animations/anim_spread.h | 6 +- code/espurna/garland/animations/anim_stars.h | 2 +- code/espurna/garland/animations/anim_start.h | 4 +- code/espurna/garland/scene.h | 2 + 14 files changed, 237 insertions(+), 22 deletions(-) create mode 100644 code/espurna/garland/animations/anim_dolphins.h create mode 100644 code/espurna/garland/animations/anim_salut.h diff --git a/README.md b/README.md index 8a0fdc4a..f76fa9a1 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,12 @@ Since November 2018, Max Prokhorov (**@mcspr**) is also actively working as a co * Extra long click (>10 seconds) to go back to factory settings (only main button) * Specific definitions for touch button devices (ESPurna Switch, Sonoff Touch & T1) * Configuration stored in different flash sectors to prevent data loss and corruption +* **Garland** Implementing garland using WS2812 leds + * 12 animation modes (include start animation) + * Web control for: + * ON/OFF + * brightness + * speed ## Notices diff --git a/code/espurna/garland.cpp b/code/espurna/garland.cpp index faae1663..2d46c7ef 100644 --- a/code/espurna/garland.cpp +++ b/code/espurna/garland.cpp @@ -80,18 +80,15 @@ Palette pals[] = { Palette("Lime", {0x51f000, 0x6fff00, 0x96ff00, 0xc9ff00, 0xf0ff00}), // Pastel: Pastel Fruity Mixture - Palette("Pastel", {0x75aa68, 0x5960ae, 0xe4be6c, 0xca5959, 0x8366ac}), - - // Green: Vibrant greens - Palette("Green", {0x89ff01, 0x42c501, 0x349404, 0x0f6902, 0x004208})}; + Palette("Pastel", {0x75aa68, 0x5960ae, 0xe4be6c, 0xca5959, 0x8366ac})}; constexpr size_t palsSize() { return sizeof(pals)/sizeof(pals[0]); } Adafruit_NeoPixel pixels = Adafruit_NeoPixel(GARLAND_LEDS, GARLAND_D_PIN, NEO_GRB + NEO_KHZ800); Scene scene(&pixels); -Anim* anims[] = {new AnimStart(), new AnimPixieDust(), new AnimSparkr(), new AnimRun(), new AnimStars(), - new AnimSpread(), new AnimRandCyc(), new AnimFly(), new AnimComets(), new AnimAssemble()}; +Anim* anims[] = {new AnimStart(), new AnimPixieDust(), new AnimSparkr(), new AnimRun(), new AnimStars(), new AnimSpread(), + new AnimRandCyc(), new AnimFly(), new AnimComets(), new AnimAssemble(), new AnimDolphins(), new AnimSalut()}; constexpr size_t animsSize() { return sizeof(anims)/sizeof(anims[0]); } @@ -434,12 +431,12 @@ void Anim::Setup(Palette* palette, uint16_t numLeds, Color* leds, Color* ledstmp } void Anim::initSeq() { - for (int i = 0; i < numLeds; i++) + for (int i = 0; i < numLeds; ++i) seq[i] = i; } void Anim::shuffleSeq() { - for (int i = 0; i < numLeds; i++) { + for (int i = 0; i < numLeds; ++i) { byte ind = (unsigned int)(rngb() * numLeds / 256); if (ind != i) { std::swap(seq[ind], seq[i]); diff --git a/code/espurna/garland/animations/anim_assemble.h b/code/espurna/garland/animations/anim_assemble.h index 74865b4f..9262bdc3 100644 --- a/code/espurna/garland/animations/anim_assemble.h +++ b/code/espurna/garland/animations/anim_assemble.h @@ -19,7 +19,7 @@ class AnimAssemble : public Anim { } int p = 0; - for (int i = 0; i < numLeds; i++) { + for (int i = 0; i < numLeds; ++i) { leds[i] = 0; Color c = palette->getCachedPalColor((byte)p); ledstmp[i] = c; diff --git a/code/espurna/garland/animations/anim_comets.h b/code/espurna/garland/animations/anim_comets.h index 21bfb93d..96dd8168 100644 --- a/code/espurna/garland/animations/anim_comets.h +++ b/code/espurna/garland/animations/anim_comets.h @@ -19,7 +19,7 @@ class AnimComets : public Anim { } void Run() override { - for (int i = 0; i < numLeds; i++) leds[i] = 0; + for (int i = 0; i < numLeds; ++i) leds[i] = 0; for (auto& c : comets) { int tail = c.head + c.len * -c.dir; diff --git a/code/espurna/garland/animations/anim_dolphins.h b/code/espurna/garland/animations/anim_dolphins.h new file mode 100644 index 00000000..5c083bef --- /dev/null +++ b/code/espurna/garland/animations/anim_dolphins.h @@ -0,0 +1,118 @@ +#if GARLAND_SUPPORT + +#include + +#include "../anim.h" +#include "../color.h" +#include "../palette.h" + +//------------------------------------------------------------------------------ +class AnimDolphins : public Anim { + public: + AnimDolphins() : Anim("Dolphins") { + cycleFactor = 3; + } + + void SetupImpl() override { + dolphins.clear(); + for (int i = 0; i < 4; ++i) + dolphins.emplace_back(palette, numLeds); + } + + void Run() override { + for (int i = 0; i < numLeds; ++i) { + leds[i] = 0; + seq[i] = 0; + } + + // Run dolphins animation. Fill seq (accupied space) + for (auto& d : dolphins) + d.Run(leds, seq); + + // Try to recreate dolphins that have been done + for (auto& d : dolphins) { + if (d.done) { + for (int i = 1; i < 5; ++i) { + Dolphin new_dolphin(palette, numLeds); + if (new_dolphin.HaveEnoughSpace(seq)) { + std::swap(d, new_dolphin); + break; + } + } + } + } + } + + private: + struct Dolphin { + bool done = false; + int len = secureRandom(10, 20); + int speed = secureRandom(1, 3); + int dir = 1; + int head = 0; + int start; + Color color; + std::vector points; + Dolphin(Palette* pal, uint16_t numLeds) : start(secureRandom(0, numLeds - len)), color(pal->getRndInterpColor()), points(len) { + // DEBUG_MSG_P(PSTR("[GARLAND] Dolphin created start = %d len = %d dir = %d cr = %d cg = %d cb = %d\n"), start, len, dir, color.r, color.g, color.b); + if (secureRandom(10) > 5) { + start = numLeds - start; + dir = -1; + } + + int halflen = len / 2; + for (int i = 0; i < halflen; ++i) { + points[i] = points[len-i-1] = Color((byte)(color.r * i / halflen), (byte)(color.g * i / halflen), (byte)(color.b * i / halflen)); + // DEBUG_MSG_P(PSTR("[GARLAND] Dolphin i=%d cr = %d cg = %d cb = %d\n"), i, points[i].r, points[i].g, points[i].b); + } + if (len > halflen * 2) { + points[halflen] = color; + } + } + + bool Run(Color* leds, byte* seq) { + if (done) + return false; + + int p = 0; + for (int i = 0; i < len; ++i) { + p = head - i; + if (p >= 0 && p < len) { + leds[start + p * dir] = points[i]; + } + } + + head += speed; + + // if tail moved out of len then dolphin is done + if (p >= len) { + done = true; + return false; + } + else { + // dolphin accupy space for future movement + int s = p < 0 ? 0 : p; + for (int i = s; i < len; ++i) { + seq[start + i * dir] = 1; + } + } + + return true; + } + + // Decide that dolphin have ehough space if seq of len before it is empty + bool HaveEnoughSpace(byte* seq) { + for (int i = 0; i < len; ++i) { + if (seq[start + i * dir] != 0) { + // DEBUG_MSG_P(PSTR("[GARLAND] Dolphin chaven't enouhg space to move.\n")); + return false; + } + } + return true; + } + }; + + std::vector dolphins; +}; + +#endif // GARLAND_SUPPORT diff --git a/code/espurna/garland/animations/anim_pixiedust.h b/code/espurna/garland/animations/anim_pixiedust.h index 02c88b8e..c33fa1d8 100644 --- a/code/espurna/garland/animations/anim_pixiedust.h +++ b/code/espurna/garland/animations/anim_pixiedust.h @@ -27,7 +27,7 @@ class AnimPixieDust : public Anim { void Run() override { if (inc > 0) { - for (int i = 0; i < numLeds; i++) { + for (int i = 0; i < numLeds; ++i) { leds[i] = (i > phase) ? prevColor : curColor; glowForEachLed(i); } @@ -38,7 +38,7 @@ class AnimPixieDust : public Anim { curColor = palette->getRndInterpColor(); } } else { - for (int i = 0; i < numLeds; i++) { + for (int i = 0; i < numLeds; ++i) { leds[i] = (i < phase) ? prevColor : curColor; glowForEachLed(i); } diff --git a/code/espurna/garland/animations/anim_randcyc.h b/code/espurna/garland/animations/anim_randcyc.h index 50b89f31..2463d854 100644 --- a/code/espurna/garland/animations/anim_randcyc.h +++ b/code/espurna/garland/animations/anim_randcyc.h @@ -10,12 +10,12 @@ class AnimRandCyc : public Anim { } void SetupImpl() override { - for (int i = 0; i < numLeds; i++) + for (int i = 0; i < numLeds; ++i) seq[i] = rngb(); } void Run() override { - for (int i = 0; i < numLeds; i++) { + for (int i = 0; i < numLeds; ++i) { leds[i] = palette->getCachedPalColor(seq[i]); seq[i] += rngb() >> 6; } diff --git a/code/espurna/garland/animations/anim_run.h b/code/espurna/garland/animations/anim_run.h index 93631e36..d3c21920 100644 --- a/code/espurna/garland/animations/anim_run.h +++ b/code/espurna/garland/animations/anim_run.h @@ -20,7 +20,7 @@ class AnimRun : public Anim { void Run() override { int p = pos; - for (int i = 0; i < numLeds; i++) { + for (int i = 0; i < numLeds; ++i) { Color c = palette->getCachedPalColor((byte)p); leds[i] = c; diff --git a/code/espurna/garland/animations/anim_salut.h b/code/espurna/garland/animations/anim_salut.h new file mode 100644 index 00000000..0e8e3865 --- /dev/null +++ b/code/espurna/garland/animations/anim_salut.h @@ -0,0 +1,92 @@ +#if GARLAND_SUPPORT + +#include + +#include "../anim.h" +#include "../color.h" +#include "../palette.h" + +//------------------------------------------------------------------------------ +class AnimSalut : public Anim { + public: + AnimSalut() : Anim("Salut") { + } + + void SetupImpl() override { + shots.clear(); + // There can be more then one shot at the moment + // but looks like one is enough + // for (int i = 0; i < 3; ++i) + shots.emplace_back(palette, numLeds); + } + + void Run() override { + for (int i = 0; i < numLeds; ++i) leds[i] = 0; + + for (auto& c : shots) { + if (!c.Run(leds)) { + Shot new_shot(palette, numLeds); + std::swap(c, new_shot); + } + } + } + + private: + struct Shot { + private: + struct Spark { + bool done = false; + float speed = ((float)secureRandom(1, 25)) / 10; + float speed_dec = ((float)secureRandom(1, 3)) / 10; + float pos; + int dir; + Color color; + uint16_t numLeds; + Spark(int pos, Palette* pal, uint16_t numLeds) : pos(pos), dir(secureRandom(10) > 5 ? -1 : 1), color(pal->getRndInterpColor()), numLeds(numLeds) {} + void Run(Color* leds) { + if (pos >= 0 && pos < numLeds) { + leds[(int)pos] = color; + if (speed > 0) { + pos += speed * dir; + speed -= speed_dec; + } else { + color.fade(5); + if (color.empty()) { + if (secureRandom(10) > 8) + leds[(int)pos] = 0xFFFFFF; + done = true; + } + } + } else { + done = true; + } + } + }; + + public: + int spark_num = secureRandom(30, 40); + int center; + std::vector sparks; + Shot(Palette* pal, uint16_t numLeds) : center(secureRandom(15, numLeds - 15)) { + // DEBUG_MSG_P(PSTR("[GARLAND] Shot created center = %d spark_num = %d\n"), center, spark_num); + sparks.reserve(spark_num); + for (int i = 0; i < spark_num; ++i) { + sparks.emplace_back(center, pal, numLeds); + } + } + bool Run(Color* leds) { + bool done = true; + for (auto& s : sparks) { + if (!s.done) { + done = false; + s.Run(leds); + } + } + return !done; + } + }; + + std::vector shots; +}; + +#endif // GARLAND_SUPPORT diff --git a/code/espurna/garland/animations/anim_sparkr.h b/code/espurna/garland/animations/anim_sparkr.h index 75babbc7..93bb9c8d 100644 --- a/code/espurna/garland/animations/anim_sparkr.h +++ b/code/espurna/garland/animations/anim_sparkr.h @@ -21,7 +21,7 @@ class AnimSparkr : public Anim { } void Run() override { - for (int i = 0; i < numLeds; i++) { + for (int i = 0; i < numLeds; ++i) { byte pos = seq[i]; leds[pos] = (i > phase) ? prevColor diff --git a/code/espurna/garland/animations/anim_spread.h b/code/espurna/garland/animations/anim_spread.h index 4606164c..38962182 100644 --- a/code/espurna/garland/animations/anim_spread.h +++ b/code/espurna/garland/animations/anim_spread.h @@ -35,15 +35,15 @@ class AnimSpread : public Anim { void SetupImpl() override { inc = secureRandom(2, 4); // DEBUG_MSG_P(PSTR("[GARLAND] AnimSpread inc = %d\n"), inc); - for (int i = 0; i < numLeds; i++) + for (int i = 0; i < numLeds; ++i) seq[i] = 0; } void Run() override { - for (int i = 0; i < numLeds; i++) + for (int i = 0; i < numLeds; ++i) leds[i] = 0; - for (int i = 0; i < numLeds; i++) { + for (int i = 0; i < numLeds; ++i) { if (seq[i] > 0) { byte width = maxWidth - seq[i]; for (int j = i - width; j <= (i + width); j++) { diff --git a/code/espurna/garland/animations/anim_stars.h b/code/espurna/garland/animations/anim_stars.h index c7c342a9..91f8eb28 100644 --- a/code/espurna/garland/animations/anim_stars.h +++ b/code/espurna/garland/animations/anim_stars.h @@ -18,7 +18,7 @@ class AnimStars : public Anim { inc = secureRandom(2, 5); //reset all phases - for (int i = 0; i < numLeds; i++) + for (int i = 0; i < numLeds; ++i) seq[i] = 255; } diff --git a/code/espurna/garland/animations/anim_start.h b/code/espurna/garland/animations/anim_start.h index c6fdaff7..c3f0ceea 100644 --- a/code/espurna/garland/animations/anim_start.h +++ b/code/espurna/garland/animations/anim_start.h @@ -17,11 +17,11 @@ class AnimStart : public Anim { leds[phase].r = 255; leds[phase].g = 255; leds[phase].b = 255; - for (int i = 0; i < numLeds; i++) { + for (int i = 0; i < numLeds; ++i) { leds[i].fade(50); } } else if (phase >= numLeds) { - for (int i = 0; i < numLeds; i++) { + for (int i = 0; i < numLeds; ++i) { short r = numLeds + 255 - phase + rngb(); r = min(r, (short)255); leds[i].r = (byte)max(r, (short)0); diff --git a/code/espurna/garland/scene.h b/code/espurna/garland/scene.h index fe244b0e..7e2630d1 100644 --- a/code/espurna/garland/scene.h +++ b/code/espurna/garland/scene.h @@ -15,10 +15,12 @@ Inspired by https://github.com/Vasil-Pahomov/ArWs2812 (currently https://github. #include "anim.h" #include "animations/anim_assemble.h" #include "animations/anim_comets.h" +#include "animations/anim_dolphins.h" #include "animations/anim_fly.h" #include "animations/anim_pixiedust.h" #include "animations/anim_randcyc.h" #include "animations/anim_run.h" +#include "animations/anim_salut.h" #include "animations/anim_sparkr.h" #include "animations/anim_spread.h" #include "animations/anim_stars.h"