Browse Source

garland: animation improvements

- add hidden animation Glow for one color glowing
- implement one color Palette for mqtt controlled animation.
mcspr-patch-1
DmitryBlinov 3 years ago
committed by Maxim Prokhorov
parent
commit
4923377eac
3 changed files with 89 additions and 37 deletions
  1. +54
    -37
      code/espurna/garland.cpp
  2. +34
    -0
      code/espurna/garland/animations/anim_glow.h
  3. +1
    -0
      code/espurna/garland/scene.h

+ 54
- 37
code/espurna/garland.cpp View File

@ -27,6 +27,7 @@ MQTT control:
#include <Adafruit_NeoPixel.h> #include <Adafruit_NeoPixel.h>
#include <memory>
#include <vector> #include <vector>
#include "garland/color.h" #include "garland/color.h"
@ -66,9 +67,7 @@ const char* MQTT_COMMAND_SEQUENCE = "sequence"; // place command to sequen
bool _garland_enabled = true; bool _garland_enabled = true;
unsigned long _lastTimeUpdate = 0; unsigned long _lastTimeUpdate = 0;
unsigned long _currentAnimDuration = ULONG_MAX;
unsigned int _currentAnimInd = 0;
unsigned int _currentPaletteInd = 0;
unsigned long _currentDuration = ULONG_MAX;
unsigned int _currentCommandInSequence = 0; unsigned int _currentCommandInSequence = 0;
String _immediate_command; String _immediate_command;
std::queue<String> _command_queue; std::queue<String> _command_queue;
@ -117,11 +116,15 @@ 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(),
Anim* anims[] = {new AnimGlow(), new AnimStart(), new AnimPixieDust(), new AnimSparkr(), new AnimRun(), new AnimStars(), new AnimSpread(),
new AnimRandCyc(), new AnimFly(), new AnimComets(), new AnimAssemble(), new AnimDolphins(), new AnimSalut()}; 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]); }
#define START_ANIMATION 1
Anim* _currentAnim = anims[1];
Palette* _currentPalette = &pals[0];
auto one_color_palette = std::unique_ptr<Palette>(new Palette("White", {0xffffff}));
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void garlandDisable() { void garlandDisable() {
pixels.clear(); pixels.clear();
@ -233,28 +236,27 @@ void _garlandWebSocketOnAction(uint32_t client_id, const char* action, JsonObjec
#endif #endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void setupScene(unsigned int anim_ind, unsigned int palette_ind, unsigned long duration) {
void setupScene(Anim* new_anim, Palette* new_palette, unsigned long new_duration) {
unsigned long currentAnimRunTime = millis() - _lastTimeUpdate; unsigned long currentAnimRunTime = millis() - _lastTimeUpdate;
_lastTimeUpdate = millis(); _lastTimeUpdate = millis();
_currentAnimDuration = duration;
int prevAnimInd = _currentAnimInd;
_currentAnimInd = anim_ind;
int prevPalInd = _currentPaletteInd;
_currentPaletteInd = palette_ind;
int numShows = scene.getNumShows(); int numShows = scene.getNumShows();
int frameRate = currentAnimRunTime > 0 ? numShows * 1000 / currentAnimRunTime : 0; int frameRate = currentAnimRunTime > 0 ? numShows * 1000 / currentAnimRunTime : 0;
static String palette_name = "Start";
DEBUG_MSG_P(PSTR("[GARLAND] Anim: %-10s Pal: %-8s timings: calc: %4d pixl: %3d show: %4d frate: %d\n"), DEBUG_MSG_P(PSTR("[GARLAND] Anim: %-10s Pal: %-8s timings: calc: %4d pixl: %3d show: %4d frate: %d\n"),
anims[prevAnimInd]->name(), pals[prevPalInd].name(),
_currentAnim->name(), palette_name.c_str(),
scene.getAvgCalcTime(), scene.getAvgPixlTime(), scene.getAvgShowTime(), frameRate); scene.getAvgCalcTime(), scene.getAvgPixlTime(), scene.getAvgShowTime(), frameRate);
_currentDuration = new_duration;
_currentAnim = new_anim;
_currentPalette = new_palette;
palette_name = _currentPalette->name();
DEBUG_MSG_P(PSTR("[GARLAND] Anim: %-10s Pal: %-8s Inter: %d\n"), DEBUG_MSG_P(PSTR("[GARLAND] Anim: %-10s Pal: %-8s Inter: %d\n"),
anims[_currentAnimInd]->name(), pals[_currentPaletteInd].name(), _currentAnimDuration);
_currentAnim->name(), palette_name.c_str(), _currentDuration);
scene.setAnim(anims[_currentAnimInd]);
scene.setPalette(&pals[_currentPaletteInd]);
scene.setAnim(_currentAnim);
scene.setPalette(_currentPalette);
scene.setup(); scene.setup();
} }
@ -286,28 +288,42 @@ bool executeCommand(const String& command) {
scene.setSpeed(speed); scene.setSpeed(speed);
} }
unsigned int newAnimInd = _currentAnimInd;
Anim* newAnim = _currentAnim;
if (root.containsKey(MQTT_PAYLOAD_ANIMATION)) { if (root.containsKey(MQTT_PAYLOAD_ANIMATION)) {
auto animation = root[MQTT_PAYLOAD_ANIMATION].as<const char*>(); auto animation = root[MQTT_PAYLOAD_ANIMATION].as<const char*>();
for (size_t i = 0; i < animsSize(); ++i) { for (size_t i = 0; i < animsSize(); ++i) {
auto anim_name = anims[i]->name(); auto anim_name = anims[i]->name();
if (strcmp(animation, anim_name) == 0) { if (strcmp(animation, anim_name) == 0) {
newAnimInd = i;
newAnim = anims[i];
scene_setup_required = true; scene_setup_required = true;
break; break;
} }
} }
} }
unsigned int newPalInd = _currentPaletteInd;
Palette* newPalette = _currentPalette;
if (root.containsKey(MQTT_PAYLOAD_PALETTE)) { if (root.containsKey(MQTT_PAYLOAD_PALETTE)) {
auto palette = root[MQTT_PAYLOAD_PALETTE].as<const char*>();
for (size_t i = 0; i < palsSize(); ++i) {
auto pal_name = pals[i].name();
if (strcmp(palette, pal_name) == 0) {
newPalInd = i;
scene_setup_required = true;
break;
if (root.is<int>(MQTT_PAYLOAD_PALETTE)) {
one_color_palette.reset(new Palette("Color", {root[MQTT_PAYLOAD_PALETTE].as<uint32_t>()}));
newPalette = one_color_palette.get();
} else {
auto palette = root[MQTT_PAYLOAD_PALETTE].as<const char*>();
bool palette_found = false;
for (size_t i = 0; i < palsSize(); ++i) {
auto pal_name = pals[i].name();
if (strcmp(palette, pal_name) == 0) {
newPalette = &pals[i];
palette_found = true;
scene_setup_required = true;
break;
}
}
if (!palette_found) {
uint32_t color = (uint32_t)strtoul(palette, NULL, 0);
if (color != 0) {
one_color_palette.reset(new Palette("Color", {color}));
newPalette = one_color_palette.get();
}
} }
} }
} }
@ -320,7 +336,7 @@ bool executeCommand(const String& command) {
if (scene_setup_required) { if (scene_setup_required) {
setupScene(newAnimInd, newPalInd, newAnimDuration);
setupScene(newAnim, newPalette, newAnimDuration);
return true; return true;
} }
return false; return false;
@ -341,7 +357,7 @@ void garlandLoop(void) {
scene.run(); scene.run();
unsigned long currentAnimRunTime = millis() - _lastTimeUpdate; unsigned long currentAnimRunTime = millis() - _lastTimeUpdate;
if (currentAnimRunTime > _currentAnimDuration && scene.finishedAnimCycle()) {
if (currentAnimRunTime > _currentDuration && scene.finishedAnimCycle()) {
bool scene_setup_done = false; bool scene_setup_done = false;
if (!_command_queue.empty()) { if (!_command_queue.empty()) {
scene_setup_done = executeCommand(_command_queue.front()); scene_setup_done = executeCommand(_command_queue.front());
@ -354,15 +370,16 @@ void garlandLoop(void) {
} }
if (!scene_setup_done) { if (!scene_setup_done) {
unsigned int newAnimInd = _currentAnimInd;
while (newAnimInd == _currentAnimInd) newAnimInd = secureRandom(1, animsSize());
Anim* newAnim = _currentAnim;
while (newAnim == _currentAnim) newAnim = anims[secureRandom(START_ANIMATION + 1, animsSize())];
unsigned int newPalInd = _currentPaletteInd;
while (newPalInd == _currentPaletteInd) newPalInd = secureRandom(palsSize());
Palette* newPalette = _currentPalette;
while (newPalette == _currentPalette)
newPalette = &pals[secureRandom(palsSize())];
unsigned long newAnimDuration = secureRandom(EFFECT_UPDATE_INTERVAL_MIN, EFFECT_UPDATE_INTERVAL_MAX); unsigned long newAnimDuration = secureRandom(EFFECT_UPDATE_INTERVAL_MIN, EFFECT_UPDATE_INTERVAL_MAX);
setupScene(newAnimInd, newPalInd, newAnimDuration);
setupScene(newAnim, newPalette, newAnimDuration);
} }
} }
} }
@ -399,7 +416,7 @@ void garlandMqttCallback(unsigned int type, const char * topic, const char * pay
std::vector<String> empty_sequence; std::vector<String> empty_sequence;
std::swap(_command_sequence, empty_sequence); std::swap(_command_sequence, empty_sequence);
_immediate_command.clear(); _immediate_command.clear();
_currentAnimDuration = 0;
_currentDuration = 0;
setDefault(); setDefault();
garlandEnabled(true); garlandEnabled(true);
} else if (command == MQTT_COMMAND_QUEUE) { } else if (command == MQTT_COMMAND_QUEUE) {
@ -428,11 +445,11 @@ void garlandSetup() {
espurnaRegisterReload(_garlandReload); espurnaRegisterReload(_garlandReload);
pixels.begin(); pixels.begin();
scene.setAnim(anims[0]);
scene.setPalette(&pals[0]);
scene.setAnim(_currentAnim);
scene.setPalette(_currentPalette);
scene.setup(); scene.setup();
_currentAnimDuration = secureRandom(EFFECT_UPDATE_INTERVAL_MIN, EFFECT_UPDATE_INTERVAL_MAX);
_currentDuration = secureRandom(EFFECT_UPDATE_INTERVAL_MIN, EFFECT_UPDATE_INTERVAL_MAX);
} }
/*####################################################################### /*#######################################################################


+ 34
- 0
code/espurna/garland/animations/anim_glow.h View File

@ -0,0 +1,34 @@
#if GARLAND_SUPPORT
#include "../anim.h"
#include "../palette.h"
//------------------------------------------------------------------------------
class AnimGlow : public Anim {
public:
AnimGlow() : Anim("Glow") {
}
void SetupImpl() override {
curColor = palette->getRndInterpColor();
inc = secureRandom(2) * 2 - 1;
glowSetUp();
}
void Run() override {
if (inc > 0) {
for (int i = 0; i < numLeds; ++i) {
leds[i] = curColor;
glowForEachLed(i);
}
} else {
for (int i = 0; i < numLeds; ++i) {
leds[i] = curColor;
glowForEachLed(i);
}
}
glowRun();
}
};
#endif // GARLAND_SUPPORT

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

@ -17,6 +17,7 @@ Inspired by https://github.com/Vasil-Pahomov/ArWs2812 (currently https://github.
#include "animations/anim_comets.h" #include "animations/anim_comets.h"
#include "animations/anim_dolphins.h" #include "animations/anim_dolphins.h"
#include "animations/anim_fly.h" #include "animations/anim_fly.h"
#include "animations/anim_glow.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"


Loading…
Cancel
Save