Add HA dropdowns, off image, flip fixes and refresh effects

Home Assistant: remove the Clock switch (its entity is deleted on connect),
add an IP sensor and Mode / Off image dropdowns whose options follow the
saved bitmaps. Remove the built-in "Nintendo border" bitmap.

Off image: a bitmap (or blank) left on the dots when the display switches off.

Nano: pause after each flip pulse and repeat pulses for changed dots, both
stored in EEPROM (G/N commands). Refresh effects (E command): instant,
sparkle, wipe, rain, from the middle out, diagonal, spiral, flip all then
reveal, push and random, optionally only for small changes. Effects run in
steps from loop() so serial input keeps flowing.

Web UI: flip settings, refresh effect and test patterns under Settings; the
System tab shows why the ESP32 last restarted. Settings records from
versions 1 and 2 are migrated. Firmware 2.3.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-15 01:29:01 +02:00
1 parent 4a5f6a8b5d
commit 1d3b084de1
42 files changed
+1631 -230

No files matched your search

+42
View File
@@ -3,6 +3,8 @@
#include <Adafruit_GFX.h>
#include "dot_sequence.h"
//#define FLIPDOT_PLCC_ADAPTER
// ESPSERIAL is set per target via build_flags in platformio.ini (-D ESPSERIAL for the ESP32)
@@ -10,6 +12,11 @@ class BROSE9323 : public Adafruit_GFX
{
private:
uint16_t _flip_time;
uint16_t _flip_gap = 0; // pause after each pulse in us, lets the coil supply recover
uint8_t _pulses = 1; // pulses for each dot that changed
uint8_t _effect = EFFECT_INSTANT;
uint16_t _effect_time = 1500; // ms, how long an effect takes
uint8_t _effect_flags = 0; // EFFECT_FLAG_...
const uint8_t _panel_width;
const uint8_t _buffer_width;
const uint16_t _buffer_size;
@@ -27,6 +34,18 @@ private:
// After boot the physical dot state is unknown, so the first display() redraws everything
bool _force_next = true;
// A running effect (display() with an effect other than EFFECT_INSTANT)
DotSequence _sequence;
bool _animating = false;
uint8_t _running_effect = EFFECT_INSTANT; // _effect, or the one chosen for EFFECT_RANDOM
uint8_t _phase = 0; // EFFECT_FLAP: 0 = to yellow, 1 = the new image
uint8_t _push_shift = 0; // EFFECT_PUSH: column shift 1..width
uint16_t _push_pos = 0; // EFFECT_PUSH: dot within the shift
bool _animate_all = false; // flip every dot, not only the changed ones
bool _drawing = false; // the buffer changed since the last display(): pause
uint32_t _step_time = 0; // us per step
uint32_t _next_step = 0; // micros() of the next step
#ifndef FLIPDOT_PLCC_ADAPTER
const uint8_t ENABLE = 7,
ADDR_0 = 3,
@@ -71,6 +90,14 @@ private:
void _selectRow(uint8_t);
void _setData(bool);
void _strobe(void);
bool _shown(uint8_t x, uint8_t y) const;
bool _changed(uint8_t x, uint8_t y) const;
bool _wanted(uint8_t x, uint8_t y) const;
void _flipTo(uint8_t x, uint8_t y, bool on, uint8_t pulses);
void _flipDot(uint8_t x, uint8_t y, uint8_t pulses);
bool _pushDot(void);
void _drawAll(bool all);
void _startEffect(bool all);
#endif
public:
BROSE9323(uint8_t, uint8_t, uint8_t, uint16_t ft = 280);
@@ -83,6 +110,21 @@ public:
void fillScreen(uint16_t);
void setDirect(bool);
void setTiming(uint16_t);
// Pause after each flip pulse in us
void setGap(uint16_t);
// Pulses for each changed dot (a second pulse catches dots that didn't flip). Full
// redraws use one pulse per dot.
void setPulses(uint8_t);
// How display() shows a new frame (RefreshEffect), how long it takes in ms (pushing
// can take longer: it flips many dots per step) and EFFECT_FLAG_... flags.
// Effects run in steps from update(), so call that often (every loop).
void setEffect(uint8_t effect, uint16_t time_ms, uint8_t flags = 0);
#ifndef ESPSERIAL
// Runs the next steps of an effect. Returns busy().
bool update(void);
// An effect is running (paused while a new frame is being drawn into the buffer)
bool busy(void) const;
#endif
#ifndef ESPSERIAL
void printBuffer(void);
#endif