Compare commits

...

12 Commits

Author SHA1 Message Date
5b70511570 Added options to config.sample.h
Some checks failed
continuous-integration/drone/push Build is failing
2019-06-19 22:31:11 +02:00
77fdba213a I'm tired and forgot to add two files to previous commits. :-/ 2019-06-19 22:29:11 +02:00
ead076f9a3 You can now set options for effects via MQTT and HTTP. Basic syntax is: <mode>,<option1>=<value1>,<option2>=<value2>,... 2019-06-19 22:28:38 +02:00
82fbc7be43 MQTT: Small fixes. Most notably, MQTT_TOPIC/status will now contain hostname and IP of pitrix. 2019-06-19 22:27:33 +02:00
90c0df093e New Effect: BigDynamicEffect. 2019-06-19 22:26:52 +02:00
26df11fc47 Added tests. Start them by sending a message to MQTT_TOPIC/run_tests. First test will test all effects for memory leaks. 2019-06-19 22:26:38 +02:00
0163bbef6c Some memory leaks fixed. 2019-06-19 22:23:49 +02:00
9eeb4b50fd Missed a patch for the previous commit. 2019-06-19 22:22:37 +02:00
d2c0268dce MatrixEffect can now have multiple columns in the same column. In RandomMatrix, they even run in all directions. 2019-06-19 22:22:03 +02:00
e897c6bdcd New Effect: DvdEffect 2019-06-19 22:17:39 +02:00
f1821b0b85 New Effect: RandomConfettiEffect 2019-06-19 22:17:10 +02:00
41af01ee0b Better handling of Animations, their members and the destructor. 2019-06-19 22:16:06 +02:00
29 changed files with 381 additions and 102 deletions

View File

@ -41,7 +41,7 @@ protected:
unsigned long currentFrameSince;
uint8_t currentFrame = 0;
uint8_t* animation_data;
CRGB** _colors;
CRGB** _colors = NULL;
CRGB* fgColor = NULL;
CRGB* bgColor = new CRGB(0x000000);
int8_t xOffset = 0;
@ -51,22 +51,22 @@ protected:
Window* _window;
uint8_t _width;
uint8_t _height;
uint8_t _frame_count;
uint8_t _color_count;
uint16_t* _frame_times;
uint16_t* _frame_data_lengths;
uint8_t** _frame_data;
uint8_t _frame_count = 0;
uint8_t _color_count = 0;
uint16_t* _frame_times = NULL;
uint16_t* _frame_data_lengths = NULL;
uint8_t** _frame_data = NULL;
bool _data_valid = false;
virtual CRGB* getColor(uint8_t color_index);
void drawPixel(int index, CRGB* color);
uint16_t getFrameDelay(int frame);
bool _load_from_file(const char* c);
public:
Animation(const char* filename, Window* win);
void setFgColor(CRGB*);
void setBgColor(CRGB* bg_color);
void setFgColor(uint32_t c);
void setBgColor(uint32_t c);
bool invert();
void setOffsets(int8_t x, int8_t y);
void setStartFrame(uint8_t sf);

View File

@ -17,6 +17,7 @@ public:
void setWindow(Window* win) {
window = win;
};
virtual void apply_option(String key, String value) {};
};
#endif

View File

@ -9,7 +9,7 @@ public:
const uint8_t width, height;
uint16_t count;
static Window* getFullWindow();
Window(): Window(0, 0, LED_WIDTH, LED_HEIGHT) {};
Window(uint8_t x, uint8_t y) : Window(x, y, LED_WIDTH-x, LED_HEIGHT-y) {};
Window(uint8_t x, uint8_t y, uint8_t width, uint8_t height) : x(x), y(y), width(width), height(height) { count = width*height; };
@ -18,6 +18,7 @@ public:
void clear(CRGB* color);
void setPixel(uint8_t x, uint8_t y, CRGB* color);
void setPixelByIndex(uint16_t index, CRGB* color);
void raisePixel(uint8_t x, uint8_t y, CRGB* color);
void line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, CRGB* color);
void lineWithAngle(uint8_t x, uint8_t y, uint8_t angle, uint8_t length, CRGB* color);
void lineWithAngle(uint8_t x, uint8_t y, uint8_t angle, uint8_t startdist, uint8_t length, CRGB* color);

View File

@ -56,6 +56,8 @@
#define EFFECT_SINGLE_DYNAMIC_LOOP_TIME 40
#define EFFECT_MULTI_DYNAMIC_LOOP_TIME 1400
#define EFFECT_BIG_DYNAMIC_LOOP_TIME 50
#define EFFECT_BIG_DYNAMIC_SIZE 3
#define EFFECT_CONFETTI_PIXELS_PER_LOOP 2
@ -73,6 +75,9 @@
#define EFFECT_GOL_BLEND_SPEED 10
#define EFFECT_GOL_RESTART_AFTER_STEPS 100
#define EFFECT_DVD_WIDTH 3
#define EFFECT_DVD_HEIGHT 2
// Stop editing here
#ifdef DEBUG

View File

@ -8,13 +8,13 @@
class AnimationEffect : public Effect {
private:
Animation *animation;
CRGB *bg_color;
uint16_t xOffset;
uint16_t yOffset;
public:
AnimationEffect(const char* name) : AnimationEffect(name, new CRGB(0x000000), 0, 0) {}
AnimationEffect(const char* name, CRGB* background_color) : AnimationEffect(name, background_color, 0, 0) {}
AnimationEffect(const char* name, CRGB* bg_color, int x, int y);
AnimationEffect(const char* name) : AnimationEffect(name, 0x000000, 0, 0) {}
AnimationEffect(const char* name, uint32_t bg_color) : AnimationEffect(name, bg_color, 0, 0) {}
AnimationEffect(const char* name, uint32_t bg_color, int x, int y);
~AnimationEffect();
AnimationEffect* setFgColor(uint32_t c);
void loop();
};

View File

@ -10,6 +10,7 @@ private:
Window* window = new Window(0, LED_HEIGHT - 6, LED_WIDTH, 6);
public:
~ClockEffect();
void loop();
void loop(boolean invert, CRGB fg_color, CRGB bg_color);
};

View File

@ -5,8 +5,16 @@
#include "my_fastled.h"
class ConfettiEffect : public Effect {
protected:
virtual CRGB _getColor();
public:
void loop();
boolean can_be_shown_with_clock();
};
class RandomConfettiEffect : public ConfettiEffect {
protected:
CRGB _getColor() override;
};
#endif

17
include/effect_dvd.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include "Effect.h"
class DvdEffect : public Effect {
private:
Window* window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
uint8_t _x = 0;
uint8_t _y = 0;
int8_t _x_dir = 1;
int8_t _y_dir = 1;
CRGB _color;
public:
DvdEffect();
~DvdEffect();
void loop() override;
bool can_be_shown_with_clock() override;
};

View File

@ -21,3 +21,11 @@ class MultiDynamicEffect : public SingleDynamicEffect {
public:
void loop();
};
class BigDynamicEffect : public Effect {
private:
Window* window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
public:
void loop();
~BigDynamicEffect();
};

View File

@ -9,16 +9,23 @@
class MatrixEffectColumn {
protected:
Window* window;
int x, y;
int length = 1;
uint8_t x, y;
uint8_t length = 1;
uint8_t _direction = 2;
bool _random_direction = false;
virtual CRGB _getColor(uint8_t height);
virtual void restart();
virtual void restart(bool completely_random);
private:
uint16_t speed;
boolean running;
unsigned long last_move = 0;
public:
MatrixEffectColumn(Window* win, int xPos);
static const uint8_t DIR_NORTH = 0;
static const uint8_t DIR_EAST = 1;
static const uint8_t DIR_SOUTH = 2;
static const uint8_t DIR_WEST = 3;
MatrixEffectColumn(Window* win, uint8_t direction=0, bool random_direction=false);
virtual ~MatrixEffectColumn() {};
void advance();
void draw();
@ -29,16 +36,16 @@ class RainbowMatrixEffectColumn : public MatrixEffectColumn {
protected:
CRGB _getColor(uint8_t height) override;
public:
RainbowMatrixEffectColumn(Window* win, int xPos) : MatrixEffectColumn(win, xPos) {};
RainbowMatrixEffectColumn(Window* win, uint8_t dir, bool rnd=false) : MatrixEffectColumn(win, dir, rnd) {};
};
class RandomMatrixEffectColumn : public MatrixEffectColumn {
protected:
uint8_t _hue = 42;
CRGB _getColor(uint8_t height) override;
void restart() override;
void restart(bool completely_random) override;
public:
RandomMatrixEffectColumn(Window* win, int xPos) : MatrixEffectColumn(win, xPos) {};
RandomMatrixEffectColumn(Window* win, uint8_t dir, bool rnd=false) : MatrixEffectColumn(win, dir, rnd) {};
};
class MatrixEffect : public Effect {

View File

@ -17,6 +17,7 @@ private:
bool is_direction_okay(uint8_t direction);
public:
SnakeEffect();
~SnakeEffect();
void loop();
boolean valid_position(Coords c);
Coords update_position(Coords c, uint8_t direction);

View File

@ -11,7 +11,7 @@ extern uint8_t cycle_effects_count;
extern Effect* current_effect;
extern ClockEffect effect_clock;
Effect* string_to_effect(String s);
Effect* select_effect(uint32_t c);
bool change_current_effect(String s);
void setup_effects();

6
include/tests.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
namespace tests {
void run();
void test_effects_for_memory_leaks();
}

View File

@ -143,7 +143,7 @@ bool Animation::_load_from_file(const char* filename) {
}
file.close();
LOGln("Animation * Loading completed successfully.");
return true;
@ -160,12 +160,14 @@ Animation::Animation(const char* filename, Window* win) {
}
}
void Animation::setFgColor(CRGB* fg_color) {
this->fgColor = fg_color;
void Animation::setFgColor(uint32_t c) {
if (this->fgColor) delete this->fgColor;
this->fgColor = new CRGB(c);
}
void Animation::setBgColor(CRGB* bg_color) {
this->bgColor = bg_color;
void Animation::setBgColor(uint32_t c) {
if (this->bgColor) delete this->bgColor;
this->bgColor = new CRGB(c);
}
bool Animation::invert() {
@ -205,15 +207,27 @@ void Animation::setSingleFrame(uint8_t frame) {
Animation::~Animation() {
for (int i=0; i<_color_count; i++) delete _colors[i];
delete [] _colors;
if (fgColor) delete fgColor;
delete bgColor;
delete [] _frame_data_lengths;
delete [] _frame_times;
LOGln("Deleting _colors...");
if (_colors) delete [] _colors;
LOGln("Deleting fgColor...");
if (fgColor != NULL) delete fgColor;
LOGln("Deleting bgColor...");
if (bgColor != NULL) delete bgColor;
LOGln("Deleting _frame_data_lengths...");
if (_frame_data_lengths) delete [] _frame_data_lengths;
LOGln("Deleting _frame_times...");
if (_frame_times) delete [] _frame_times;
for (int i=0; i<_frame_count; i++) {
delete [] _frame_data[i];
}
delete [] _frame_data;
LOGln("Deleting _frame_data...");
if (_frame_data) delete [] _frame_data;
LOGln("Deleteion done.");
}
void Animation::draw() {
@ -230,7 +244,7 @@ void Animation::drawFrame(uint8_t frame_index) {
CRGB red(0xFF0000);
CRGB black(0x000000);
for (int x=0; x<_window->width; x++) for (int y=0; y<_window->height; y++) {
_window->setPixel(x, y, (y*_window->width+x) % 2 ? &red : &black);
_window->setPixel(x, y, (y*_window->width+x + y) % 2 ? &red : &black);
}
return;
}

View File

@ -11,6 +11,11 @@ void Window::setPixel(uint8_t x, uint8_t y, CRGB* color) {
leds[this->coordsToGlobalIndex(x, y)] = *color;
}
void Window::raisePixel(uint8_t x, uint8_t y, CRGB* color) {
if (x>=this->width || y>=this->height) return;
leds[this->coordsToGlobalIndex(x, y)] |= *color;
}
void Window::setPixelByIndex(uint16_t index, CRGB* color) {
uint8_t x = index % this->width;
uint8_t y = index / this->width;
@ -69,7 +74,7 @@ void Window::line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, CRGB* color) {
int8_t sy = y1<y2 ? 1 : -1;
int16_t err = dx + dy;
int16_t e2;
while (1) {
setPixel(x1, y1, color);
if (x1==x2 && y1==y2) break;
@ -86,12 +91,12 @@ void Window::circle(uint8_t x0, uint8_t y0, uint8_t radius, CRGB* color) {
int16_t ddF_y = -2 * radius;
uint8_t x = 0;
uint8_t y = radius;
setPixel(x0, y0 + radius, color);
setPixel(x0, y0 - radius, color);
setPixel(x0 + radius, y0, color);
setPixel(x0 - radius, y0, color);
while (x < y) {
if (f >= 0) {
y--;
@ -101,12 +106,12 @@ void Window::circle(uint8_t x0, uint8_t y0, uint8_t radius, CRGB* color) {
x++;
ddF_x += 2;
f += ddF_x + 1;
setPixel(x0 + x, y0 + y, color);
setPixel(x0 - x, y0 + y, color);
setPixel(x0 + x, y0 - y, color);
setPixel(x0 - x, y0 - y, color);
setPixel(x0 + y, y0 + x, color);
setPixel(x0 - y, y0 + x, color);
setPixel(x0 + y, y0 - x, color);
@ -121,14 +126,14 @@ void Window::lineWithAngle(uint8_t x, uint8_t y, uint8_t angle, uint8_t length,
void Window::lineWithAngle(uint8_t x, uint8_t y, uint8_t angle, uint8_t startdist, uint8_t length, CRGB* color) {
int16_t x1 = x;
int16_t y1 = y;
if (startdist > 0) {
x1 = x + scale8(startdist, cos8(angle));
y1 = y + scale8(startdist, sin8(angle));
}
int16_t x2 = x + scale8(startdist + length, cos8(angle));
int16_t y2 = y + scale8(startdist + length, sin8(angle));
line(x1, y1, x2, y2, color);
}

View File

@ -1,16 +1,20 @@
#include "effect_animation.h"
#include "functions.h"
AnimationEffect::AnimationEffect(const char* name, CRGB* bg, int x, int y) {
this->bg_color = bg;
AnimationEffect::AnimationEffect(const char* name, uint32_t bg, int x, int y) {
this->xOffset = x;
this->yOffset = y;
this->animation = new Animation(name, window);
this->animation->setBgColor(this->bg_color);
this->animation->setBgColor(bg);
this->animation->setOffsets(this->xOffset, this->yOffset);
}
AnimationEffect* AnimationEffect::setFgColor(uint32_t c) {
animation->setFgColor(c);
return this;
}
AnimationEffect::~AnimationEffect() {
delete this->animation;
}

View File

@ -40,3 +40,7 @@ void ClockEffect::loop(boolean invert, CRGB fg_color, CRGB bg_color) {
window->setPixel(7, 4, &fg_color);
}
}
ClockEffect::~ClockEffect() {
delete window;
}

View File

@ -6,9 +6,17 @@
void ConfettiEffect::loop() {
window->fadeToBlackBy(3);
for (int i=0; i<EFFECT_CONFETTI_PIXELS_PER_LOOP; i++) {
CRGB color(CHSV(baseHue + random8(64), 200, 255));
CRGB color = _getColor();
window->addPixelColor(random16(LED_COUNT), &color);
}
}
CRGB ConfettiEffect::_getColor() {
return CHSV(baseHue + random8(64), 255, 255);
}
CRGB RandomConfettiEffect::_getColor() {
return CHSV(random8(), 255, 255);
}
boolean ConfettiEffect::can_be_shown_with_clock() { return true; };

View File

@ -1,5 +1,6 @@
#include "effect_cycle.h"
#include "effects.h"
#include <ErriezCRC32.h>
CycleEffect::CycleEffect() {
changeEffect();
@ -23,7 +24,7 @@ void CycleEffect::changeEffect() {
if (effect) delete effect;
LOGln("CycleEffect * Searching for new effect '%s'", cycle_effects[new_id]);
delay(25);
effect = string_to_effect(cycle_effects[new_id]);
effect = select_effect( crc32String(cycle_effects[new_id]) );
effect_id = new_id;
effectSince = millis();
}

37
src/effect_dvd.cpp Normal file
View File

@ -0,0 +1,37 @@
#include "effect_dvd.h"
#include "my_fastled.h"
void DvdEffect::loop() {
bool dir_changed = false;
EVERY_N_MILLISECONDS( 250 ) {
_x += _x_dir;
_y += _y_dir;
if (_x == 0 || _x + EFFECT_DVD_WIDTH >= window->width) {
_x_dir = -_x_dir;
dir_changed = true;
}
if (_y == 0 || _y + EFFECT_DVD_HEIGHT >= window->height) {
_y_dir = -_y_dir;
dir_changed = true;
}
}
window->clear();
for (int x=0; x<EFFECT_DVD_WIDTH; x++) for (int y=0; y<EFFECT_DVD_HEIGHT; y++) {
window->setPixel(_x + x, _y + y, (CRGB*)&_color);
}
if (dir_changed) _color = (CRGB)CHSV(random8(), 255, 255);
}
bool DvdEffect::can_be_shown_with_clock() { return true; }
DvdEffect::DvdEffect() {
_color = CHSV(random8(), 255, 255);
}
DvdEffect::~DvdEffect() {
delete window;
}

View File

@ -34,3 +34,28 @@ void MultiDynamicEffect::loop() {
}
this->draw();
}
BigDynamicEffect::~BigDynamicEffect() {
delete window;
}
void BigDynamicEffect::loop() {
EVERY_N_MILLISECONDS( EFFECT_BIG_DYNAMIC_LOOP_TIME ) {
uint8_t x = random8(0, window->width - EFFECT_BIG_DYNAMIC_SIZE + 1);
uint8_t y = random8(0, window->height - EFFECT_BIG_DYNAMIC_SIZE + 1);
CRGB color = CHSV(random8(), 255, 255);
CRGB black(0x000000);
for (uint8_t ix=0; ix<EFFECT_BIG_DYNAMIC_SIZE; ix++) for (uint8_t iy=0; iy<EFFECT_BIG_DYNAMIC_SIZE; iy++) {
window->setPixel(x+ix, y+iy, &color);
}
/*for (uint8_t ix=0; ix<EFFECT_BIG_DYNAMIC_SIZE+2; ix++) {
window->setPixel(x-1+ix, y-1, &black);
window->setPixel(x-1+ix, y+EFFECT_BIG_DYNAMIC_SIZE+1, &black);
}
for (uint8_t iy=0; iy<EFFECT_BIG_DYNAMIC_SIZE+2; iy++) {
window->setPixel(x-1, y-1+iy, &black);
window->setPixel(x+EFFECT_BIG_DYNAMIC_SIZE+1, y-1+iy, &black);
}*/
}
}

View File

@ -3,7 +3,7 @@
GolEffect::GolEffect() {
this->window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
_data = new uint8_t[this->window->count];
_old = new uint8_t[this->window->count];
for(uint16_t i=0; i<this->window->count; i++) {
@ -26,6 +26,7 @@ void GolEffect::_initialize() {
GolEffect::~GolEffect() {
delete[] _data;
delete[] _old;
delete window;
}
void GolEffect::loop() {
@ -35,7 +36,7 @@ void GolEffect::loop() {
} else {
_blend += EFFECT_GOL_BLEND_SPEED;
}
_draw();
}
@ -52,14 +53,14 @@ void GolEffect::_advance() {
uint16_t changes = 0;
for(uint8_t x=0; x<this->window->width; x++) for(uint8_t y=0; y<this->window->height; y++) {
uint16_t index = y*w + x;
uint8_t count =
uint8_t count =
(x>0 && y>0 && _old[index - w - 1]) +
(y>0 && _old[index - w]) +
(x<this->window->width-1 && y>0 && _old[index - w + 1]) +
(x>0 && _old[index - 1]) +
(x<this->window->width-1 && _old[index + 1]) +
(x>0 && y<this->window->height-1 && _old[index + w - 1]) +
(y<this->window->height-1 && _old[index + w]) +
(x<this->window->width-1 && y<this->window->height-1 && _old[index + w + 1]);
@ -79,7 +80,7 @@ void GolEffect::_advance() {
}
}
}
if (changes == 0) {
_initialize();
}

View File

@ -2,29 +2,80 @@
#include "my_color_palettes.h"
#include "functions.h"
MatrixEffectColumn::MatrixEffectColumn(Window* win, int xPos) {
MatrixEffectColumn::MatrixEffectColumn(Window* win, uint8_t dir, bool rand) {
window = win;
x = xPos;
restart();
y = random8(0, window->height);
_direction = dir;
_random_direction = rand;
restart(true);
}
void MatrixEffectColumn::restart() {
y=-1;
void MatrixEffectColumn::restart(bool completely_random) {
if (_random_direction) {
_direction = random8(4);
}
if (completely_random) {
x = random8(window->width);
y = random8(window->height);
} else {
switch(_direction) {
case DIR_NORTH:
x = random8(window->width);
y = window->height - 1;
break;
case DIR_EAST:
x = 0;
y = random8(window->height);
break;
case DIR_SOUTH:
x = random8(window->width);
y = 0;
break;
case DIR_WEST:
x = window->width - 1;
y = random8(window->height);
break;
}
}
length = random8(EFFECT_MATRIX_LENGTH_MIN, EFFECT_MATRIX_LENGTH_MAX);
running = true;
speed = random8(EFFECT_MATRIX_SPEED_MIN, EFFECT_MATRIX_SPEED_MAX);
}
void MatrixEffectColumn::advance() {
y++;
if (y-length > window->height) running = false;
switch(_direction) {
case DIR_NORTH:
y--;
if (y > window->height && y + length > window->height) running=false;
break;
case DIR_EAST:
x++;
if (x - length > window->width) running=false;
break;
case DIR_SOUTH:
y++;
if (y - length > window->height) running=false;
break;
case DIR_WEST:
x--;
if (x > window->width && y + length > window->width) running=false;
break;
}
}
void MatrixEffectColumn::draw() {
int8_t xdir = 0;
int8_t ydir = 0;
switch (_direction) {
case DIR_NORTH: ydir = 1; break;
case DIR_EAST: xdir = 1; break;
case DIR_SOUTH: ydir = -1; break;
case DIR_WEST: xdir = -1; break;
}
for(int i=0; i<length; i++) {
CRGB color = _getColor(i);
window->setPixel(x, y-i, &color);
window->raisePixel(x+(xdir*i), y+(ydir*i), &color);
}
}
@ -32,7 +83,7 @@ void MatrixEffectColumn::loop() {
if (!running) {
if (random8() < 20) {
// Start the column again.
restart();
restart(false);
}
} else {
if (millis() - last_move > speed) {
@ -75,8 +126,8 @@ CRGB RandomMatrixEffectColumn::_getColor(uint8_t i) {
return color;
}
void RandomMatrixEffectColumn::restart() {
MatrixEffectColumn::restart();
void RandomMatrixEffectColumn::restart(bool completely_random) {
MatrixEffectColumn::restart(completely_random);
_hue = random8();
}
@ -97,15 +148,15 @@ MatrixEffect::MatrixEffect() {
}
void MatrixEffect::_init() {
for (int i=0; i<window->width; i++) _columns[i] = new MatrixEffectColumn(window, i);
for (int i=0; i<window->width; i++) _columns[i] = new MatrixEffectColumn(window, MatrixEffectColumn::DIR_SOUTH);
}
void RandomMatrixEffect::_init() {
for (int i=0; i<window->width; i++) _columns[i] = new RandomMatrixEffectColumn(window, i);
for (int i=0; i<window->width; i++) _columns[i] = new RandomMatrixEffectColumn(window, random8(4), true);
}
void RainbowMatrixEffect::_init() {
for (int i=0; i<window->width; i++) _columns[i] = new RainbowMatrixEffectColumn(window, i);
for (int i=0; i<window->width; i++) _columns[i] = new RainbowMatrixEffectColumn(window, MatrixEffectColumn::DIR_SOUTH);
}
MatrixEffect::~MatrixEffect() {

View File

@ -10,6 +10,7 @@ PixelClockEffect::PixelClockEffect() {
PixelClockEffect::~PixelClockEffect() {
delete _color_seconds;
delete _color_minutes;
delete window;
}
void PixelClockEffect::loop() {

View File

@ -6,6 +6,10 @@ SnakeEffect::SnakeEffect() {
this->window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
}
SnakeEffect::~SnakeEffect() {
delete window;
}
void SnakeEffect::loop() {
if (run++ % EFFECT_SNAKE_SLOWDOWN == 0) { // Change the coordinates only on every n-th run.
if (random8(EFFECT_SNAKE_DIRECTION_CHANGE)==0 || is_turn_needed()) turn_random();

View File

@ -17,46 +17,77 @@
#include "effect_firework.h"
#include "effect_gol.h"
#include "effect_pixelclock.h"
#include "effect_dvd.h"
Effect* current_effect;
ClockEffect effect_clock;
Effect* string_to_effect(String name) {
uint32_t crc = crc32String(name.c_str());
switch (crc) {
Effect* select_effect(uint32_t code) {
switch (code) {
// use e.g. https://crccalc.com/ for the conversion of name to crc.
case 0xD682E3C8 /* sinematrix3 */ : return new Sinematrix3Effect();
case 0x90A887DA /* big_clock */ : return new BigClockEffect();
case 0xBE7BBE92 /* clock */ : return new ClockEffect();
case 0x733BE087 /* bell */ : return new BellEffect();
case 0x2BBC5D43 /* off */ : return new StaticEffect(0x000000);
case 0x1D84F231 /* koopa */ : return new AnimationEffect("/koopa.pia", new CRGB(0x000000), 0, 0);
case 0xAC43BCF1 /* couple_rain */ : return new AnimationEffect("/couple_rain.pia", new CRGB(0x000000), -8, -16);
case 0xF1B117F7 /* single_dynamic */ : return new SingleDynamicEffect();
case 0xF52F2804 /* multi_dynamic */ : return new MultiDynamicEffect();
case 0xF83341CF /* matrix */ : return new MatrixEffect();
case 0xD2B79DD0 /* rainbow_matrix */ : return new RainbowMatrixEffect();
case 0xE8DD3433 /* random_matrix */ : return new RandomMatrixEffect();
case 0xB086D193 /* cycle */ : return new CycleEffect();
case 0x2293EF9F /* twirl */ : return new TwirlEffect();
case 0x60ECC3E6 /* heart */ : return new AnimationEffect("/heart.pia", new CRGB(0x000000), 0, 0);
case 0x42090A49 /* confetti */ : return new ConfettiEffect();
case 0x516D6B9E /* snake */ : return new SnakeEffect();
case 0x58DE09CF /* fire */ : return new FireEffect();
case 0x08BA9C08 /* firework */ : return new FireworkEffect();
case 0x14B85EAC /* gol */ : return new GolEffect();
case 0xFA13015D /* cake */ : return new AnimationEffect("/cake.pia", new CRGB(0x000000), 0, 0);
case 0xA2B0D68B /* pixel_clock */ : return new PixelClockEffect();
case 0: case 0xD682E3C8 /* sinematrix3 */ : return new Sinematrix3Effect();
case 1: case 0x90A887DA /* big_clock */ : return new BigClockEffect();
case 2: case 0xBE7BBE92 /* clock */ : return new ClockEffect();
case 3: case 0x733BE087 /* bell */ : return new BellEffect(); //(new AnimationEffect("/bell.pia", 0x000000, 0, 0))->setFgColor(0xFFFF00);
case 4: case 0x2BBC5D43 /* off */ : return new StaticEffect(0x000000);
case 5: case 0x1D84F231 /* koopa */ : return new AnimationEffect("/koopa.pia", CRGB(0x000000), 0, 0);
case 6: case 0xAC43BCF1 /* couple_rain */ : return new AnimationEffect("/couple_rain.pia", CRGB(0x000000), -8, -16);
case 7: case 0xF1B117F7 /* single_dynamic */ : return new SingleDynamicEffect();
case 8: case 0xF52F2804 /* multi_dynamic */ : return new MultiDynamicEffect();
case 9: case 0xF83341CF /* matrix */ : return new MatrixEffect();
case 10: case 0xD2B79DD0 /* rainbow_matrix */ : return new RainbowMatrixEffect();
case 11: case 0xE8DD3433 /* random_matrix */ : return new RandomMatrixEffect();
case 12: case 0xB086D193 /* cycle */ : return new CycleEffect();
case 13: case 0x2293EF9F /* twirl */ : return new TwirlEffect();
case 14: case 0x60ECC3E6 /* heart */ : return new AnimationEffect("/heart.pia", CRGB(0x000000), 0, 0);
case 15: case 0x42090A49 /* confetti */ : return new ConfettiEffect();
case 16: case 0x516D6B9E /* snake */ : return new SnakeEffect();
case 17: case 0x58DE09CF /* fire */ : return new FireEffect();
case 18: case 0x08BA9C08 /* firework */ : return new FireworkEffect();
case 19: case 0x14B85EAC /* gol */ : return new GolEffect();
case 20: case 0xFA13015D /* cake */ : return new AnimationEffect("/cake.pia", CRGB(0x000000), 0, 0);
case 21: case 0xA2B0D68B /* pixel_clock */ : return new PixelClockEffect();
case 22: case 0x2C0E6962 /* big_dynamic */ : return new BigDynamicEffect();
case 23: case 0xDA6F31A5 /* random_confetti */ : return new RandomConfettiEffect();
case 24: case 0x8325C1DF /* dvd */ : return new DvdEffect();
default : return NULL;
};
}
bool change_current_effect(String name) {
Effect* new_effect = string_to_effect(name);
if (new_effect == NULL) return false;
bool change_current_effect(String payload) {
int pos = payload.indexOf(",");
String options = "";
if (pos != -1) {
LOGln("Effects * Effect comes with options.");
options = payload.substring(pos+1);
payload.remove(pos);
LOGln("Effects * Cleaned effect name: %s", payload.c_str());
}
Effect* new_effect = select_effect( crc32String(payload.c_str()) );
if (new_effect == NULL) {
LOGln("Effects * Could not find effect with name %s", payload.c_str());
return false;
}
delete current_effect;
current_effect = new_effect;
if (options.length() > 0) {
LOGln("Effects * Parsing options: %s", options.c_str());
options += ",";
int p_colon;
while ((p_colon = options.indexOf(",")) >= 0) {
int p_equal = options.indexOf("=");
if (p_equal >= 0 && p_equal < p_colon) {
String key = options.substring(0, p_equal);
String value = options.substring(p_equal + 1, p_colon);
LOGln("Effects * Applying option: %s = %s", key.c_str(), value.c_str());
current_effect->apply_option(key, value);
}
options.remove(0, p_colon + 1);
}
}
return true;
}

View File

@ -10,6 +10,7 @@
#include "Effect.h"
#include "effects.h"
#include "functions.h"
#include "tests.h"
WiFiClient wifi;
PubSubClient mqtt_client(wifi);
@ -57,12 +58,20 @@ void mqtt_callback(char* original_topic, byte* pl, unsigned int length) {
if(topic.compareTo("mode")==0) {
LOGln("MQTT * Changing mode...");
change_current_effect(payload);
bool result = change_current_effect(payload);
if (result) {
LOGln("MQTT * Effect changed.");
} else {
LOGln("MQTT * Could not change effect.");
}
return;
} else if (topic.compareTo("reboot")==0) {
LOGln("MQTT * Rebooting");
ESP.restart();
return; // Will never be reached, but anyway...
} else if (topic.compareTo("run_tests")==0) {
tests::run();
return;
}
long value = payload.toInt();
LOGln("MQTT * Payload as number: %d", value);
@ -81,10 +90,12 @@ void mqtt_callback(char* original_topic, byte* pl, unsigned int length) {
}
boolean mqtt_connect() {
LOG("MQTT * Connecting to MQTT server with client id %s", hostname);
LOGln("MQTT * Connecting to MQTT server with client id %s", hostname);
if (mqtt_client.connect(hostname, MQTT_USER, MQTT_PASS, MQTT_TOPIC "status", 0, true, "OFFLINE", true)) {
LOGln("MQTT * Connected.");
mqtt_client.publish(MQTT_TOPIC "status", "ONLINE", true);
char buffer[40];
snprintf(buffer, 40, "ONLINE %s %s", hostname, WiFi.localIP().toString().c_str());
mqtt_client.publish(MQTT_TOPIC "status", buffer, true);
mqtt_client.subscribe(MQTT_TOPIC "+");
mqtt_client.subscribe(MQTT_TOPIC_WEATHER "#");
}

View File

@ -1,5 +1,4 @@
#include <Arduino.h>
#include <SimpleList.h>
#include "ntp.h"
#include "config.h"
@ -20,7 +19,7 @@ char hostname[30]; // defined as extern in prototypes.h
void setup() {
Serial.begin(74880);
LOGln("Core * Starting");
int chipid;
#if defined( ESP8266 )
chipid = ESP.getChipId();
@ -28,7 +27,7 @@ void setup() {
chipid = ESP.getEfuseMac() & 0xFFFFFF;
#endif
snprintf(hostname, 30, HOSTNAME, chipid);
setup_effects();
wifi_setup();
ntp_setup();

28
src/tests.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "tests.h"
#include "effects.h"
namespace tests {
void run() {
LOGln("Tests * Running test for memory leaks...");
test_effects_for_memory_leaks();
}
void test_effects_for_memory_leaks() {
int i=0;
Effect* effect;
int32_t diffs[3] = {0, 0, 0};
int32_t usage = 0;
while (1) {
for (int j=0; j<3; j++) {
int free_at_start = ESP.getFreeHeap();
effect = select_effect(i);
if (j==0) usage = free_at_start - ESP.getFreeHeap();
if (effect == NULL) return;
delete effect;
diffs[j] = free_at_start - ESP.getFreeHeap();
}
LOGln("Tests * Memory usage of effect #%d: %d, leakage %d, %d, %d", i, usage, diffs[0], diffs[1], diffs[2]);
i++;
}
}
}