Compare commits
33 Commits
521e5f735d
...
master
Author | SHA1 | Date | |
---|---|---|---|
d76e088c37 | |||
c9825c8f9b | |||
ae997ef802 | |||
a6af2829ee | |||
0a4a62d7c8 | |||
7747e38253 | |||
b9cfc6568b | |||
1d66f9c541 | |||
f9e6a5ebd6 | |||
a96f6c79e3 | |||
ecf5998510 | |||
0ac4f9b181 | |||
fd44b217a7 | |||
209140cfb7 | |||
bcb5fdc9be | |||
b5bb0feccf | |||
0863380648 | |||
075823220a | |||
caa86551a0 | |||
10be8ef7cc | |||
9de77349e8 | |||
599bcd87bc | |||
70ddba2cbc | |||
3f09d9adbf | |||
cfb25d6030 | |||
4762a852d8 | |||
8e2d2225cb | |||
65dd09ca0d | |||
f014fd7cae | |||
1707084299 | |||
402d7f5d75 | |||
d28dca0a4d | |||
439e2de17f |
BIN
data/child.pia
Normal file
BIN
data/child.pia
Normal file
Binary file not shown.
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
class Effect {
|
class Effect {
|
||||||
protected:
|
protected:
|
||||||
Window* window = Window::getFullWindow(); // Use a full screen window per default.
|
Window* window = &Window::window_full; // Use a full screen window per default.
|
||||||
public:
|
public:
|
||||||
virtual ~Effect() {};
|
virtual ~Effect() {};
|
||||||
virtual void loop(uint16_t ms) = 0;
|
virtual void loop(uint16_t ms) = 0;
|
||||||
|
32
include/SimpleEffect.h
Normal file
32
include/SimpleEffect.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Effect.h"
|
||||||
|
#include "prototypes.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#define SE_CYCLE_COLORS 1 // Slowly cycle through the rainbow.
|
||||||
|
#define SE_RANDOM_PIXEL_COLORS 2 // Every pixel gets a random color every frame.
|
||||||
|
#define SE_ONLY_POSITIVE 4 // Only use colors, not white. This is equivalent to running your output through abs()
|
||||||
|
#define SE_FADEOUT 8 // Fades the old image out. Returning 0 doesn't change the pixel's value.
|
||||||
|
#define SE_RANDOM_STATIC_COLOR 16 // Sets a random static color at start of the effect.
|
||||||
|
#define SE_DEBUG 32 // Prints debug messages.
|
||||||
|
|
||||||
|
class SimpleEffect : public Effect {
|
||||||
|
protected:
|
||||||
|
Window* window = &Window::window_full; // Use a full screen window per default.
|
||||||
|
uint8_t _color = 0;
|
||||||
|
uint16_t _flags;
|
||||||
|
String _name;
|
||||||
|
simple_effect_t _method;
|
||||||
|
public:
|
||||||
|
SimpleEffect(String name, uint16_t flags, simple_effect_t method): _name { name }, _method { method } {
|
||||||
|
_flags = flags;
|
||||||
|
if (_flags & SE_RANDOM_STATIC_COLOR) {
|
||||||
|
_color = random8();
|
||||||
|
_flags &= ~SE_CYCLE_COLORS & ~SE_RANDOM_PIXEL_COLORS;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
void loop(uint16_t ms) override;
|
||||||
|
String get_name() { return _name; };
|
||||||
|
boolean can_be_shown_with_clock() { return true; }
|
||||||
|
|
||||||
|
};
|
@ -14,10 +14,13 @@ private:
|
|||||||
void _circle_point(int x0, int y0, int x1, int y1, CRGB* color);
|
void _circle_point(int x0, int y0, int x1, int y1, CRGB* color);
|
||||||
void _subpixel_render(uint8_t x, uint8_t y, CRGB* color, SubpixelRenderingMode m);
|
void _subpixel_render(uint8_t x, uint8_t y, CRGB* color, SubpixelRenderingMode m);
|
||||||
public:
|
public:
|
||||||
|
static Window window_full;
|
||||||
|
static Window window_with_clock;
|
||||||
|
static Window window_clock;
|
||||||
|
|
||||||
const uint8_t x, y;
|
const uint8_t x, y;
|
||||||
const uint8_t width, height;
|
const uint8_t width, height;
|
||||||
uint16_t count;
|
uint16_t count;
|
||||||
static Window* getFullWindow();
|
|
||||||
|
|
||||||
Window(): Window(0, 0, LED_WIDTH, LED_HEIGHT) {};
|
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) : Window(x, y, LED_WIDTH-x, LED_HEIGHT-y) {};
|
||||||
@ -50,4 +53,5 @@ public:
|
|||||||
void blur_row(uint8_t y, fract8 intensity);
|
void blur_row(uint8_t y, fract8 intensity);
|
||||||
void blur_columns(fract8 intensity);
|
void blur_columns(fract8 intensity);
|
||||||
void blur_column(uint8_t x, fract8 intensity);
|
void blur_column(uint8_t x, fract8 intensity);
|
||||||
|
void fill_with_checkerboard();
|
||||||
};
|
};
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#define MQTT_REPORT_METRICS // Whether to report metrics via MQTT. Disable if unwanted.
|
#define MQTT_REPORT_METRICS // Whether to report metrics via MQTT. Disable if unwanted.
|
||||||
#define MQTT_TOPIC_WEATHER "accuweather/pitrix/" // MQTT topic to listen for weather data. Must not start with a slash, but must end with one.
|
#define MQTT_TOPIC_WEATHER "accuweather/pitrix/" // MQTT topic to listen for weather data. Must not start with a slash, but must end with one.
|
||||||
#define MQTT_TOPIC_TIMER "alexa/timer"
|
#define MQTT_TOPIC_TIMER "alexa/timer"
|
||||||
|
#define MQTT_TOPIC_HOMEASSISTANT "homeassistant"
|
||||||
|
|
||||||
#define HOSTNAME "pitrix-%08X" // Hostname of the ESP to use for OTA and MQTT client id. %08X will be replaced by the chip id.
|
#define HOSTNAME "pitrix-%08X" // Hostname of the ESP to use for OTA and MQTT client id. %08X will be replaced by the chip id.
|
||||||
#define OTA_STARTUP_DELAY 10 // How many seconds to wait at startup. This is useful to prevent being unable to flash OTA by a bug in the code. Set to 0 to disable.
|
#define OTA_STARTUP_DELAY 10 // How many seconds to wait at startup. This is useful to prevent being unable to flash OTA by a bug in the code. Set to 0 to disable.
|
||||||
@ -96,22 +97,18 @@
|
|||||||
Serial.println(buffer);\
|
Serial.println(buffer);\
|
||||||
} while (0);
|
} while (0);
|
||||||
#else
|
#else
|
||||||
#define LOG(msg, ...) do { \
|
#define LOG(x, ...) Serial.printf(x, ##__VA_ARGS__);
|
||||||
char buffer[128]; \
|
#define LOGln(x, ...) { Serial.printf(x, ##__VA_ARGS__); Serial.println(); }
|
||||||
snprintf_P(buffer, 128, PSTR(msg), ##__VA_ARGS__);\
|
|
||||||
Serial.print(buffer);\
|
|
||||||
} while (0);
|
|
||||||
#define LOGln(msg, ...) do { \
|
|
||||||
char buffer[128]; \
|
|
||||||
snprintf_P(buffer, 128, PSTR(msg), ##__VA_ARGS__);\
|
|
||||||
Serial.println(buffer);\
|
|
||||||
} while (0);
|
|
||||||
#endif
|
#endif
|
||||||
|
#define DBG(msg, ...) { Serial.printf(msg, ##__VA_ARGS__); Serial.println(); }
|
||||||
#else
|
#else
|
||||||
#define LOG(msg, ...) do {} while(0);
|
#define LOG(x) do {} while(0);
|
||||||
#define LOGln(msg, ...) do {} while(0);
|
#define LOGln(x) do {} while(0);
|
||||||
|
#define DBG(msg, ...) do {} while(0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined( ESP8266 ) && !defined( ESP32 )
|
#if !defined( ESP8266 ) && !defined( ESP32 )
|
||||||
#error "Neither ESP8266 nor ESP32 are set. Maybe you are compiling this for another platform...?"
|
#error "Neither ESP8266 nor ESP32 are set. Maybe you are compiling this for another platform...?"
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Effect.h"
|
|
||||||
#include "my_fastled.h"
|
|
||||||
|
|
||||||
class ConfettiEffect : public Effect {
|
|
||||||
protected:
|
|
||||||
virtual CRGB _getColor();
|
|
||||||
public:
|
|
||||||
void loop(uint16_t ms);
|
|
||||||
boolean can_be_shown_with_clock();
|
|
||||||
String get_name() override { return "confetti"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class RandomConfettiEffect : public ConfettiEffect {
|
|
||||||
protected:
|
|
||||||
CRGB _getColor() override;
|
|
||||||
String get_name() override { return "random_confetti"; }
|
|
||||||
};
|
|
||||||
|
|
@ -1,15 +1,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Effect.h"
|
#include "Effect.h"
|
||||||
#include "effect_clock.h"
|
#include "effects/clock.h"
|
||||||
#include "effect_timer.h"
|
#include "effects/timer.h"
|
||||||
|
|
||||||
|
#define SIMPLE_EFFECT(name, use_in_cycle, flags, ...) {name, use_in_cycle, [](){ return new SimpleEffect(name, flags, [](double t, uint16_t i, uint8_t x, uint8_t y)->double __VA_ARGS__ ); }}
|
||||||
|
|
||||||
struct EffectEntry {
|
struct EffectEntry {
|
||||||
const char* name;
|
const char* name;
|
||||||
bool use_in_cycle;
|
bool use_in_cycle;
|
||||||
std::function<Effect*()> create;
|
std::function<Effect*()> create;
|
||||||
|
#ifdef MQTT_REPORT_METRICS
|
||||||
|
int16_t heap_change_sum;
|
||||||
|
uint16_t run_count;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
extern const EffectEntry effects[];
|
extern EffectEntry effects[];
|
||||||
extern const uint8_t effects_size;
|
extern const uint8_t effects_size;
|
||||||
|
|
||||||
extern Effect* current_effect;
|
extern Effect* current_effect;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include "Effect.h"
|
#include "Effect.h"
|
||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
#include "my_fastled.h"
|
#include "my_fastled.h"
|
||||||
#include "Animation.h"
|
#include "../Animation.h"
|
||||||
|
|
||||||
class AnimationEffect : public Effect {
|
class AnimationEffect : public Effect {
|
||||||
private:
|
private:
|
||||||
@ -11,12 +11,14 @@ private:
|
|||||||
const char* name;
|
const char* name;
|
||||||
uint16_t xOffset;
|
uint16_t xOffset;
|
||||||
uint16_t yOffset;
|
uint16_t yOffset;
|
||||||
|
unsigned long _last_blink_at;
|
||||||
|
uint16_t _blink_freq;
|
||||||
public:
|
public:
|
||||||
AnimationEffect(const char* name) : AnimationEffect(name, 0x000000, 0, 0) {}
|
AnimationEffect(const char* name, uint32_t bg_color=0x000000, int x=0, int y=0);
|
||||||
AnimationEffect(const char* name, uint32_t bg_color) : AnimationEffect(name, bg_color, 0, 0) {}
|
static AnimationEffect* Blinker(const char* name, uint16_t interval, uint32_t color, uint32_t background_color=0x000000);
|
||||||
AnimationEffect(const char* name, uint32_t bg_color, int x, int y);
|
|
||||||
~AnimationEffect();
|
~AnimationEffect();
|
||||||
AnimationEffect* setFgColor(uint32_t c);
|
AnimationEffect* setFgColor(uint32_t c);
|
||||||
|
AnimationEffect* setBlinkFrequency(uint16_t);
|
||||||
void loop(uint16_t ms);
|
void loop(uint16_t ms);
|
||||||
String get_name() override;
|
String get_name() override;
|
||||||
};
|
};
|
@ -3,17 +3,19 @@
|
|||||||
#include "Effect.h"
|
#include "Effect.h"
|
||||||
|
|
||||||
class BigClockEffect : public Effect {
|
class BigClockEffect : public Effect {
|
||||||
private:
|
protected:
|
||||||
CRGB _color_font = CRGB(0xAAAAAA);
|
CRGB _color_font = CRGB(0xAAAAAA);
|
||||||
CRGB _color_seconds_light = CRGB(0xFFFF00);
|
CRGB _color_seconds_light = CRGB(0xFFFF00);
|
||||||
CRGB _color_seconds_dark = CRGB(0xAA0000);
|
CRGB _color_seconds_dark = CRGB(0xAA0000);
|
||||||
CRGB _color_seconds_moving_light = CRGB(0x666600);
|
CRGB _color_seconds_moving_light = CRGB(0x666600);
|
||||||
CRGB _color_seconds_moving_dark = CRGB(0x660000);
|
CRGB _color_seconds_moving_dark = CRGB(0x660000);
|
||||||
|
|
||||||
|
virtual CRGB _get_color_font() { return CRGB(0xAAAAAA); }
|
||||||
|
|
||||||
void _draw_seconds(uint8_t seconds);
|
void _draw_seconds(uint8_t seconds);
|
||||||
void _draw_border_pixel(accum88 pos, CRGB* color);
|
virtual void _draw_border_pixel(accum88 pos, CRGB* color);
|
||||||
|
void _draw_colon(bool odd);
|
||||||
public:
|
public:
|
||||||
void loop(uint16_t ms);
|
virtual void loop(uint16_t ms);
|
||||||
String get_name() override { return "big_clock"; }
|
String get_name() override { return "big_clock"; }
|
||||||
};
|
};
|
@ -16,7 +16,7 @@ public:
|
|||||||
|
|
||||||
class Blur2DEffect : public Effect {
|
class Blur2DEffect : public Effect {
|
||||||
private:
|
private:
|
||||||
Window* window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
|
Window* window = &Window::window_with_clock;
|
||||||
uint8_t _count;
|
uint8_t _count;
|
||||||
Blur2DBlob* _blobs;
|
Blur2DBlob* _blobs;
|
||||||
public:
|
public:
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
class ClockEffect : public Effect {
|
class ClockEffect : public Effect {
|
||||||
protected:
|
protected:
|
||||||
Window* window = new Window(0, LED_HEIGHT - 6, LED_WIDTH, 6);
|
Window* window = &Window::window_clock;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~ClockEffect();
|
virtual ~ClockEffect();
|
||||||
@ -16,10 +16,3 @@ public:
|
|||||||
void loop_with_invert(bool invert);
|
void loop_with_invert(bool invert);
|
||||||
void loop(boolean invert, CRGB fg_color, CRGB bg_color, uint8_t y);
|
void loop(boolean invert, CRGB fg_color, CRGB bg_color, uint8_t y);
|
||||||
};
|
};
|
||||||
|
|
||||||
class NightClockEffect : public ClockEffect {
|
|
||||||
public:
|
|
||||||
NightClockEffect();
|
|
||||||
~NightClockEffect();
|
|
||||||
void loop(uint16_t ms) override;
|
|
||||||
};
|
|
11
include/effects/diamond.h
Normal file
11
include/effects/diamond.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Effect.h"
|
||||||
|
|
||||||
|
class DiamondEffect : public Effect {
|
||||||
|
private:
|
||||||
|
Window* window = &Window::window_with_clock;
|
||||||
|
public:
|
||||||
|
void loop(uint16_t ms) override;
|
||||||
|
bool can_be_shown_with_clock() override;
|
||||||
|
String get_name() override { return "diamond"; }
|
||||||
|
};
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
class DvdEffect : public Effect {
|
class DvdEffect : public Effect {
|
||||||
private:
|
private:
|
||||||
Window* window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
|
Window* window = &Window::window_with_clock;
|
||||||
saccum78 _x = 0;
|
saccum78 _x = 0;
|
||||||
saccum78 _y = 0;
|
saccum78 _y = 0;
|
||||||
int8_t _x_dir = 1;
|
int8_t _x_dir = 1;
|
@ -26,7 +26,7 @@ public:
|
|||||||
|
|
||||||
class BigDynamicEffect : public Effect {
|
class BigDynamicEffect : public Effect {
|
||||||
private:
|
private:
|
||||||
Window* window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
|
Window* window = &Window::window_with_clock;
|
||||||
public:
|
public:
|
||||||
void loop(uint16_t ms);
|
void loop(uint16_t ms);
|
||||||
~BigDynamicEffect();
|
~BigDynamicEffect();
|
@ -34,7 +34,7 @@ public:
|
|||||||
|
|
||||||
class FireworkEffect : public Effect {
|
class FireworkEffect : public Effect {
|
||||||
private:
|
private:
|
||||||
Window* window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
|
Window* window = &Window::window_with_clock;
|
||||||
bool _skyburst = 0;
|
bool _skyburst = 0;
|
||||||
|
|
||||||
accum88 _burst_x;
|
accum88 _burst_x;
|
@ -6,7 +6,7 @@
|
|||||||
class LightspeedEffectStar {
|
class LightspeedEffectStar {
|
||||||
private:
|
private:
|
||||||
uint16_t _angle;
|
uint16_t _angle;
|
||||||
accum88 _start;
|
accum88 _distance;
|
||||||
uint16_t _speed;
|
uint16_t _speed;
|
||||||
uint16_t _target;
|
uint16_t _target;
|
||||||
uint8_t _saturation;
|
uint8_t _saturation;
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
class MarqueeEffect : public Effect {
|
class MarqueeEffect : public Effect {
|
||||||
private:
|
private:
|
||||||
Window* window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
|
Window* window = &Window::window_with_clock;
|
||||||
String _text = String("No text set +++ ");
|
String _text = String("No text set +++ ");
|
||||||
saccum78 _position = (window->width<<8);
|
saccum78 _position = (window->width<<8);
|
||||||
public:
|
public:
|
8
include/effects/night_clock.h
Normal file
8
include/effects/night_clock.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Effect.h"
|
||||||
|
|
||||||
|
class NightClockEffect : public Effect {
|
||||||
|
public:
|
||||||
|
virtual void loop(uint16_t ms);
|
||||||
|
String get_name() override { return "night_clock"; }
|
||||||
|
};
|
@ -14,6 +14,7 @@ class SnakeEffect : public Effect {
|
|||||||
private:
|
private:
|
||||||
Coords _pos;
|
Coords _pos;
|
||||||
Coords _apple;
|
Coords _apple;
|
||||||
|
Coords _tail;
|
||||||
int8_t _dir = SNAKE_DIR_NORTH;
|
int8_t _dir = SNAKE_DIR_NORTH;
|
||||||
uint8_t* _map;
|
uint8_t* _map;
|
||||||
uint16_t _pixels;
|
uint16_t _pixels;
|
||||||
@ -32,11 +33,16 @@ private:
|
|||||||
const uint32_t _weights[36] = {0xbd25943f, 0xbf279d81, 0x3e25d128, 0x3ec62438, 0x3f0e719c, 0x3eefbea9, 0x3e947ed4, 0xbe5323c1, 0xbf2d4796, 0xbf3f0a75, 0x3f0e45d9, 0xbf0253ca, 0xbedca2f2, 0xbd79073c, 0x3ede80ec, 0xbd4b97b6, 0x3f69a6be, 0xbe4b8bf2, 0x3eccf87d, 0xbf301113, 0xbf62b6e8, 0xbf71daf6, 0xbf204130, 0xbf222609, 0x3e26c03c, 0xbf497837, 0xbee4d175, 0x3ec601de, 0x3e4954eb, 0x3eef2619, 0xbe849370, 0xbf18fb2b, 0x3f25bbd1, 0xbf3b4e44, 0x3f484d59, 0x3edd6a8a};
|
const uint32_t _weights[36] = {0xbd25943f, 0xbf279d81, 0x3e25d128, 0x3ec62438, 0x3f0e719c, 0x3eefbea9, 0x3e947ed4, 0xbe5323c1, 0xbf2d4796, 0xbf3f0a75, 0x3f0e45d9, 0xbf0253ca, 0xbedca2f2, 0xbd79073c, 0x3ede80ec, 0xbd4b97b6, 0x3f69a6be, 0xbe4b8bf2, 0x3eccf87d, 0xbf301113, 0xbf62b6e8, 0xbf71daf6, 0xbf204130, 0xbf222609, 0x3e26c03c, 0xbf497837, 0xbee4d175, 0x3ec601de, 0x3e4954eb, 0x3eef2619, 0xbe849370, 0xbf18fb2b, 0x3f25bbd1, 0xbf3b4e44, 0x3f484d59, 0x3edd6a8a};
|
||||||
// Round 193, 164.8 points, length 36, 6% stopped, 94% died
|
// Round 193, 164.8 points, length 36, 6% stopped, 94% died
|
||||||
//const uint32_t _weights[36] = {0x3e872ffb, 0xbea57262, 0xbee269bf, 0x3ed790a3, 0xbf54014f, 0x3ecde0a6, 0xbf240a93, 0xbe9e4782, 0x3f205106, 0xbf4465c2, 0xbf79579a, 0xbf07f122, 0x3ed0e1bc, 0xbf7a5a09, 0xbf0fc70b, 0xbf6d1971, 0xbe0f5585, 0xbec94b12, 0x3f51f7a9, 0x3eaac42b, 0xbe6aafa6, 0x3d3e3ce3, 0xbf7c4232, 0xbe634103, 0x3f800000, 0x3eff886c, 0x3deae1e8, 0x3eea6988, 0xbf800000, 0xbf426a20, 0x3e3a0a45, 0xbe848803, 0x3e84e8c9, 0x3ef9fabc, 0xbe7733e6, 0xbecda633};
|
//const uint32_t _weights[36] = {0x3e872ffb, 0xbea57262, 0xbee269bf, 0x3ed790a3, 0xbf54014f, 0x3ecde0a6, 0xbf240a93, 0xbe9e4782, 0x3f205106, 0xbf4465c2, 0xbf79579a, 0xbf07f122, 0x3ed0e1bc, 0xbf7a5a09, 0xbf0fc70b, 0xbf6d1971, 0xbe0f5585, 0xbec94b12, 0x3f51f7a9, 0x3eaac42b, 0xbe6aafa6, 0x3d3e3ce3, 0xbf7c4232, 0xbe634103, 0x3f800000, 0x3eff886c, 0x3deae1e8, 0x3eea6988, 0xbf800000, 0xbf426a20, 0x3e3a0a45, 0xbe848803, 0x3e84e8c9, 0x3ef9fabc, 0xbe7733e6, 0xbecda633};
|
||||||
|
// Round 13650, 244.8 points, length 42, 34% stopped, 66% died
|
||||||
|
//const uint32_t _weights[36] = {0xbeb99de3, 0x3e6ca488, 0xbe3e9dad, 0xbed38d4e, 0x3f279fc1, 0xbd367111, 0xbf473843, 0xbf800000, 0x3f614edc, 0xbecc734f, 0xbe59b29d, 0x3d479078, 0x3efa7ca6, 0xbedc6ce6, 0x3f4626a1, 0x3e9d8c2c, 0x3f29e25c, 0x3ebde05d, 0x3e8f3e29, 0xbe8ad92c, 0xbe148f2d, 0x3d4a3ca7, 0xbf800000, 0x3d9cd634, 0x3f29802e, 0xbf2cc57e, 0xbcbfafff, 0x3e280b8a, 0x3f5ff9a3, 0xbf4e29c9, 0x3e8936d2, 0xbf49dda9, 0xbe9bf4c7, 0x3e203ea8, 0xbd4edf4d, 0xbf4e3c05};
|
||||||
|
|
||||||
const uint8_t _net_layout[3] = {6, 4, 3};
|
const uint8_t _net_layout[3] = {6, 4, 3};
|
||||||
const uint8_t _net_layers = 3;
|
const uint8_t _net_layers = 3;
|
||||||
const uint8_t _net_total_size = 36;
|
const uint8_t _net_total_size = 36;
|
||||||
|
|
||||||
|
uint8_t _head_rounds = 0;
|
||||||
|
uint8_t _tail_rounds = 0;
|
||||||
|
|
||||||
|
|
||||||
uint16_t _xy2i(uint8_t x, uint8_t y);
|
uint16_t _xy2i(uint8_t x, uint8_t y);
|
||||||
uint16_t _xy2i(Coords c);
|
uint16_t _xy2i(Coords c);
|
||||||
@ -49,6 +55,7 @@ private:
|
|||||||
void _place_apple();
|
void _place_apple();
|
||||||
void _init();
|
void _init();
|
||||||
void _decide();
|
void _decide();
|
||||||
|
uint8_t _coords_to_field_id(Coords);
|
||||||
int8_t _manual_decision();
|
int8_t _manual_decision();
|
||||||
void _move();
|
void _move();
|
||||||
void _draw();
|
void _draw();
|
30
include/effects/tpm2_net.h
Normal file
30
include/effects/tpm2_net.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Effect.h"
|
||||||
|
#include "prototypes.h"
|
||||||
|
#include "my_fastled.h"
|
||||||
|
#include "Window.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
|
||||||
|
class Tpm2NetEffect : public Effect {
|
||||||
|
protected:
|
||||||
|
Window* window = &Window::window_full;
|
||||||
|
WiFiUDP _udp;
|
||||||
|
uint16_t _pixel_index = 0;
|
||||||
|
|
||||||
|
void _parse_command(uint16_t size, uint8_t packet_number);
|
||||||
|
void _parse_data(uint16_t size, uint8_t packet_number);
|
||||||
|
void _respond(uint8_t* data, uint8_t len);
|
||||||
|
void _respond_ack();
|
||||||
|
void _respond_with_data(uint8_t* data, uint8_t len);
|
||||||
|
void _respond_unknown_command();
|
||||||
|
unsigned long _last_packet_at = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Tpm2NetEffect();
|
||||||
|
virtual ~Tpm2NetEffect();
|
||||||
|
virtual void loop(uint16_t ms);
|
||||||
|
bool can_be_shown_with_clock();
|
||||||
|
String get_name() override { return "tpm2.net"; }
|
||||||
|
};
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
class TvStaticEffect : public Effect {
|
class TvStaticEffect : public Effect {
|
||||||
private:
|
private:
|
||||||
Window* _window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
|
Window* _window = &Window::window_with_clock;
|
||||||
public:
|
public:
|
||||||
~TvStaticEffect();
|
~TvStaticEffect();
|
||||||
void loop(uint16_t ms) override;
|
void loop(uint16_t ms) override;
|
@ -17,8 +17,8 @@ void mqtt_setup();
|
|||||||
|
|
||||||
void mqtt_loop();
|
void mqtt_loop();
|
||||||
|
|
||||||
void mqtt_publish(const char* topic, int number);
|
void mqtt_publish(const char* topic, int number, bool retain=false);
|
||||||
void mqtt_publish(const char* topic, const char* message);
|
void mqtt_publish(const char* topic, const char* message, bool retain=false);
|
||||||
|
|
||||||
void mqtt_log(const char* message);
|
void mqtt_log(const char* message);
|
||||||
void mqtt_log(int number);
|
void mqtt_log(int number);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include "my_fastled.h"
|
||||||
|
|
||||||
extern uint8_t baseHue;
|
extern uint8_t baseHue;
|
||||||
extern char hostname[30];
|
extern char hostname[30];
|
||||||
@ -31,3 +32,5 @@ typedef struct {
|
|||||||
uint16_t x;
|
uint16_t x;
|
||||||
uint16_t y;
|
uint16_t y;
|
||||||
} Coords;
|
} Coords;
|
||||||
|
|
||||||
|
typedef std::function<double(double, uint16_t, uint8_t, uint8_t)> simple_effect_t;
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
lib_dir = lib
|
lib_dir = lib
|
||||||
env_default = ota
|
default_envs = ota
|
||||||
|
|
||||||
[extra]
|
[extra]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
@ -29,10 +29,12 @@ lib_ldf_mode = deep
|
|||||||
build_flags = -Wl,-Teagle.flash.2m512.ld
|
build_flags = -Wl,-Teagle.flash.2m512.ld
|
||||||
|
|
||||||
[env:local]
|
[env:local]
|
||||||
upload_port = /dev/cu.wchusbserial1420
|
upload_port = /dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0
|
||||||
platform = espressif8266
|
platform = espressif8266
|
||||||
board = esp07
|
board = esp07
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps = ${extra.lib_deps}
|
lib_deps = ${extra.lib_deps}
|
||||||
lib_ldf_mode = deep
|
lib_ldf_mode = deep
|
||||||
build_flags = -Wl,-Teagle.flash.2m512.ld
|
build_flags = -Wl,-Teagle.flash.2m512.ld
|
||||||
|
monitor_filters = time, esp8266_exception_decoder
|
||||||
|
build_type = debug
|
||||||
|
@ -84,16 +84,16 @@ bool Animation::_load_from_file(const char* filename) {
|
|||||||
// Now we can be sure to have the right amount of bytes available for reading
|
// Now we can be sure to have the right amount of bytes available for reading
|
||||||
|
|
||||||
_width = file.read();
|
_width = file.read();
|
||||||
LOGln("Animation * width: %d", _width);
|
DBG("Animation * width: %d", _width);
|
||||||
_height = file.read();
|
_height = file.read();
|
||||||
LOGln("Animation * height: %d", _height);
|
DBG("Animation * height: %d", _height);
|
||||||
|
|
||||||
_frame_count = file.read();
|
_frame_count = file.read();
|
||||||
LOGln("Animation * frame_count: %d", _frame_count);
|
DBG("Animation * frame_count: %d", _frame_count);
|
||||||
_color_count = file.read();
|
_color_count = file.read();
|
||||||
LOGln("Animation * color_count: %d", _color_count);
|
DBG("Animation * color_count: %d", _color_count);
|
||||||
|
|
||||||
LOGln("Animation * Loading colors...");
|
DBG("Animation * Loading colors...");
|
||||||
_colors = new CRGB*[_color_count];
|
_colors = new CRGB*[_color_count];
|
||||||
char* temp = new char[_color_count*3];
|
char* temp = new char[_color_count*3];
|
||||||
int bytes_read = file.readBytes(temp, _color_count*3);
|
int bytes_read = file.readBytes(temp, _color_count*3);
|
||||||
@ -102,36 +102,33 @@ bool Animation::_load_from_file(const char* filename) {
|
|||||||
_colors[i] = new CRGB(temp[i*3], temp[i*3+1], temp[i*3+2]);
|
_colors[i] = new CRGB(temp[i*3], temp[i*3+1], temp[i*3+2]);
|
||||||
}
|
}
|
||||||
delete [] temp;
|
delete [] temp;
|
||||||
LOGln("Animation * Color loading done.");
|
DBG("Animation * Color loading done.");
|
||||||
|
|
||||||
LOG("Animation * Loading frame times...");
|
DBG("Animation * Loading frame times...");
|
||||||
_frame_times = new uint16_t[_frame_count];
|
_frame_times = new uint16_t[_frame_count];
|
||||||
for (int i=0; i<_frame_count; i++) {
|
for (int i=0; i<_frame_count; i++) {
|
||||||
_frame_times[i] = (file.read() << 8) | file.read();
|
_frame_times[i] = (file.read() << 8) | file.read();
|
||||||
}
|
}
|
||||||
LOGln(" done.");
|
DBG(" done.");
|
||||||
|
|
||||||
LOGln("Animation * Loading frame lengths...");
|
DBG("Animation * Loading frame lengths...");
|
||||||
_frame_data_lengths = new uint16_t[_frame_count];
|
_frame_data_lengths = new uint16_t[_frame_count];
|
||||||
temp = new char[_frame_count*2];
|
temp = new char[_frame_count*2];
|
||||||
bytes_read = file.readBytes(temp, _frame_count*2);
|
bytes_read = file.readBytes(temp, _frame_count*2);
|
||||||
LOGln("Animation * Read %d bytes.", bytes_read);
|
DBG("Animation * Read %d bytes.", bytes_read);
|
||||||
for (int i=0; i<_frame_count; i++) {
|
for (int i=0; i<_frame_count; i++) {
|
||||||
//LOGln("Animation * Raw frame lengths: %d, %d", temp[i*2], temp[i*2+1]);
|
//LOGln("Animation * Raw frame lengths: %d, %d", temp[i*2], temp[i*2+1]);
|
||||||
_frame_data_lengths[i] = (temp[i*2]<<8) | temp[i*2+1];
|
_frame_data_lengths[i] = (temp[i*2]<<8) | temp[i*2+1];
|
||||||
}
|
}
|
||||||
delete [] temp;
|
delete [] temp;
|
||||||
LOGln("Animation * Frame length loading done.");
|
DBG("Animation * Frame length loading done.");
|
||||||
|
|
||||||
LOGln("Animation * Loading frame data...");
|
DBG("Animation * Loading frame data...");
|
||||||
_frame_data = new uint8_t*[_frame_count];
|
_frame_data = new uint8_t*[_frame_count];
|
||||||
for (int i=0; i<_frame_count; i++) {
|
for (int i=0; i<_frame_count; i++) {
|
||||||
uint16_t fl = _frame_data_lengths[i];
|
uint16_t fl = _frame_data_lengths[i];
|
||||||
LOGln("Animation * Loading frame %d with %d bytes...", i, fl);
|
DBG("Animation * Loading frame %d/%d with %d bytes...", i, _frame_count, fl);
|
||||||
_frame_data[i] = new uint8_t[fl];
|
_frame_data[i] = new uint8_t[fl];
|
||||||
/*for (int b=0; b<fl; b++) {
|
|
||||||
_frame_data[i][b] = file.read();
|
|
||||||
}*/
|
|
||||||
file.readBytes((char*)_frame_data[i], fl);
|
file.readBytes((char*)_frame_data[i], fl);
|
||||||
}
|
}
|
||||||
LOGln("Animation * Frame data loaded.");
|
LOGln("Animation * Frame data loaded.");
|
||||||
@ -208,27 +205,25 @@ void Animation::setSingleFrame(uint8_t frame) {
|
|||||||
Animation::~Animation() {
|
Animation::~Animation() {
|
||||||
for (int i=0; i<_color_count; i++) delete _colors[i];
|
for (int i=0; i<_color_count; i++) delete _colors[i];
|
||||||
|
|
||||||
LOGln("Animation * Deleting _colors...");
|
DBG("Animation * Deleting _colors...");
|
||||||
if (_colors) delete [] _colors;
|
if (_colors) delete[] _colors;
|
||||||
|
|
||||||
LOGln("Animation * Deleting fgColor...");
|
DBG("Animation * Deleting fgColor...");
|
||||||
if (fgColor != NULL) delete fgColor;
|
if (fgColor != NULL) delete fgColor;
|
||||||
|
|
||||||
LOGln("Animation * Deleting bgColor...");
|
DBG("Animation * Deleting bgColor...");
|
||||||
if (bgColor != NULL) delete bgColor;
|
if (bgColor != NULL) delete bgColor;
|
||||||
|
|
||||||
LOGln("Animation * Deleting _frame_data_lengths...");
|
DBG("Animation * Deleting _frame_data_lengths...");
|
||||||
if (_frame_data_lengths) delete [] _frame_data_lengths;
|
if (_frame_data_lengths) delete[] _frame_data_lengths;
|
||||||
|
|
||||||
LOGln("Animation * Deleting _frame_times...");
|
DBG("Animation * Deleting _frame_times...");
|
||||||
if (_frame_times) delete [] _frame_times;
|
if (_frame_times) delete[] _frame_times;
|
||||||
for (int i=0; i<_frame_count; i++) {
|
for (int i=0; i<_frame_count; i++) {
|
||||||
delete [] _frame_data[i];
|
delete[] _frame_data[i];
|
||||||
}
|
}
|
||||||
|
DBG("Animation * Deleting _frame_data...");
|
||||||
LOGln("Animation * Deleting _frame_data...");
|
if (_frame_data) delete[] _frame_data;
|
||||||
if (_frame_data) delete [] _frame_data;
|
|
||||||
|
|
||||||
LOGln("Animation * Deletion done.");
|
LOGln("Animation * Deletion done.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
src/SimpleEffect.cpp
Normal file
35
src/SimpleEffect.cpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include "SimpleEffect.h"
|
||||||
|
|
||||||
|
void SimpleEffect::loop(uint16_t ms) {
|
||||||
|
if (_flags & SE_FADEOUT) window->fadeToBlackBy(3);
|
||||||
|
double t = 0.001 * millis();
|
||||||
|
for(uint8_t x=0; x<window->width; x++) for(uint8_t y=0; y<window->height; y++) {
|
||||||
|
uint16_t i = y*window->width + x;
|
||||||
|
double r = _method(t, i, x, y);
|
||||||
|
//if (i==0) Serial.printf("t=%f i=%d x=%d y=%d => r=%f, abs(r)=%d\n", t, i, x, y, r, abs(r)*255);
|
||||||
|
if ((_flags & SE_DEBUG) && i==17) Serial.printf("t=%f i=%d x=%d y=%d => r=%f, abs(r*255)=%d\n", t, i, x, y, r, (int)abs(r*255));
|
||||||
|
if ((_flags & SE_FADEOUT) && r==0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp r between -1.0 and +1.0
|
||||||
|
if (r<-1.0) {
|
||||||
|
r = -1.0;
|
||||||
|
} else if (r>1.0) {
|
||||||
|
r = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_flags & SE_ONLY_POSITIVE) {
|
||||||
|
r = abs(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
CRGB color;
|
||||||
|
if (_flags & SE_RANDOM_PIXEL_COLORS) {
|
||||||
|
color = CHSV(random8(), 255, abs(r*255));
|
||||||
|
} else {
|
||||||
|
color = CHSV(_flags & SE_CYCLE_COLORS ? baseHue : _color, r<0?0:255, abs(r*255));
|
||||||
|
}
|
||||||
|
|
||||||
|
window->setPixel(x, y, &color);
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,9 @@
|
|||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
|
|
||||||
Window* Window::getFullWindow() {
|
Window Window::window_full = Window();
|
||||||
static Window win;
|
Window Window::window_with_clock = Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
|
||||||
return &win;
|
Window Window::window_clock = Window(0, LED_HEIGHT-6, LED_WIDTH, 6);
|
||||||
}
|
|
||||||
|
|
||||||
void Window::setPixel(uint8_t x, uint8_t y, CRGB* color) {
|
void Window::setPixel(uint8_t x, uint8_t y, CRGB* color) {
|
||||||
if (x>=this->width || y>=this->height) return;
|
if (x>=this->width || y>=this->height) return;
|
||||||
@ -217,6 +216,11 @@ void Window::lineWithAngle(uint8_t x, uint8_t y, uint16_t angle, uint8_t startdi
|
|||||||
x1 = (x<<8) + (startdist<<8) * cos16(angle) / 0x10000;
|
x1 = (x<<8) + (startdist<<8) * cos16(angle) / 0x10000;
|
||||||
y1 = (y<<8) + (startdist<<8) * sin16(angle) / 0x10000;
|
y1 = (y<<8) + (startdist<<8) * sin16(angle) / 0x10000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (length==0) {
|
||||||
|
setSubPixel(x1, y1, color);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
saccum78 x2 = (x<<8) + ((startdist + length)<<8) * cos16(angle) / 0x10000;
|
saccum78 x2 = (x<<8) + ((startdist + length)<<8) * cos16(angle) / 0x10000;
|
||||||
saccum78 y2 = (y<<8) + ((startdist + length)<<8) * sin16(angle) / 0x10000;
|
saccum78 y2 = (y<<8) + ((startdist + length)<<8) * sin16(angle) / 0x10000;
|
||||||
@ -268,3 +272,14 @@ void Window::_subpixel_render(uint8_t x, uint8_t y, CRGB* color, SubpixelRenderi
|
|||||||
case SUBPIXEL_RENDERING_SET: setPixel(x, y, color); break;
|
case SUBPIXEL_RENDERING_SET: setPixel(x, y, color); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::fill_with_checkerboard() {
|
||||||
|
CRGB pink(0xFF00FF);
|
||||||
|
CRGB black(0x000000);
|
||||||
|
uint8_t s = (uint8_t)(millis() / 1000);
|
||||||
|
for(int x=0; x<this->width; x++) {
|
||||||
|
for(int y=0; y<this->height; y++) {
|
||||||
|
this->setPixel(x, y, ((x+y+s) % 2)?&pink:&black);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
#include "effect_confetti.h"
|
|
||||||
#include "config.h"
|
|
||||||
#include "functions.h"
|
|
||||||
#include "prototypes.h"
|
|
||||||
|
|
||||||
void ConfettiEffect::loop(uint16_t ms) {
|
|
||||||
window->fadeToBlackBy(3);
|
|
||||||
for (int i=0; i<settings.effects.confetti.pixels_per_loop; i++) {
|
|
||||||
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; };
|
|
122
src/effects.cpp
122
src/effects.cpp
@ -1,29 +1,32 @@
|
|||||||
#include "effects.h"
|
#include "effects.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "my_fastled.h"
|
#include "my_fastled.h"
|
||||||
#include "effect_bell.h"
|
#include "effects/bell.h"
|
||||||
#include "effect_sinematrix3.h"
|
#include "effects/sinematrix3.h"
|
||||||
#include "effect_big_clock.h"
|
#include "effects/big_clock.h"
|
||||||
#include "effect_clock.h"
|
#include "effects/clock.h"
|
||||||
#include "effect_static.h"
|
#include "effects/static.h"
|
||||||
#include "effect_animation.h"
|
#include "effects/animation.h"
|
||||||
#include "effect_dynamic.h"
|
#include "effects/dynamic.h"
|
||||||
#include "effect_matrix.h"
|
#include "effects/matrix.h"
|
||||||
#include "effect_twirl.h"
|
#include "effects/twirl.h"
|
||||||
#include "effect_cycle.h"
|
#include "effects/cycle.h"
|
||||||
#include "effect_confetti.h"
|
#include "effects/snake.h"
|
||||||
#include "effect_snake.h"
|
#include "effects/fire.h"
|
||||||
#include "effect_fire.h"
|
#include "effects/firework.h"
|
||||||
#include "effect_firework.h"
|
#include "effects/gol.h"
|
||||||
#include "effect_gol.h"
|
#include "effects/pixelclock.h"
|
||||||
#include "effect_pixelclock.h"
|
#include "effects/dvd.h"
|
||||||
#include "effect_dvd.h"
|
#include "effects/analogclock.h"
|
||||||
#include "effect_analogclock.h"
|
#include "effects/sines.h"
|
||||||
#include "effect_sines.h"
|
#include "effects/marquee.h"
|
||||||
#include "effect_marquee.h"
|
#include "effects/blur2d.h"
|
||||||
#include "effect_blur2d.h"
|
#include "effects/tv_static.h"
|
||||||
#include "effect_tv_static.h"
|
#include "effects/lightspeed.h"
|
||||||
#include "effect_lightspeed.h"
|
#include "effects/diamond.h"
|
||||||
|
#include "effects/tpm2_net.h"
|
||||||
|
#include "SimpleEffect.h"
|
||||||
|
#include "effects/night_clock.h"
|
||||||
|
|
||||||
Effect* current_effect;
|
Effect* current_effect;
|
||||||
|
|
||||||
@ -31,38 +34,49 @@ ClockEffect effect_clock;
|
|||||||
TimerEffect effect_timer;
|
TimerEffect effect_timer;
|
||||||
|
|
||||||
// We're using 0 instead of false to get a better visual difference between true and false.
|
// We're using 0 instead of false to get a better visual difference between true and false.
|
||||||
const EffectEntry effects[] = {
|
EffectEntry effects[] = {
|
||||||
/* 0 */ {"sinematrix3", true, [](){ return new Sinematrix3Effect(); }},
|
/* 0 */ {"sinematrix3", true, [](){ return new Sinematrix3Effect(); }},
|
||||||
/* 1 */ {"big_clock", true, [](){ return new BigClockEffect(); }},
|
/* 1 */ {"big_clock", true, [](){ return new BigClockEffect(); }},
|
||||||
/* 2 */ {"clock", 0, [](){ return new ClockEffect(); }},
|
/* 2 */ {"clock", 0, [](){ return new ClockEffect(); }},
|
||||||
/* 3 */ {"bell", 0, [](){ return new BellEffect(); }},
|
/* 3 */ {"bell", 0, [](){ return AnimationEffect::Blinker("/bell.pia", 300, 0xFFFF00); }},
|
||||||
/* 4 */ {"off", 0, [](){ return new StaticEffect(0x000000); }},
|
/* 4 */ {"off", 0, [](){ return new StaticEffect(0x000000); }},
|
||||||
/* 5 */ {"single_dynamic", true, [](){ return new SingleDynamicEffect(); }},
|
/* 5 */ {"single_dynamic", true, [](){ return new SingleDynamicEffect(); }},
|
||||||
/* 6 */ {"multi_dynamic", true, [](){ return new MultiDynamicEffect(); }},
|
/* 6 */ {"multi_dynamic", true, [](){ return new MultiDynamicEffect(); }},
|
||||||
/* 7 */ {"big_dynamic", true, [](){ return new BigDynamicEffect(); }},
|
/* 7 */ {"big_dynamic", true, [](){ return new BigDynamicEffect(); }},
|
||||||
/* 8 */ {"matrix", true, [](){ return new MatrixEffect(); }},
|
/* 8 */ {"matrix", true, [](){ return new MatrixEffect(); }},
|
||||||
/* 9 */ {"random_matrix", true, [](){ return new RandomMatrixEffect(); }},
|
/* 9 */ {"random_matrix", true, [](){ return new RandomMatrixEffect(); }},
|
||||||
/* 10 */ {"rainbow_matrix", true, [](){ return new RainbowMatrixEffect(); }},
|
/* 10 */ {"rainbow_matrix", true, [](){ return new RainbowMatrixEffect(); }},
|
||||||
/* 11 */ {"cycle", 0, [](){ return new CycleEffect(); }},
|
/* 11 */ {"cycle", 0, [](){ return new CycleEffect(); }},
|
||||||
/* 12 */ {"twirl", true, [](){ return new TwirlEffect(); }},
|
/* 12 */ {"twirl", true, [](){ return new TwirlEffect(); }},
|
||||||
/* 13 */ {"confetti", true, [](){ return new ConfettiEffect(); }},
|
/* 13 */ SIMPLE_EFFECT("confetti", true, SE_CYCLE_COLORS | SE_FADEOUT, {return random8()>252?1:0;}),
|
||||||
/* 14 */ {"random_confetti", true, [](){ return new RandomConfettiEffect(); }},
|
/* 14 */ SIMPLE_EFFECT("rainbow_confetti", true, SE_RANDOM_PIXEL_COLORS | SE_FADEOUT, {return random8()>252?1:0;}),
|
||||||
/* 15 */ {"snake", true, [](){ return new SnakeEffect(); }},
|
/* 15 */ {"snake", true, [](){ return new SnakeEffect(); }},
|
||||||
/* 16 */ {"firework", true, [](){ return new FireworkEffect(); }},
|
/* 16 */ {"firework", true, [](){ return new FireworkEffect(); }},
|
||||||
/* 17 */ {"gol", true, [](){ return new GolEffect(); }},
|
/* 17 */ {"gol", true, [](){ return new GolEffect(); }},
|
||||||
/* 18 */ {"pixel_clock", 0, [](){ return new PixelClockEffect(); }},
|
/* 18 */ {"pixel_clock", 0, [](){ return new PixelClockEffect(); }},
|
||||||
/* 19 */ {"dvd", 0, [](){ return new DvdEffect(); }},
|
/* 19 */ {"dvd", true, [](){ return new DvdEffect(); }},
|
||||||
/* 20 */ {"analog_clock", 0, [](){ return new AnalogClockEffect(); }},
|
/* 20 */ {"analog_clock", 0, [](){ return new AnalogClockEffect(); }},
|
||||||
/* 21 */ {"sines", true, [](){ return new SinesEffect(); }},
|
/* 21 */ {"sines", true, [](){ return new SinesEffect(); }},
|
||||||
/* 22 */ {"blur2d", true, [](){ return new Blur2DEffect(); }},
|
/* 22 */ {"blur2d", true, [](){ return new Blur2DEffect(); }},
|
||||||
/* 23 */ {"marquee", 0, [](){ return new MarqueeEffect(); }},
|
/* 23 */ {"marquee", 0, [](){ return new MarqueeEffect(); }},
|
||||||
/* 24 */ {"night_clock", 0, [](){ return new NightClockEffect(); }},
|
/* 24 */ {"night_clock", 0, [](){ return new NightClockEffect(); }},
|
||||||
/* 25 */ {"tv_static", 0, [](){ return new TvStaticEffect(); }},
|
/* 25 */ {"tv_static", 0, [](){ return new TvStaticEffect(); }},
|
||||||
/* 26 */ {"sinematrix3_rainbow", true, [](){ return new Sinematrix3Effect(SINEMATRIX_COLOR_RAINBOW); }},
|
/* 26 */ {"sinematrix3_rainbow", true, [](){ return new Sinematrix3Effect(SINEMATRIX_COLOR_RAINBOW); }},
|
||||||
/* 27 */ {"sinematrix3_purplefly", true, [](){ return new Sinematrix3Effect(SINEMATRIX_COLOR_PURPLEFLY); }},
|
/* 27 */ {"sinematrix3_purplefly", true, [](){ return new Sinematrix3Effect(SINEMATRIX_COLOR_PURPLEFLY); }},
|
||||||
/* 28 */ {"lightspeed", true, [](){ return new LightspeedEffect(); }},
|
/* 28 */ {"lightspeed", true, [](){ return new LightspeedEffect(); }},
|
||||||
|
/* 29 */ {"koopa", 0, [](){ return new AnimationEffect("/koopa.pia"); }},
|
||||||
|
/* 30 */ {"cake", 0, [](){ return new AnimationEffect("/cake.pia"); }},
|
||||||
|
/* 31 */ {"child", 0, [](){ return AnimationEffect::Blinker("/child.pia", 300, 0xFFFF00); }},
|
||||||
|
/* 32 */ {"diamond", true, [](){ return new DiamondEffect(); }},
|
||||||
|
/* 33 */ {"tpm2.net", 0, [](){ return new Tpm2NetEffect(); }},
|
||||||
|
/* 34 */ SIMPLE_EFFECT("slow_blinking", true, SE_CYCLE_COLORS, {return sin(t + (x+1)*(y+1)*i);} ),
|
||||||
|
/* 35 */ SIMPLE_EFFECT("upwave", true, SE_CYCLE_COLORS, {return (cos(t+y/2));} ),
|
||||||
|
/* 36 */ SIMPLE_EFFECT("centerwave", true, SE_CYCLE_COLORS, {return sin(t*2 - sqrt((x-4)*(x-4) + (y-7)*(y-7)));} ),
|
||||||
|
/* 37 */ SIMPLE_EFFECT("sineline", true, SE_RANDOM_STATIC_COLOR, {return sin(x/2)-sin(x-t)-y+6;} ),
|
||||||
|
/* 38 */ SIMPLE_EFFECT("barbershop", true, SE_RANDOM_STATIC_COLOR, {return 1*cos(0.8*i-t*5);} ),
|
||||||
|
/* 39 */ SIMPLE_EFFECT("zigzag", true, SE_CYCLE_COLORS, { return cos(cos(x+y)-y*cos(t/8+x/16));} ),
|
||||||
};
|
};
|
||||||
const uint8_t effects_size = 29;
|
const uint8_t effects_size = 40;
|
||||||
|
|
||||||
|
|
||||||
Effect* select_effect(const char* name) {
|
Effect* select_effect(const char* name) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_analogclock.h"
|
#include "effects/analogclock.h"
|
||||||
#include "my_fastled.h"
|
#include "my_fastled.h"
|
||||||
#include "ntp.h"
|
#include "ntp.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_animation.h"
|
#include "effects/animation.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
|
|
||||||
AnimationEffect::AnimationEffect(const char* name, uint32_t bg, int x, int y) {
|
AnimationEffect::AnimationEffect(const char* name, uint32_t bg, int x, int y) {
|
||||||
@ -9,6 +9,8 @@ AnimationEffect::AnimationEffect(const char* name, uint32_t bg, int x, int y) {
|
|||||||
this->animation = new Animation(name, window);
|
this->animation = new Animation(name, window);
|
||||||
this->animation->setBgColor(bg);
|
this->animation->setBgColor(bg);
|
||||||
this->animation->setOffsets(this->xOffset, this->yOffset);
|
this->animation->setOffsets(this->xOffset, this->yOffset);
|
||||||
|
|
||||||
|
_last_blink_at = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimationEffect* AnimationEffect::setFgColor(uint32_t c) {
|
AnimationEffect* AnimationEffect::setFgColor(uint32_t c) {
|
||||||
@ -16,11 +18,23 @@ AnimationEffect* AnimationEffect::setFgColor(uint32_t c) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AnimationEffect* AnimationEffect::setBlinkFrequency(uint16_t ms) {
|
||||||
|
_blink_freq = ms;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
AnimationEffect::~AnimationEffect() {
|
AnimationEffect::~AnimationEffect() {
|
||||||
delete this->animation;
|
delete this->animation;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationEffect::loop(uint16_t ms) {
|
void AnimationEffect::loop(uint16_t ms) {
|
||||||
|
if (_blink_freq > 0) {
|
||||||
|
unsigned long mil = millis();
|
||||||
|
if (mil < _last_blink_at || _last_blink_at + _blink_freq <= mil) {
|
||||||
|
this->animation->invert();
|
||||||
|
_last_blink_at = mil;
|
||||||
|
}
|
||||||
|
}
|
||||||
this->animation->drawFrame();
|
this->animation->drawFrame();
|
||||||
this->animation->advance();
|
this->animation->advance();
|
||||||
}
|
}
|
||||||
@ -30,3 +44,10 @@ String AnimationEffect::get_name() {
|
|||||||
s += this->name;
|
s += this->name;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AnimationEffect* AnimationEffect::Blinker(const char* name, uint16_t interval, uint32_t color, uint32_t background_color) {
|
||||||
|
AnimationEffect* anim = new AnimationEffect(name, background_color);
|
||||||
|
anim->setFgColor(color);
|
||||||
|
anim->setBlinkFrequency(interval);
|
||||||
|
return anim;
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
#include "Effect.h"
|
#include "Effect.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
#include "effect_bell.h"
|
#include "effects/bell.h"
|
||||||
#include "sprites.h"
|
#include "sprites.h"
|
||||||
|
|
||||||
void BellEffect::loop(uint16_t ms) {
|
void BellEffect::loop(uint16_t ms) {
|
@ -1,5 +1,5 @@
|
|||||||
#include "Effect.h"
|
#include "Effect.h"
|
||||||
#include "effect_big_clock.h"
|
#include "effects/big_clock.h"
|
||||||
#include "fonts.h"
|
#include "fonts.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@ -11,35 +11,43 @@ void BigClockEffect::loop(uint16_t ms) {
|
|||||||
time(&now);
|
time(&now);
|
||||||
localtime_r(&now, &timeinfo);
|
localtime_r(&now, &timeinfo);
|
||||||
uint8_t h = timeinfo.tm_hour;
|
uint8_t h = timeinfo.tm_hour;
|
||||||
window->drawChar(&font_numbers3x5_blocky, 6<<8, 2<<8, '0' + (h / 10), &_color_font);
|
CRGB color = _get_color_font();
|
||||||
window->drawChar(&font_numbers3x5_blocky, 11<<8, 2<<8, '0' + (h % 10), &_color_font);
|
window->drawChar(&font_numbers3x5_blocky, 6<<8, 2<<8, '0' + (h / 10), &color);
|
||||||
|
window->drawChar(&font_numbers3x5_blocky, 11<<8, 2<<8, '0' + (h % 10), &color);
|
||||||
|
|
||||||
uint8_t m = timeinfo.tm_min;
|
uint8_t m = timeinfo.tm_min;
|
||||||
window->drawChar(&font_numbers3x5_blocky, 6<<8, 9<<8, '0' + (m / 10), &_color_font);
|
window->drawChar(&font_numbers3x5_blocky, 6<<8, 9<<8, '0' + (m / 10), &color);
|
||||||
window->drawChar(&font_numbers3x5_blocky, 11<<8, 9<<8, '0' + (m % 10), &_color_font);
|
window->drawChar(&font_numbers3x5_blocky, 11<<8, 9<<8, '0' + (m % 10), &color);
|
||||||
|
|
||||||
uint8_t s = timeinfo.tm_sec;
|
uint8_t s = timeinfo.tm_sec;
|
||||||
if (s & 1) {
|
_draw_colon(s & 1);
|
||||||
window->setPixel(3, 10, &_color_font);
|
|
||||||
window->setPixel(3, 12, &_color_font);
|
|
||||||
}
|
|
||||||
|
|
||||||
_draw_seconds(timeinfo.tm_sec);
|
_draw_seconds(timeinfo.tm_sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BigClockEffect::_draw_colon(bool odd) {
|
||||||
|
if (odd) {
|
||||||
|
CRGB color = _get_color_font();
|
||||||
|
window->setPixel(3, 10, &color);
|
||||||
|
window->setPixel(3, 12, &color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BigClockEffect::_draw_seconds(uint8_t seconds) {
|
void BigClockEffect::_draw_seconds(uint8_t seconds) {
|
||||||
for (int i=1; i<=seconds; i++) {
|
for (int i=1; i<=seconds; i++) {
|
||||||
_draw_border_pixel(i<<8, (i%5==0) ? &_color_seconds_light : &_color_seconds_dark);
|
_draw_border_pixel(i<<8, (i%5==0) ? &_color_seconds_light : &_color_seconds_dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t mil = millis() % 1000;
|
/*timeval tv;
|
||||||
|
gettimeofday(&tv, nullptr);
|
||||||
|
uint16_t mil = (tv.tv_usec / 1000) % 1000;
|
||||||
accum88 pos = (seconds<<8) + ((settings.effects.big_clock.spacing-1)<<8) * (1000 - mil) / 1000 + (1<<8);
|
accum88 pos = (seconds<<8) + ((settings.effects.big_clock.spacing-1)<<8) * (1000 - mil) / 1000 + (1<<8);
|
||||||
uint8_t sec = seconds + 1;
|
uint8_t sec = seconds + 1;
|
||||||
while (pos < (60<<8)) {
|
while (pos < (60<<8)) {
|
||||||
_draw_border_pixel(pos, sec%5==0 ? &_color_seconds_moving_light : &_color_seconds_moving_dark);
|
_draw_border_pixel(pos, sec%5==0 ? &_color_seconds_moving_light : &_color_seconds_moving_dark);
|
||||||
pos += settings.effects.big_clock.spacing<<8;
|
pos += settings.effects.big_clock.spacing<<8;
|
||||||
sec++;
|
sec++;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void BigClockEffect::_draw_border_pixel(accum88 i, CRGB* color) {
|
void BigClockEffect::_draw_border_pixel(accum88 i, CRGB* color) {
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_blur2d.h"
|
#include "effects/blur2d.h"
|
||||||
Blur2DBlob::Blur2DBlob() {
|
Blur2DBlob::Blur2DBlob() {
|
||||||
_x_freq = random16(6<<8, 15<<8);
|
_x_freq = random16(6<<8, 15<<8);
|
||||||
_y_freq = random16(6<<8, 15<<8);
|
_y_freq = random16(6<<8, 15<<8);
|
||||||
@ -45,5 +45,4 @@ void Blur2DEffect::_delete() {
|
|||||||
|
|
||||||
Blur2DEffect::~Blur2DEffect() {
|
Blur2DEffect::~Blur2DEffect() {
|
||||||
_delete();
|
_delete();
|
||||||
delete window;
|
|
||||||
}
|
}
|
@ -1,21 +1,9 @@
|
|||||||
#include "effect_clock.h"
|
#include "effects/clock.h"
|
||||||
#include <FastLED.h>
|
#include <FastLED.h>
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
#include "fonts.h"
|
#include "fonts.h"
|
||||||
#include "ntp.h"
|
#include "ntp.h"
|
||||||
|
|
||||||
NightClockEffect::NightClockEffect() {
|
|
||||||
window = Window::getFullWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NightClockEffect::loop(uint16_t ms) {
|
|
||||||
uint16_t minutes = minutes16();
|
|
||||||
//uint8_t y = minutes % ((window->height - 5) * 2 - 2);
|
|
||||||
//if (y > window->height - 5) y = 2*window->height - 2*y;
|
|
||||||
uint8_t y = minutes % 10;
|
|
||||||
ClockEffect::loop(false, CRGB(0x200000), CRGB(0x000000), y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClockEffect::loop(uint16_t ms) {
|
void ClockEffect::loop(uint16_t ms) {
|
||||||
loop_with_invert(false);
|
loop_with_invert(false);
|
||||||
}
|
}
|
||||||
@ -64,9 +52,4 @@ void ClockEffect::loop(boolean invert, CRGB fg_color, CRGB bg_color, uint8_t yPo
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClockEffect::~ClockEffect() {
|
ClockEffect::~ClockEffect() {
|
||||||
delete window;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NightClockEffect::~NightClockEffect() {
|
|
||||||
delete window;
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_cycle.h"
|
#include "effects/cycle.h"
|
||||||
#include "effects.h"
|
#include "effects.h"
|
||||||
|
|
||||||
CycleEffect::CycleEffect() {
|
CycleEffect::CycleEffect() {
|
||||||
@ -26,31 +26,46 @@ void CycleEffect::changeEffect() {
|
|||||||
LOGln("CycleEffect * Changing effect from #%d to #%d", effect_id, new_id);
|
LOGln("CycleEffect * Changing effect from #%d to #%d", effect_id, new_id);
|
||||||
delay(25);
|
delay(25);
|
||||||
|
|
||||||
if (effect) delete effect;
|
String old_effect_name = String("UNKNOWN");
|
||||||
|
if (effect) {
|
||||||
|
old_effect_name = effect->get_name();
|
||||||
|
delete effect;
|
||||||
|
}
|
||||||
|
|
||||||
int16_t diff;
|
int16_t diff = 0;
|
||||||
uint16_t old_heap = _heap_free;
|
uint16_t old_heap = _heap_free;
|
||||||
_heap_free = ESP.getFreeHeap();
|
_heap_free = ESP.getFreeHeap();
|
||||||
if (old_heap) {
|
if (old_heap) {
|
||||||
// diff positive = More heap used (baad)
|
// diff positive = More heap used (baad)
|
||||||
// diff negative = Less heap used (good-ish)
|
// diff negative = Less heap used (good-ish)
|
||||||
diff = old_heap - _heap_free;
|
diff = old_heap - _heap_free;
|
||||||
LOGln("CycleEffect * Heap usage: #%d,%d,%+d", effect_id, _heap_free, diff);
|
LOGln("CycleEffect * Heap usage: #%d,%s,%d,%+d", effect_id, old_effect_name.c_str(), _heap_free, diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(25);
|
delay(25);
|
||||||
LOGln("CycleEffect * Searching for new effect #%d", new_id);
|
LOGln("CycleEffect * Searching for new effect #%d", new_id);
|
||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
|
EffectEntry* e = nullptr;
|
||||||
for (uint8_t i=0; i<effects_size; i++) {
|
for (uint8_t i=0; i<effects_size; i++) {
|
||||||
if (effects[i].use_in_cycle) {
|
if (effects[i].use_in_cycle) {
|
||||||
if (count == new_id) {
|
if (count == new_id) {
|
||||||
effect = effects[i].create();
|
e = &effects[i];
|
||||||
|
effect = e->create();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (effect) {
|
if (e) {
|
||||||
|
#ifdef MQTT_REPORT_METRICS
|
||||||
|
e->heap_change_sum += diff;
|
||||||
|
e->run_count++;
|
||||||
|
LOGln("CycleEffect * Last effect stats: name:%s, runs:%d, total_change:%d", old_effect_name.c_str(), e->run_count, e->heap_change_sum);
|
||||||
|
String topic = "metrics/effects/";
|
||||||
|
topic.concat(old_effect_name);
|
||||||
|
String message = String("runs:") + e->run_count + ", total_heap_change:" + e->heap_change_sum;
|
||||||
|
mqtt_publish(topic.c_str(), message.c_str(), true);
|
||||||
|
#endif
|
||||||
effect_id = new_id;
|
effect_id = new_id;
|
||||||
effectSince = millis();
|
effectSince = millis();
|
||||||
LOGln("CycleEffect * Effect %s found", effect->get_name().c_str());
|
LOGln("CycleEffect * Effect %s found", effect->get_name().c_str());
|
14
src/effects/diamond.cpp
Normal file
14
src/effects/diamond.cpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include "effects/diamond.h"
|
||||||
|
#include "my_fastled.h"
|
||||||
|
|
||||||
|
void DiamondEffect::loop(uint16_t ms) {
|
||||||
|
for (int x=0; x<window->width; x++) {
|
||||||
|
for (int y=0; y<window->height; y++) {
|
||||||
|
uint8_t distance = abs(window->height/2 - y) + abs(window->width/2 - x);
|
||||||
|
CRGB col = CHSV(distance*8 - (millis()>>5)%255, 255, 255);
|
||||||
|
window->setPixel(x, y, &col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DiamondEffect::can_be_shown_with_clock() { return true; }
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_dvd.h"
|
#include "effects/dvd.h"
|
||||||
#include "my_fastled.h"
|
#include "my_fastled.h"
|
||||||
|
|
||||||
void DvdEffect::loop(uint16_t ms) {
|
void DvdEffect::loop(uint16_t ms) {
|
||||||
@ -47,5 +47,4 @@ DvdEffect::DvdEffect() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DvdEffect::~DvdEffect() {
|
DvdEffect::~DvdEffect() {
|
||||||
delete window;
|
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_dynamic.h"
|
#include "effects/dynamic.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@ -36,7 +36,6 @@ void MultiDynamicEffect::loop(uint16_t ms) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BigDynamicEffect::~BigDynamicEffect() {
|
BigDynamicEffect::~BigDynamicEffect() {
|
||||||
delete window;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BigDynamicEffect::loop(uint16_t ms) {
|
void BigDynamicEffect::loop(uint16_t ms) {
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_fire.h"
|
#include "effects/fire.h"
|
||||||
#include "my_color_palettes.h"
|
#include "my_color_palettes.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "my_fastled.h"
|
#include "my_fastled.h"
|
@ -1,5 +1,5 @@
|
|||||||
// Based on https://gist.github.com/kriegsman/68929cbd1d6de4535b20
|
// Based on https://gist.github.com/kriegsman/68929cbd1d6de4535b20
|
||||||
#include "effect_firework.h"
|
#include "effects/firework.h"
|
||||||
|
|
||||||
FireworkEffectDot::FireworkEffectDot(Window* w, FireworkEffect* e) {
|
FireworkEffectDot::FireworkEffectDot(Window* w, FireworkEffect* e) {
|
||||||
_window = w;
|
_window = w;
|
||||||
@ -176,7 +176,6 @@ FireworkEffect::FireworkEffect() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FireworkEffect::~FireworkEffect() {
|
FireworkEffect::~FireworkEffect() {
|
||||||
delete window;
|
|
||||||
for (int i=0; i<settings.effects.firework.sparks; i++) {
|
for (int i=0; i<settings.effects.firework.sparks; i++) {
|
||||||
delete _sparks[i];
|
delete _sparks[i];
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
#include "effect_gol.h"
|
#include "effects/gol.h"
|
||||||
#include "my_fastled.h"
|
#include "my_fastled.h"
|
||||||
|
|
||||||
GolEffect::GolEffect() {
|
GolEffect::GolEffect() {
|
||||||
this->window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
|
this->window = &Window::window_with_clock;
|
||||||
|
|
||||||
_data = new uint8_t[this->window->count];
|
_data = new uint8_t[this->window->count];
|
||||||
_old = new uint8_t[this->window->count];
|
_old = new uint8_t[this->window->count];
|
||||||
@ -26,7 +26,6 @@ void GolEffect::_initialize() {
|
|||||||
GolEffect::~GolEffect() {
|
GolEffect::~GolEffect() {
|
||||||
delete[] _data;
|
delete[] _data;
|
||||||
delete[] _old;
|
delete[] _old;
|
||||||
delete window;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GolEffect::loop(uint16_t ms) {
|
void GolEffect::loop(uint16_t ms) {
|
@ -1,15 +1,14 @@
|
|||||||
#include "effect_lightspeed.h"
|
#include "effects/lightspeed.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
|
|
||||||
LightspeedEffect::LightspeedEffect() {
|
LightspeedEffect::LightspeedEffect() {
|
||||||
window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
|
window = &Window::window_with_clock;
|
||||||
_init();
|
_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
LightspeedEffect::~LightspeedEffect() {
|
LightspeedEffect::~LightspeedEffect() {
|
||||||
delete window;
|
|
||||||
_delete();
|
_delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,11 +39,12 @@ boolean LightspeedEffect::can_be_shown_with_clock() { return true; };
|
|||||||
|
|
||||||
LightspeedEffectStar::LightspeedEffectStar() {
|
LightspeedEffectStar::LightspeedEffectStar() {
|
||||||
_init();
|
_init();
|
||||||
|
_distance = random16(10<<8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightspeedEffectStar::_init() {
|
void LightspeedEffectStar::_init() {
|
||||||
_angle = random16();
|
_angle = random16();
|
||||||
_start = 0;
|
_distance = 0;
|
||||||
_speed = random16(128, 2<<8);
|
_speed = random16(128, 2<<8);
|
||||||
_target = random16(25<<8, 35<<8);
|
_target = random16(25<<8, 35<<8);
|
||||||
_saturation = random8(100);
|
_saturation = random8(100);
|
||||||
@ -52,12 +52,14 @@ void LightspeedEffectStar::_init() {
|
|||||||
|
|
||||||
void LightspeedEffectStar::loop(Window* win) {
|
void LightspeedEffectStar::loop(Window* win) {
|
||||||
CRGB col = CHSV(192, _saturation, 255);
|
CRGB col = CHSV(192, _saturation, 255);
|
||||||
if (_start < (8<<8)) {
|
accum88 current_speed = _speed * beatsin16(0x100, 0, 65535) / 65535;
|
||||||
win->lineWithAngle(win->width/2, win->height/2, _angle, 0, _start>>8, &col);
|
uint8_t length = (current_speed>>6);
|
||||||
|
if (_distance < (length<<8)) {
|
||||||
|
win->lineWithAngle(win->width/2, win->height/2, _angle, 0, _distance>>8, &col);
|
||||||
} else {
|
} else {
|
||||||
win->lineWithAngle(win->width/2, win->height/2, _angle, (_start>>8) - 8, 8, &col);
|
win->lineWithAngle(win->width/2, win->height/2, _angle, (_distance>>8) - length, length, &col);
|
||||||
}
|
}
|
||||||
_start+=_speed;
|
_distance += current_speed;
|
||||||
//_angle+=8<<8;
|
//_angle+=8<<8;
|
||||||
if (_start > _target) _init();
|
if (_distance > _target) _init();
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_marquee.h"
|
#include "effects/marquee.h"
|
||||||
#include "fonts.h"
|
#include "fonts.h"
|
||||||
|
|
||||||
boolean MarqueeEffect::can_be_shown_with_clock() {
|
boolean MarqueeEffect::can_be_shown_with_clock() {
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_matrix.h"
|
#include "effects/matrix.h"
|
||||||
#include "my_color_palettes.h"
|
#include "my_color_palettes.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
|
|
26
src/effects/night_clock.cpp
Normal file
26
src/effects/night_clock.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "Effect.h"
|
||||||
|
#include "effects/night_clock.h"
|
||||||
|
#include "fonts.h"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
void NightClockEffect::loop(uint16_t ms) {
|
||||||
|
window->clear();
|
||||||
|
time_t now;
|
||||||
|
tm timeinfo;
|
||||||
|
time(&now);
|
||||||
|
localtime_r(&now, &timeinfo);
|
||||||
|
uint8_t h = timeinfo.tm_hour;
|
||||||
|
CRGB color = CRGB(0x440000);
|
||||||
|
window->drawChar(&font5x7, 4<<8, 0<<8, '0' + (h / 10), &color);
|
||||||
|
window->drawChar(&font5x7, 10<<8, 0<<8, '0' + (h % 10), &color);
|
||||||
|
|
||||||
|
uint8_t m = timeinfo.tm_min;
|
||||||
|
window->drawChar(&font5x7, 4<<8, 9<<8, '0' + (m / 10), &color);
|
||||||
|
window->drawChar(&font5x7, 10<<8, 9<<8, '0' + (m % 10), &color);
|
||||||
|
|
||||||
|
uint8_t s = timeinfo.tm_sec;
|
||||||
|
if(s & 1) {
|
||||||
|
window->setPixel(2, 11, &color);
|
||||||
|
window->setPixel(2, 13, &color);
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
#include "effect_pixelclock.h"
|
#include "effects/pixelclock.h"
|
||||||
#include "ntp.h"
|
#include "ntp.h"
|
||||||
|
|
||||||
PixelClockEffect::PixelClockEffect() {
|
PixelClockEffect::PixelClockEffect() {
|
||||||
window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
|
window = &Window::window_with_clock;
|
||||||
_color_seconds = new CRGB(0x00FF00);
|
_color_seconds = new CRGB(0x00FF00);
|
||||||
_color_minutes = new CRGB(0xFFFF00);
|
_color_minutes = new CRGB(0xFFFF00);
|
||||||
}
|
}
|
||||||
@ -10,7 +10,6 @@ PixelClockEffect::PixelClockEffect() {
|
|||||||
PixelClockEffect::~PixelClockEffect() {
|
PixelClockEffect::~PixelClockEffect() {
|
||||||
delete _color_seconds;
|
delete _color_seconds;
|
||||||
delete _color_minutes;
|
delete _color_minutes;
|
||||||
delete window;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PixelClockEffect::loop(uint16_t ms) {
|
void PixelClockEffect::loop(uint16_t ms) {
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_sinematrix3.h"
|
#include "effects/sinematrix3.h"
|
||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
#include "Effect.h"
|
#include "Effect.h"
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_sines.h"
|
#include "effects/sines.h"
|
||||||
|
|
||||||
SinesEffectSinus::SinesEffectSinus(Window* w) {
|
SinesEffectSinus::SinesEffectSinus(Window* w) {
|
||||||
_window = w;
|
_window = w;
|
@ -1,8 +1,8 @@
|
|||||||
#include "effect_snake.h"
|
#include "effects/snake.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
|
|
||||||
SnakeEffect::SnakeEffect() {
|
SnakeEffect::SnakeEffect() {
|
||||||
window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
|
window = &Window::window_with_clock;
|
||||||
_pixels = window->width * window->height;
|
_pixels = window->width * window->height;
|
||||||
_map = new uint8_t[_pixels];
|
_map = new uint8_t[_pixels];
|
||||||
_init();
|
_init();
|
||||||
@ -25,15 +25,10 @@ void SnakeEffect::_init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SnakeEffect::~SnakeEffect() {
|
SnakeEffect::~SnakeEffect() {
|
||||||
delete window;
|
|
||||||
delete _map;
|
delete _map;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SnakeEffect::_place_apple() {
|
void SnakeEffect::_place_apple() {
|
||||||
if (SNAKE_DEBUG) {
|
|
||||||
_apple = {3, 3};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (_length < _pixels) {
|
if (_length < _pixels) {
|
||||||
uint8_t start = random8(_pixels);
|
uint8_t start = random8(_pixels);
|
||||||
for (int i=0; i<_pixels; i++) {
|
for (int i=0; i<_pixels; i++) {
|
||||||
@ -60,7 +55,7 @@ void SnakeEffect::_decide() {
|
|||||||
inputs[3] = a_l;
|
inputs[3] = a_l;
|
||||||
inputs[4] = a_s;
|
inputs[4] = a_s;
|
||||||
inputs[5] = a_r;
|
inputs[5] = a_r;
|
||||||
if (SNAKE_DEBUG) LOGln("SnakeEffect * Position: %d, %d - Inputs: %3.1f %3.1f %3.1f %3.1f %3.1f %3.1f", _pos.x, _pos.y, inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5]);
|
if (SNAKE_DEBUG) DBG("SnakeEffect * Position: %d, %d - Inputs: %3.1f %3.1f %3.1f %3.1f %3.1f %3.1f", _pos.x, _pos.y, inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5]);
|
||||||
float* outputs = NULL;
|
float* outputs = NULL;
|
||||||
uint8_t i=0;
|
uint8_t i=0;
|
||||||
for (uint8_t layer=1; layer<_net_layers; layer++) {
|
for (uint8_t layer=1; layer<_net_layers; layer++) {
|
||||||
@ -92,7 +87,7 @@ void SnakeEffect::_decide() {
|
|||||||
decision = decision - 1;
|
decision = decision - 1;
|
||||||
delete outputs;
|
delete outputs;
|
||||||
|
|
||||||
if (SNAKE_DEBUG) LOGln("SnakeEffect * Decision: %d", decision);
|
if (SNAKE_DEBUG) DBG("SnakeEffect * Decision: %d", decision);
|
||||||
|
|
||||||
_dir += decision;
|
_dir += decision;
|
||||||
if (_dir < 0) _dir += 4;
|
if (_dir < 0) _dir += 4;
|
||||||
@ -124,6 +119,65 @@ int8_t SnakeEffect::_manual_decision() {
|
|||||||
return 0;
|
return 0;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
/* This uses a predefined meandering path through the complete field.
|
||||||
|
The snake always tries to reach the field matching following criteria:
|
||||||
|
(1) Being free.
|
||||||
|
(2) Having a number smaller than the field the apple is on. (Watch out for "overflows".)
|
||||||
|
*/
|
||||||
|
int8_t SnakeEffect::_manual_decision() {
|
||||||
|
uint8_t head_index = _coords_to_field_id(_pos);
|
||||||
|
uint8_t apple_index = _coords_to_field_id(_apple);
|
||||||
|
uint8_t tail_index = _coords_to_field_id(_tail);
|
||||||
|
if (SNAKE_DEBUG) DBG("SnakeEffect * Decision. head: %d, apple: %d, tail: %d", head_index, apple_index, tail_index);
|
||||||
|
|
||||||
|
uint16_t best_distance = 0xFFFF;
|
||||||
|
int8_t decision = 0;
|
||||||
|
|
||||||
|
for (int i=-1; i<=1; i++) { // Test all thre possible directions (left, ahead, right)
|
||||||
|
Coords new_pos = _new_pos(_dir + i);
|
||||||
|
uint8_t new_index = _coords_to_field_id(new_pos);
|
||||||
|
|
||||||
|
int16_t distance;
|
||||||
|
if (apple_index >= new_index) {
|
||||||
|
distance = apple_index - new_index;
|
||||||
|
} else {
|
||||||
|
distance = (window->width * window->height) - apple_index + new_index;
|
||||||
|
}
|
||||||
|
if (SNAKE_DEBUG) DBG("SnakeEffect * Decision: %d would have distance %d", i, distance);
|
||||||
|
if (distance < best_distance && _is_free(_dir + i)) {
|
||||||
|
best_distance = distance;
|
||||||
|
decision = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SNAKE_DEBUG) DBG("SnakeEffect * Decision taken: %d with distance %d", decision, best_distance);
|
||||||
|
|
||||||
|
/* apple_index > new_index && head_index > apple_index
|
||||||
|
apple_index > new_index && head_index < apple_index && new_index > head_index
|
||||||
|
|
||||||
|
uint16_t head_index = (_head_rounds<<8) | _coords_to_field_id(_pos);
|
||||||
|
uint16_t apple_index = (_head_rounds<<8) | _coords_to_field_id(_apple);
|
||||||
|
uint16_t tail_index = (_tail_rounds<<8) | _coords_to_field_id(_tail);
|
||||||
|
|
||||||
|
if (apple_index < head_index) apple_index += 0x100;
|
||||||
|
|
||||||
|
uint8_t best_dist = 0xFF;
|
||||||
|
int8_t decision = 0;
|
||||||
|
for (int i=-1; i<=1; i++) {
|
||||||
|
Coords new_pos = _new_pos(_dir + i);
|
||||||
|
uint16_t theoretical_index = (_head_rounds<<8) | _coords_to_field_id(new_pos);
|
||||||
|
if (theoretical_index < head_index) theoretical_index += 0x100;
|
||||||
|
int16_t dist = apple_index - theoretical_index;
|
||||||
|
if (dist < 0) dist += window->height * window->width;
|
||||||
|
if (dist < best_dist && _is_free(_dir + i) && theoretical_index<tail_index && theoretical_index<tail_index) {
|
||||||
|
decision = i;
|
||||||
|
best_dist = dist;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
_dir = (_dir + decision) % 4;
|
||||||
|
return decision;
|
||||||
|
}
|
||||||
|
|
||||||
bool SnakeEffect::_is_free(uint8_t dir) {
|
bool SnakeEffect::_is_free(uint8_t dir) {
|
||||||
return _free_spaces(dir)!=0;
|
return _free_spaces(dir)!=0;
|
||||||
}
|
}
|
||||||
@ -150,6 +204,17 @@ uint8_t SnakeEffect::_free_spaces(uint8_t dir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t SnakeEffect::_coords_to_field_id(Coords c) {
|
||||||
|
if (c.y==0) return window->width - c.x;
|
||||||
|
if (c.x % 2 == 0) {
|
||||||
|
// even columns
|
||||||
|
return window->width + c.x*(window->height - 1) + c.y - 1;
|
||||||
|
} else {
|
||||||
|
// odd columns
|
||||||
|
return window->width + (c.x+1)*(window->height-1) - c.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t SnakeEffect::_to_apple(uint8_t dir) {
|
uint8_t SnakeEffect::_to_apple(uint8_t dir) {
|
||||||
uint8_t d = dir % 4;
|
uint8_t d = dir % 4;
|
||||||
int8_t d_x = _apple.x - _pos.x;
|
int8_t d_x = _apple.x - _pos.x;
|
||||||
@ -202,12 +267,12 @@ void SnakeEffect::_move() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
if (_last_move_at < now && now - _last_move_at < 0) {
|
if (_last_move_at < now && now - _last_move_at < 50) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_round++;
|
_round++;
|
||||||
_last_move_at = now;
|
_last_move_at = now;
|
||||||
_decide();
|
_manual_decision();
|
||||||
|
|
||||||
if (_dying==0 && !_is_free(_dir)) {
|
if (_dying==0 && !_is_free(_dir)) {
|
||||||
_dying = 150;
|
_dying = 150;
|
||||||
@ -215,6 +280,10 @@ void SnakeEffect::_move() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_pos = _new_pos(_dir);
|
_pos = _new_pos(_dir);
|
||||||
|
|
||||||
|
uint8_t index_head = _coords_to_field_id(_pos);
|
||||||
|
uint8_t index_tail = _coords_to_field_id(_tail);
|
||||||
|
|
||||||
if (SNAKE_DEBUG) LOGln("SnakeEffect * new_pos: %d, %d", _pos.x, _pos.y);
|
if (SNAKE_DEBUG) LOGln("SnakeEffect * new_pos: %d, %d", _pos.x, _pos.y);
|
||||||
if (SNAKE_DEBUG) LOGln("SnakeEffect * apple: %d, %d", _apple.x, _apple.y);
|
if (SNAKE_DEBUG) LOGln("SnakeEffect * apple: %d, %d", _apple.x, _apple.y);
|
||||||
if (_pos.x==_apple.x && _pos.y==_apple.y) {
|
if (_pos.x==_apple.x && _pos.y==_apple.y) {
|
||||||
@ -222,13 +291,26 @@ void SnakeEffect::_move() {
|
|||||||
_length++;
|
_length++;
|
||||||
}
|
}
|
||||||
for (int i=0; i<_pixels; i++) {
|
for (int i=0; i<_pixels; i++) {
|
||||||
if (_map[i]>0 && _map[i]<_length-1) _map[i]++;
|
if (_map[i]>0 && _map[i]<_length-1) {
|
||||||
|
_map[i]++;
|
||||||
|
if (_map[i]==_length-1) {
|
||||||
|
_tail = _i2xy(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
else _map[i]=0;
|
else _map[i]=0;
|
||||||
}
|
}
|
||||||
_map[_xy2i(_pos)] = 1;
|
_map[_xy2i(_pos)] = 1;
|
||||||
if (_pos.x==_apple.x && _pos.y==_apple.y) {
|
if (_pos.x==_apple.x && _pos.y==_apple.y) {
|
||||||
_place_apple();
|
_place_apple();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (index_head > _coords_to_field_id(_pos)) _head_rounds++;
|
||||||
|
if (index_tail > _coords_to_field_id(_tail)) _tail_rounds++;
|
||||||
|
if (_head_rounds > 0 && _head_rounds > 0) {
|
||||||
|
uint8_t min = (_head_rounds < _tail_rounds) ? _tail_rounds : _head_rounds;
|
||||||
|
_head_rounds -= min;
|
||||||
|
_tail_rounds -= min;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SnakeEffect::_draw() {
|
void SnakeEffect::_draw() {
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_static.h"
|
#include "effects/static.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
#include "my_fastled.h"
|
#include "my_fastled.h"
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_timer.h"
|
#include "effects/timer.h"
|
||||||
#include <FastLED.h>
|
#include <FastLED.h>
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
#include "fonts.h"
|
#include "fonts.h"
|
181
src/effects/tpm2_net.cpp
Normal file
181
src/effects/tpm2_net.cpp
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
#include "effects/tpm2_net.h"
|
||||||
|
#include "my_fastled.h"
|
||||||
|
|
||||||
|
void Tpm2NetEffect::loop(uint16_t ms) {
|
||||||
|
int packetsize = _udp.parsePacket();
|
||||||
|
uint8_t data[255];
|
||||||
|
uint8_t type = 0x00;
|
||||||
|
if (packetsize > 0) {
|
||||||
|
_last_packet_at = millis();
|
||||||
|
DBG("TPM2.Net * Received %d bytes from %s", packetsize, _udp.remoteIP().toString().c_str());
|
||||||
|
if (packetsize < 7) {
|
||||||
|
LOGln("TPM2.Net * Packet is too short. Ignoring it.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_udp.read(data, 6);
|
||||||
|
if (data[0] != 0x9C) {
|
||||||
|
LOGln("TPM2.Net * Block start byte is 0x%02X, expected 0x9C", data[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (data[1] == 0xC0) {
|
||||||
|
DBG("TPM2.Net * Received a command packet.");
|
||||||
|
type = 0xC0;
|
||||||
|
} else if (data[1] == 0xDA) {
|
||||||
|
DBG("TPM2.Net * Received a data packet.");
|
||||||
|
type = 0xDA;
|
||||||
|
} else {
|
||||||
|
LOGln("TPM2.Net * Unexpected packet type 0x%02X, expected 0xC0 or 0xDA.", data[1]);
|
||||||
|
}
|
||||||
|
uint16_t framesize = (data[2]<<8) | data[3];
|
||||||
|
uint8_t packet_number = data[4];
|
||||||
|
//uint8_t packet_count = data[5];
|
||||||
|
|
||||||
|
if (packetsize != framesize + 7) {
|
||||||
|
LOGln("TPM2.Net * Invalid packet size. Expected %d bytes, was %d bytes.", framesize+7, packetsize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type==0xC0) {
|
||||||
|
_parse_command(framesize, packet_number);
|
||||||
|
} else if (type==0xDA) {
|
||||||
|
_parse_data(framesize, packet_number);
|
||||||
|
}
|
||||||
|
} else if (_last_packet_at + 5000 < millis()) {
|
||||||
|
window->fill_with_checkerboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tpm2NetEffect::_parse_command(uint16_t size, uint8_t packet_number) {
|
||||||
|
if (packet_number!=0) {
|
||||||
|
LOGln("TPM2.Net * Command packet with packet_number > 0 (%d). Ignoring it.", packet_number);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (size < 2) {
|
||||||
|
LOGln("TPM2.Net * Command packet need at least 2 data bytes.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t ctrl = _udp.read();
|
||||||
|
bool write = ctrl & 0x80;
|
||||||
|
bool respond = ctrl & 0x40;
|
||||||
|
uint8_t cmd = _udp.read();
|
||||||
|
uint8_t data = 0;
|
||||||
|
if (write) {
|
||||||
|
if (size<3) {
|
||||||
|
LOGln("TPM2.Net * Got a write command, but no data to write.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data = _udp.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd == 0x0A) { // Master Brightness
|
||||||
|
if (write) {
|
||||||
|
FastLED.setBrightness(data);
|
||||||
|
} else {
|
||||||
|
uint8_t data[1] = {FastLED.getBrightness()};
|
||||||
|
_respond_with_data(data, 1);
|
||||||
|
}
|
||||||
|
} else if (cmd == 0x10 && !write) {
|
||||||
|
uint16_t pixels = window->width * window->height;
|
||||||
|
uint8_t data[2] = {(uint8_t)(pixels >> 8), (uint8_t)(pixels & 0xFF)};
|
||||||
|
_respond_with_data(data, 2);
|
||||||
|
} else {
|
||||||
|
LOGln("TPM2.Net * Unknown command. write:%d, command:0x%02X", write, cmd);
|
||||||
|
if (respond) {
|
||||||
|
_respond_unknown_command();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tpm2NetEffect::_parse_data(uint16_t framesize, uint8_t packet_number) {
|
||||||
|
if (packet_number==0) {
|
||||||
|
_pixel_index=0;
|
||||||
|
}
|
||||||
|
uint8_t len;
|
||||||
|
uint8_t data[3];
|
||||||
|
CRGB color;
|
||||||
|
while ((len = _udp.read(data, 3))==3) {
|
||||||
|
// We got 3 bytes
|
||||||
|
color.setRGB(data[0], data[1], data[2]);
|
||||||
|
window->setPixelByIndex(_pixel_index, &color);
|
||||||
|
_pixel_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
bool dir_changed = false;
|
||||||
|
|
||||||
|
_x += _x_dir * settings.effects.dvd.speed;
|
||||||
|
_y += _y_dir * settings.effects.dvd.speed;
|
||||||
|
|
||||||
|
if (_x <= 0) {
|
||||||
|
_x = -_x;
|
||||||
|
_x_dir = -_x_dir;
|
||||||
|
dir_changed = true;
|
||||||
|
//LOGln("speed: %d", settings.effects.dvd.speed);
|
||||||
|
} else if (_x + (settings.effects.dvd.width << 8) >= (window->width << 8)) {
|
||||||
|
_x -= 2*settings.effects.dvd.speed;
|
||||||
|
_x_dir = -_x_dir;
|
||||||
|
dir_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_y <= 0) {
|
||||||
|
_y = -_y;
|
||||||
|
_y_dir = -_y_dir;
|
||||||
|
dir_changed = true;
|
||||||
|
} else if (_y + (settings.effects.dvd.height << 8) >= (window->height << 8)) {
|
||||||
|
_y -= 2*settings.effects.dvd.speed;
|
||||||
|
_y_dir = -_y_dir;
|
||||||
|
dir_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->clear();
|
||||||
|
|
||||||
|
if (dir_changed) _color = (CRGB)CHSV(random8(), 255, 255);
|
||||||
|
|
||||||
|
for (int x=0; x<settings.effects.dvd.width; x++) for (int y=0; y<settings.effects.dvd.height; y++) {
|
||||||
|
window->setSubPixel(_x + (x<<8), _y + (y<<8), (CRGB*)&_color);
|
||||||
|
}
|
||||||
|
for (int x=1; x<settings.effects.dvd.width; x++) for (int y=1; y<settings.effects.dvd.height; y++) {
|
||||||
|
window->setPixel((_x>>8) + x, (_y>>8) + y, (CRGB*)&_color);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tpm2NetEffect::_respond(uint8_t* data, uint8_t len) {
|
||||||
|
_udp.beginPacket(_udp.remoteIP(), 65442);
|
||||||
|
_udp.write(data, len);
|
||||||
|
_udp.endPacket();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tpm2NetEffect::_respond_ack() {
|
||||||
|
uint8_t data[8] = {0x9C, 0xAC, 0x00, 0x01, 0x00, 0x01, 0x00, 0x36};
|
||||||
|
_respond(data, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tpm2NetEffect::_respond_unknown_command() {
|
||||||
|
uint8_t data[8] = {0x9C, 0xAC, 0x00, 0x01, 0x00, 0x01, 0x02, 0x36};
|
||||||
|
_respond(data, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tpm2NetEffect::_respond_with_data(uint8_t* dat, uint8_t len) {
|
||||||
|
uint8_t data[8 + len];
|
||||||
|
data[0] = 0x9C;
|
||||||
|
data[1] = 0xAD;
|
||||||
|
data[2] = (len+1)>>8;
|
||||||
|
data[3] = (len+1)&0xFF;
|
||||||
|
data[4] = 0x00;
|
||||||
|
data[5] = 0x01;
|
||||||
|
data[6] = 0x00;
|
||||||
|
memcpy(&(data[7]), dat, len);
|
||||||
|
data[8 + len - 1] = 0x36;
|
||||||
|
_respond(data, 8 + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Tpm2NetEffect::can_be_shown_with_clock() { return false; }
|
||||||
|
|
||||||
|
Tpm2NetEffect::Tpm2NetEffect() {
|
||||||
|
_udp.begin(65506);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tpm2NetEffect::~Tpm2NetEffect() {
|
||||||
|
_udp.stop();
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_tv_static.h"
|
#include "effects/tv_static.h"
|
||||||
|
|
||||||
void TvStaticEffect::loop(uint16_t ms) {
|
void TvStaticEffect::loop(uint16_t ms) {
|
||||||
//uint8_t dark_position = (millis() % settings.effects.tv_static.black_bar_speed) * _window->width / settings.effects.tv_static.black_bar_speed;
|
//uint8_t dark_position = (millis() % settings.effects.tv_static.black_bar_speed) * _window->width / settings.effects.tv_static.black_bar_speed;
|
@ -1,4 +1,4 @@
|
|||||||
#include "effect_twirl.h"
|
#include "effects/twirl.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
|
|
||||||
boolean TwirlEffect::can_be_shown_with_clock() { return true; };
|
boolean TwirlEffect::can_be_shown_with_clock() { return true; };
|
36
src/mqtt.cpp
36
src/mqtt.cpp
@ -23,7 +23,7 @@ void mqtt_callback(char* original_topic, byte* pl, unsigned int length) {
|
|||||||
pl[length] = '\0';
|
pl[length] = '\0';
|
||||||
String payload((char*)pl);
|
String payload((char*)pl);
|
||||||
String topic (original_topic);
|
String topic (original_topic);
|
||||||
if (topic.equals(MQTT_TOPIC "log") || topic.equals(MQTT_TOPIC "status") || topic.equals(MQTT_TOPIC "metrics")) {
|
if (topic.equals(MQTT_TOPIC "log") || topic.equals(MQTT_TOPIC "status") || topic.equals(MQTT_TOPIC "status_details") || topic.startsWith(MQTT_TOPIC "metrics")) {
|
||||||
// Return our own messages
|
// Return our own messages
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ void mqtt_callback(char* original_topic, byte* pl, unsigned int length) {
|
|||||||
if (topic.startsWith(MQTT_TOPIC_WEATHER)) {
|
if (topic.startsWith(MQTT_TOPIC_WEATHER)) {
|
||||||
// Weather stuff
|
// Weather stuff
|
||||||
topic.remove(0, strlen(MQTT_TOPIC_WEATHER));
|
topic.remove(0, strlen(MQTT_TOPIC_WEATHER));
|
||||||
LOGln("MQTT * Weather stuff.");
|
DBG("MQTT * Weather stuff.");
|
||||||
if (topic.startsWith("icons/")) {
|
if (topic.startsWith("icons/")) {
|
||||||
topic.remove(0, 6);
|
topic.remove(0, 6);
|
||||||
uint8_t id = topic.toInt();
|
uint8_t id = topic.toInt();
|
||||||
@ -39,7 +39,7 @@ void mqtt_callback(char* original_topic, byte* pl, unsigned int length) {
|
|||||||
uint8_t val = payload.toInt();
|
uint8_t val = payload.toInt();
|
||||||
if (val==0) return;
|
if (val==0) return;
|
||||||
weather_icon_ids[id] = val;
|
weather_icon_ids[id] = val;
|
||||||
LOGln("Set weather_icon_ids[%d] to value %d", id, val);
|
DBG("Set weather_icon_ids[%d] to value %d", id, val);
|
||||||
} else if (topic.startsWith("temperatures/")) {
|
} else if (topic.startsWith("temperatures/")) {
|
||||||
topic.remove(0, 13);
|
topic.remove(0, 13);
|
||||||
uint8_t id = topic.toInt();
|
uint8_t id = topic.toInt();
|
||||||
@ -47,7 +47,7 @@ void mqtt_callback(char* original_topic, byte* pl, unsigned int length) {
|
|||||||
uint8_t val = payload.toInt();
|
uint8_t val = payload.toInt();
|
||||||
if (val==0) return;
|
if (val==0) return;
|
||||||
weather_temperatures[id] = val;
|
weather_temperatures[id] = val;
|
||||||
LOGln("Set weather_temperatures[%d] to value %d", id, val);
|
DBG("Set weather_temperatures[%d] to value %d", id, val);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (topic.equals(MQTT_TOPIC_TIMER)) {
|
} else if (topic.equals(MQTT_TOPIC_TIMER)) {
|
||||||
@ -98,15 +98,33 @@ void mqtt_callback(char* original_topic, byte* pl, unsigned int length) {
|
|||||||
|
|
||||||
boolean mqtt_connect() {
|
boolean mqtt_connect() {
|
||||||
LOGln("MQTT * Connecting to MQTT server with client id %s", hostname);
|
LOGln("MQTT * Connecting to MQTT server with client id %s", hostname);
|
||||||
|
mqtt_client.setBufferSize(350);
|
||||||
if (mqtt_client.connect(hostname, MQTT_USER, MQTT_PASS, MQTT_TOPIC "status", 0, true, "OFFLINE", true)) {
|
if (mqtt_client.connect(hostname, MQTT_USER, MQTT_PASS, MQTT_TOPIC "status", 0, true, "OFFLINE", true)) {
|
||||||
LOGln("MQTT * Connected.");
|
LOGln("MQTT * Connected.");
|
||||||
LOGln("Core * Flash chip id: 0x%X. Size: %d bytes. 'Real' size: %d bytes.", ESP.getFlashChipId(), ESP.getFlashChipSize(), ESP.getFlashChipRealSize());
|
LOGln("Core * Flash chip id: 0x%X. Size: %d bytes. 'Real' size: %d bytes.", ESP.getFlashChipId(), ESP.getFlashChipSize(), ESP.getFlashChipRealSize());
|
||||||
char buffer[40];
|
char buffer[40];
|
||||||
snprintf(buffer, 40, "ONLINE %s %s", hostname, WiFi.localIP().toString().c_str());
|
snprintf(buffer, 40, "ONLINE %s %s", hostname, WiFi.localIP().toString().c_str());
|
||||||
mqtt_client.publish(MQTT_TOPIC "status", buffer, true);
|
mqtt_client.publish(MQTT_TOPIC "status", "ONLINE", true);
|
||||||
|
mqtt_client.publish(MQTT_TOPIC "status_details", buffer, true);
|
||||||
mqtt_client.subscribe(MQTT_TOPIC "+");
|
mqtt_client.subscribe(MQTT_TOPIC "+");
|
||||||
mqtt_client.subscribe(MQTT_TOPIC_WEATHER "#");
|
mqtt_client.subscribe(MQTT_TOPIC_WEATHER "#");
|
||||||
mqtt_client.subscribe(MQTT_TOPIC_TIMER);
|
mqtt_client.subscribe(MQTT_TOPIC_TIMER);
|
||||||
|
|
||||||
|
#ifdef MQTT_TOPIC_HOMEASSISTANT
|
||||||
|
// Set MQTT values for homeassistant auto device discovery
|
||||||
|
String topic = MQTT_TOPIC_HOMEASSISTANT "/light/";
|
||||||
|
topic += hostname;
|
||||||
|
topic += "/config";
|
||||||
|
String message = "{\"~\":\"" MQTT_TOPIC "\",\"opt\":1,\"avty_t\":\"~status\",\"pl_avail\":\"ONLINE\",\"pl_not_avail\":\"OFFLINE\",";
|
||||||
|
message += "\"bri_cmd_t\": \"~brightness\",\"bri_scl\":255,\"fx_cmd_t\":\"~modus\",\"name\":\"Pitrix\",\"uniq_id\":\"";
|
||||||
|
message += hostname;
|
||||||
|
message += "\",";
|
||||||
|
message += "\"stat_t\":\"~modus\",\"cmd_t\":\"~modus\",\"pl_on\":\"cycle\",\"pl_off\":\"night_clock\"}";
|
||||||
|
mqtt_client.publish(topic.c_str(), message.c_str(), true);
|
||||||
|
DBG("MQTT * Homeassistant data:");
|
||||||
|
DBG("MQTT * Topic: %s", topic.c_str());
|
||||||
|
DBG("MQTT * Data: %s", message.c_str());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return mqtt_client.connected();
|
return mqtt_client.connected();
|
||||||
}
|
}
|
||||||
@ -133,16 +151,16 @@ void mqtt_loop() {
|
|||||||
|
|
||||||
String mqtt_log_str = String();
|
String mqtt_log_str = String();
|
||||||
|
|
||||||
void mqtt_publish(const char* topic, int number) {
|
void mqtt_publish(const char* topic, int number, bool retain) {
|
||||||
char b[32];
|
char b[32];
|
||||||
sprintf(b, "%d", number);
|
sprintf(b, "%d", number);
|
||||||
mqtt_publish(topic, b);
|
mqtt_publish(topic, b, retain);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mqtt_publish(const char* topic, const char* message) {
|
void mqtt_publish(const char* topic, const char* message, bool retain) {
|
||||||
char t[127];
|
char t[127];
|
||||||
sprintf(t, MQTT_TOPIC "%s", topic);
|
sprintf(t, MQTT_TOPIC "%s", topic);
|
||||||
mqtt_client.publish(t, message);
|
mqtt_client.publish(t, message, retain);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mqtt_log(const char* message) {
|
void mqtt_log(const char* message) {
|
||||||
|
@ -51,7 +51,16 @@ void setup() {
|
|||||||
#ifdef MQTT_ENABLE
|
#ifdef MQTT_ENABLE
|
||||||
mqtt_setup();
|
mqtt_setup();
|
||||||
#endif
|
#endif
|
||||||
SPIFFS.begin();
|
if (!SPIFFS.begin()) {
|
||||||
|
LOGln("Core * Could not open SPIFFS filesystem");
|
||||||
|
} else {
|
||||||
|
LOGln("Core * Files in SPIFFS filesystem:");
|
||||||
|
Dir d = SPIFFS.openDir("/");
|
||||||
|
while(d.next()) {
|
||||||
|
LOGln("Core * %s", d.fileName().c_str());
|
||||||
|
}
|
||||||
|
LOGln("Core * End of SPIFFS file listing.");
|
||||||
|
}
|
||||||
load_settings();
|
load_settings();
|
||||||
LOGln("Core * Setup complete");
|
LOGln("Core * Setup complete");
|
||||||
}
|
}
|
||||||
@ -64,7 +73,7 @@ void loop() {
|
|||||||
EVERY_N_SECONDS(1) {
|
EVERY_N_SECONDS(1) {
|
||||||
Serial.print("Core * Waiting for OTA... "); Serial.println(starting_up);
|
Serial.print("Core * Waiting for OTA... "); Serial.println(starting_up);
|
||||||
starting_up--;
|
starting_up--;
|
||||||
Window* w = Window::getFullWindow();
|
Window* w = &Window::window_full;
|
||||||
CRGB color(0xFF0000);
|
CRGB color(0xFF0000);
|
||||||
w->clear();
|
w->clear();
|
||||||
for (int i=0; i<starting_up; i++) {
|
for (int i=0; i<starting_up; i++) {
|
||||||
|
@ -16,9 +16,13 @@ namespace tests {
|
|||||||
for (int j=0; j<3; j++) {
|
for (int j=0; j<3; j++) {
|
||||||
int free_at_start = ESP.getFreeHeap();
|
int free_at_start = ESP.getFreeHeap();
|
||||||
effect = select_effect(i);
|
effect = select_effect(i);
|
||||||
effect->loop(1);
|
|
||||||
if (effect == NULL) return;
|
if (effect == NULL) return;
|
||||||
effect_name = effect->get_name();
|
effect_name = effect->get_name();
|
||||||
|
if (effect_name && !effect_name.equals("cycle")) {
|
||||||
|
LOGln("Testing effect %s...", effect_name.c_str());
|
||||||
|
delay(1);
|
||||||
|
effect->loop(1);
|
||||||
|
}
|
||||||
delete effect;
|
delete effect;
|
||||||
diffs[i] = ESP.getFreeHeap() - free_at_start;
|
diffs[i] = ESP.getFreeHeap() - free_at_start;
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,6 @@
|
|||||||
require 'websocket-eventmachine-client'
|
require 'websocket-eventmachine-client'
|
||||||
require 'pp'
|
require 'pp'
|
||||||
|
|
||||||
def rgb2ansi(r, g, b)
|
|
||||||
if r==g && g==b
|
|
||||||
return 16 if r<8
|
|
||||||
return 231 if r>248
|
|
||||||
return (((r - 8) / 247.0) * 24).round + 232
|
|
||||||
end
|
|
||||||
|
|
||||||
return 16 + 36*(r/51.0).round + 6*(g/51.0).round + (b/51.0).round
|
|
||||||
end
|
|
||||||
|
|
||||||
IP = ARGV[0]
|
IP = ARGV[0]
|
||||||
EFFECT = ARGV[1]
|
EFFECT = ARGV[1]
|
||||||
uri = "ws://#{IP}:80/ws"
|
uri = "ws://#{IP}:80/ws"
|
||||||
@ -41,8 +31,7 @@ EM.run do
|
|||||||
str += "|"
|
str += "|"
|
||||||
(0...width).each do |x|
|
(0...width).each do |x|
|
||||||
r, g, b = *data.shift(3)
|
r, g, b = *data.shift(3)
|
||||||
color_code = rgb2ansi(r, g, b)
|
str += "\033[38;2;#{r};#{g};#{b}m●"
|
||||||
str += "\033[48;5;#{color_code}m "
|
|
||||||
end
|
end
|
||||||
str += "\033[0m|\n"
|
str += "\033[0m|\n"
|
||||||
end
|
end
|
||||||
|
18
src/wifi.cpp
18
src/wifi.cpp
@ -6,10 +6,20 @@
|
|||||||
void wifi_setup() {
|
void wifi_setup() {
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||||
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
uint8_t result;
|
||||||
Serial.println("WiFi * Connection Failed! Rebooting...");
|
uint8_t counter = 0;
|
||||||
delay(5000);
|
while ((result = WiFi.waitForConnectResult()) != WL_CONNECTED) {
|
||||||
ESP.restart();
|
counter++;
|
||||||
|
if (counter > 100) {
|
||||||
|
Serial.print("WiFi * Connection Failed! Last result was: ");
|
||||||
|
Serial.print(result);
|
||||||
|
Serial.println(" Rebooting...");
|
||||||
|
delay(100);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
Serial.print("WiFi * Still waiting for WiFi to connect. This is loop number ");
|
||||||
|
Serial.println(counter);
|
||||||
|
delay(100);
|
||||||
}
|
}
|
||||||
Serial.println("WiFi * Ready");
|
Serial.println("WiFi * Ready");
|
||||||
Serial.print("WiFi * IP address: ");
|
Serial.print("WiFi * IP address: ");
|
||||||
|
Reference in New Issue
Block a user