Browse Source

garland: updates (#2412)

- Update README.md - add garland description
- Add new animation - Dolphins
mcspr-patch-1
DmitryBlinov 3 years ago
committed by GitHub
parent
commit
c1243fda31
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 237 additions and 22 deletions
  1. +6
    -0
      README.md
  2. +5
    -8
      code/espurna/garland.cpp
  3. +1
    -1
      code/espurna/garland/animations/anim_assemble.h
  4. +1
    -1
      code/espurna/garland/animations/anim_comets.h
  5. +118
    -0
      code/espurna/garland/animations/anim_dolphins.h
  6. +2
    -2
      code/espurna/garland/animations/anim_pixiedust.h
  7. +2
    -2
      code/espurna/garland/animations/anim_randcyc.h
  8. +1
    -1
      code/espurna/garland/animations/anim_run.h
  9. +92
    -0
      code/espurna/garland/animations/anim_salut.h
  10. +1
    -1
      code/espurna/garland/animations/anim_sparkr.h
  11. +3
    -3
      code/espurna/garland/animations/anim_spread.h
  12. +1
    -1
      code/espurna/garland/animations/anim_stars.h
  13. +2
    -2
      code/espurna/garland/animations/anim_start.h
  14. +2
    -0
      code/espurna/garland/scene.h

+ 6
- 0
README.md View File

@ -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) * 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) * Specific definitions for touch button devices (ESPurna Switch, Sonoff Touch & T1)
* Configuration stored in different flash sectors to prevent data loss and corruption * 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 ## Notices


+ 5
- 8
code/espurna/garland.cpp View File

@ -80,18 +80,15 @@ Palette pals[] = {
Palette("Lime", {0x51f000, 0x6fff00, 0x96ff00, 0xc9ff00, 0xf0ff00}), Palette("Lime", {0x51f000, 0x6fff00, 0x96ff00, 0xc9ff00, 0xf0ff00}),
// Pastel: Pastel Fruity Mixture // 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]); } constexpr size_t palsSize() { return sizeof(pals)/sizeof(pals[0]); }
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(GARLAND_LEDS, GARLAND_D_PIN, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel pixels = Adafruit_NeoPixel(GARLAND_LEDS, GARLAND_D_PIN, NEO_GRB + NEO_KHZ800);
Scene scene(&pixels); 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]); } 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() { void Anim::initSeq() {
for (int i = 0; i < numLeds; i++)
for (int i = 0; i < numLeds; ++i)
seq[i] = i; seq[i] = i;
} }
void Anim::shuffleSeq() { void Anim::shuffleSeq() {
for (int i = 0; i < numLeds; i++) {
for (int i = 0; i < numLeds; ++i) {
byte ind = (unsigned int)(rngb() * numLeds / 256); byte ind = (unsigned int)(rngb() * numLeds / 256);
if (ind != i) { if (ind != i) {
std::swap(seq[ind], seq[i]); std::swap(seq[ind], seq[i]);


+ 1
- 1
code/espurna/garland/animations/anim_assemble.h View File

@ -19,7 +19,7 @@ class AnimAssemble : public Anim {
} }
int p = 0; int p = 0;
for (int i = 0; i < numLeds; i++) {
for (int i = 0; i < numLeds; ++i) {
leds[i] = 0; leds[i] = 0;
Color c = palette->getCachedPalColor((byte)p); Color c = palette->getCachedPalColor((byte)p);
ledstmp[i] = c; ledstmp[i] = c;


+ 1
- 1
code/espurna/garland/animations/anim_comets.h View File

@ -19,7 +19,7 @@ class AnimComets : public Anim {
} }
void Run() override { 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) { for (auto& c : comets) {
int tail = c.head + c.len * -c.dir; int tail = c.head + c.len * -c.dir;


+ 118
- 0
code/espurna/garland/animations/anim_dolphins.h View File

@ -0,0 +1,118 @@
#if GARLAND_SUPPORT
#include <vector>
#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<Color> 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<Dolphin> dolphins;
};
#endif // GARLAND_SUPPORT

+ 2
- 2
code/espurna/garland/animations/anim_pixiedust.h View File

@ -27,7 +27,7 @@ class AnimPixieDust : public Anim {
void Run() override { void Run() override {
if (inc > 0) { if (inc > 0) {
for (int i = 0; i < numLeds; i++) {
for (int i = 0; i < numLeds; ++i) {
leds[i] = (i > phase) ? prevColor : curColor; leds[i] = (i > phase) ? prevColor : curColor;
glowForEachLed(i); glowForEachLed(i);
} }
@ -38,7 +38,7 @@ class AnimPixieDust : public Anim {
curColor = palette->getRndInterpColor(); curColor = palette->getRndInterpColor();
} }
} else { } else {
for (int i = 0; i < numLeds; i++) {
for (int i = 0; i < numLeds; ++i) {
leds[i] = (i < phase) ? prevColor : curColor; leds[i] = (i < phase) ? prevColor : curColor;
glowForEachLed(i); glowForEachLed(i);
} }


+ 2
- 2
code/espurna/garland/animations/anim_randcyc.h View File

@ -10,12 +10,12 @@ class AnimRandCyc : public Anim {
} }
void SetupImpl() override { void SetupImpl() override {
for (int i = 0; i < numLeds; i++)
for (int i = 0; i < numLeds; ++i)
seq[i] = rngb(); seq[i] = rngb();
} }
void Run() override { void Run() override {
for (int i = 0; i < numLeds; i++) {
for (int i = 0; i < numLeds; ++i) {
leds[i] = palette->getCachedPalColor(seq[i]); leds[i] = palette->getCachedPalColor(seq[i]);
seq[i] += rngb() >> 6; seq[i] += rngb() >> 6;
} }


+ 1
- 1
code/espurna/garland/animations/anim_run.h View File

@ -20,7 +20,7 @@ class AnimRun : public Anim {
void Run() override { void Run() override {
int p = pos; int p = pos;
for (int i = 0; i < numLeds; i++) {
for (int i = 0; i < numLeds; ++i) {
Color c = palette->getCachedPalColor((byte)p); Color c = palette->getCachedPalColor((byte)p);
leds[i] = c; leds[i] = c;


+ 92
- 0
code/espurna/garland/animations/anim_salut.h View File

@ -0,0 +1,92 @@
#if GARLAND_SUPPORT
#include <vector>
#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<Spark> 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<Shot> shots;
};
#endif // GARLAND_SUPPORT

+ 1
- 1
code/espurna/garland/animations/anim_sparkr.h View File

@ -21,7 +21,7 @@ class AnimSparkr : public Anim {
} }
void Run() override { void Run() override {
for (int i = 0; i < numLeds; i++) {
for (int i = 0; i < numLeds; ++i) {
byte pos = seq[i]; byte pos = seq[i];
leds[pos] = (i > phase) ? prevColor leds[pos] = (i > phase) ? prevColor


+ 3
- 3
code/espurna/garland/animations/anim_spread.h View File

@ -35,15 +35,15 @@ class AnimSpread : public Anim {
void SetupImpl() override { void SetupImpl() override {
inc = secureRandom(2, 4); inc = secureRandom(2, 4);
// DEBUG_MSG_P(PSTR("[GARLAND] AnimSpread inc = %d\n"), inc); // 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; seq[i] = 0;
} }
void Run() override { void Run() override {
for (int i = 0; i < numLeds; i++)
for (int i = 0; i < numLeds; ++i)
leds[i] = 0; leds[i] = 0;
for (int i = 0; i < numLeds; i++) {
for (int i = 0; i < numLeds; ++i) {
if (seq[i] > 0) { if (seq[i] > 0) {
byte width = maxWidth - seq[i]; byte width = maxWidth - seq[i];
for (int j = i - width; j <= (i + width); j++) { for (int j = i - width; j <= (i + width); j++) {


+ 1
- 1
code/espurna/garland/animations/anim_stars.h View File

@ -18,7 +18,7 @@ class AnimStars : public Anim {
inc = secureRandom(2, 5); inc = secureRandom(2, 5);
//reset all phases //reset all phases
for (int i = 0; i < numLeds; i++)
for (int i = 0; i < numLeds; ++i)
seq[i] = 255; seq[i] = 255;
} }


+ 2
- 2
code/espurna/garland/animations/anim_start.h View File

@ -17,11 +17,11 @@ class AnimStart : public Anim {
leds[phase].r = 255; leds[phase].r = 255;
leds[phase].g = 255; leds[phase].g = 255;
leds[phase].b = 255; leds[phase].b = 255;
for (int i = 0; i < numLeds; i++) {
for (int i = 0; i < numLeds; ++i) {
leds[i].fade(50); leds[i].fade(50);
} }
} else if (phase >= numLeds) { } else if (phase >= numLeds) {
for (int i = 0; i < numLeds; i++) {
for (int i = 0; i < numLeds; ++i) {
short r = numLeds + 255 - phase + rngb(); short r = numLeds + 255 - phase + rngb();
r = min(r, (short)255); r = min(r, (short)255);
leds[i].r = (byte)max(r, (short)0); leds[i].r = (byte)max(r, (short)0);


+ 2
- 0
code/espurna/garland/scene.h View File

@ -15,10 +15,12 @@ Inspired by https://github.com/Vasil-Pahomov/ArWs2812 (currently https://github.
#include "anim.h" #include "anim.h"
#include "animations/anim_assemble.h" #include "animations/anim_assemble.h"
#include "animations/anim_comets.h" #include "animations/anim_comets.h"
#include "animations/anim_dolphins.h"
#include "animations/anim_fly.h" #include "animations/anim_fly.h"
#include "animations/anim_pixiedust.h" #include "animations/anim_pixiedust.h"
#include "animations/anim_randcyc.h" #include "animations/anim_randcyc.h"
#include "animations/anim_run.h" #include "animations/anim_run.h"
#include "animations/anim_salut.h"
#include "animations/anim_sparkr.h" #include "animations/anim_sparkr.h"
#include "animations/anim_spread.h" #include "animations/anim_spread.h"
#include "animations/anim_stars.h" #include "animations/anim_stars.h"


Loading…
Cancel
Save