Public Access
Restructure ESP32 firmware into modules, fix bugs, add tests
Structure (src/esp32/): - logic/: DisplayController, schedule, power timer, LED pattern; pure C++ - display/: FlipdotFrames and bitmaps - nano_link/: NanoLink (relay, serial, READY, bootloader) and flash bridge - net/: WiFi/OTA/panic window, Home Assistant - config.h with all settings; libs.h (globals in a header) removed Bug fixes: - Home Assistant switches now report their state back and start as ON - loop() no longer blocks: WiFi.waitForConnectResult() (up to 60 s without WiFi) and getLocalTime() (5 s before NTP sync) were called every iteration - Power switch off now powers off after 1 s even when a 30 s countdown is already running - millis() overflow safe power-off timer; no frame catch-up bursts - No garbage time string before NTP sync; 'Connecting...' stays instead - Frames are only sent when the screen changes instead of every second - Reset reasons are logged once instead of every 100 ms - Removed dead code (unused fonts, WiFiMulti, rotated bitmap, ...) Tests: new test_esp32 environment (26 tests); native renamed to test_nano Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cefb76c1ad
commit
683a47c055
29 files changed
+1289
-755
No files matched your search
+52
-23
@@ -1,6 +1,6 @@
|
||||
# ESP32: controller
|
||||
|
||||
PlatformIO environments: `esp32` (OTA) and `esp32_usb` (USB)
|
||||
PlatformIO environments: `esp32` (OTA) and `esp32_usb` (USB). Tests: `test_esp32`.
|
||||
|
||||
The ESP32 decides what is shown on the display. It never touches the panel itself. The
|
||||
BROSE9323 driver is built with `-D ESPSERIAL`, so every GFX call is sent to the Nano over
|
||||
@@ -11,35 +11,55 @@ debug output. Wiring is described in the [main README](../../README.md#wiring-be
|
||||
|
||||
| File | Contents |
|
||||
|------|----------|
|
||||
| `main.cpp` | setup, OTA, clock / power logic, Home Assistant callbacks |
|
||||
| `libs.h` | includes and global objects (display, MQTT, WiFi, pins, timezone) |
|
||||
| `bitmaps.h` | 1-bit bitmaps (Pikachu, thought bubble, Nintendo logo, ...) |
|
||||
| `nano_flash_bridge.h/.cpp` | WiFi to serial bridge for flashing the Nano over WiFi (TCP port 2323) |
|
||||
| `secrets.example.h` | template for `secrets.h` (WiFi and MQTT credentials, **gitignored**) |
|
||||
| `main.cpp` | Creates the objects, `setup()` and `loop()` |
|
||||
| `config.h` | All settings: pins, timings, timezone, Home Assistant device id |
|
||||
| `credentials.h` | Includes `secrets.h` (WiFi and MQTT credentials, **gitignored**); template: `secrets.example.h` |
|
||||
| **`logic/`** | **Pure logic without Arduino code, tested on the PC** |
|
||||
| `logic/display_controller.*` | Decides what is shown and when the display is powered (`DisplayController`) |
|
||||
| `logic/schedule.*` | When the clock is shown (night, clock, standby) |
|
||||
| `logic/power_timer.*` | Countdown to switching the display off |
|
||||
| `logic/status_led.h` | Blink pattern of the built-in LED |
|
||||
| **`display/`** | **What is drawn** |
|
||||
| `display/frames.*` | The screens: clock, logo, blank, text (`FlipdotFrames`) |
|
||||
| `display/bitmaps.h` | 1-bit bitmaps (Pikachu, thought bubble, Nintendo logo, ...) |
|
||||
| **`nano_link/`** | **Connection to the Nano** |
|
||||
| `nano_link/nano_link.*` | Relay and serial link: power on (waits for `READY`), power off, bootloader start (`NanoLink`) |
|
||||
| `nano_link/nano_flash_bridge.*` | WiFi to serial bridge for flashing the Nano over WiFi (TCP port 2323) |
|
||||
| **`net/`** | **Network** |
|
||||
| `net/wifi_ota.*` | WiFi, ESP32 OTA updates and the OTA panic window |
|
||||
| `net/home_assistant.*` | MQTT and the two Home Assistant switches |
|
||||
|
||||
`DisplayController` only talks to two small interfaces, `DisplayPower` (implemented by
|
||||
`NanoLink`) and `Frames` (implemented by `FlipdotFrames`). The tests replace both with
|
||||
fakes.
|
||||
|
||||
## Features
|
||||
|
||||
- **Frames only when something changes:** a new frame is sent when the minute changes, the
|
||||
screen changes (clock, logo, blank) or the Nano was just powered on. The serial line is
|
||||
quiet in between, which also gives the Nano time for its periodic full redraw.
|
||||
- **OTA updates** through ArduinoOTA. Hostname: `FlipDotDisplay`.
|
||||
- **OTA panic window:** after a crash or watchdog reset, the ESP32 runs only the OTA
|
||||
handler for 15 seconds before it starts the main code. A firmware that crashes on boot
|
||||
can still be replaced over the air.
|
||||
- **NTP time** with timezone `CET-1CEST,M3.5.0,M10.5.0/3` (Europe/Amsterdam).
|
||||
- **Home Assistant** through MQTT (`home-assistant-integration` library) with two switches:
|
||||
- `FlipDotDisplayClock`: clock on, or the Nintendo logo when off
|
||||
- `FlipDotDisplayPower`: turns the display off through the relay
|
||||
handler for 15 seconds before it starts the main code, with the LED blinking fast. A
|
||||
firmware that crashes on boot can still be replaced over the air.
|
||||
- **NTP time** with timezone `CET-1CEST,M3.5.0,M10.5.0/3` (Europe/Amsterdam). Until the
|
||||
time is synced, the display shows "Connecting...".
|
||||
- **Home Assistant** through MQTT (`home-assistant-integration` library) with two switches.
|
||||
Each switch reports its new state back, so Home Assistant always shows the real state.
|
||||
- `FlipDot Display Clock`: on = clock; off = Nintendo logo while the display is on,
|
||||
then power off after 30 s
|
||||
- `FlipDot Display Power`: off = clear the display and power it off after 1 s
|
||||
- **Relay on GPIO 13** switches the power for both the panels and the Nano. `LOW` turns it
|
||||
on.
|
||||
- **On:** the ESP waits for the Nano's `READY` message, at most 3 s
|
||||
(`NANO_BOOT_TIMEOUT`), before it sends frames. The relay stays on while it is needed;
|
||||
the ESP only waits when it actually switches the relay on.
|
||||
- **Off:** the ESP stops sending and releases its TX pin (`Serial.end()` and the pin set
|
||||
to input). An idle UART line is high and would otherwise power the Nano through its RX
|
||||
pin.
|
||||
(`NANO_BOOT_TIMEOUT`), before it sends frames.
|
||||
- **Off:** the ESP releases its TX pin (`Serial2.end()` and the pin set to input). An
|
||||
idle UART line is high and would otherwise power the Nano through its RX pin.
|
||||
- **Nano flash bridge:** `pio run -e nano_ota -t upload` flashes the Nano through the ESP32.
|
||||
While a flash session runs, the clock is paused. See the
|
||||
[main README](../../README.md#flashing-the-nano-over-wifi).
|
||||
- **Status LED** (built-in) blinks fast when WiFi is down and slowly when connected. It is
|
||||
off at night or when the display is powered off.
|
||||
- **Status LED** (built-in): off while the display is off, slow blink with WiFi, fast blink
|
||||
without WiFi.
|
||||
|
||||
## Schedule
|
||||
|
||||
@@ -47,11 +67,20 @@ debug output. Wiring is described in the [main README](../../README.md#wiring-be
|
||||
|------|---------|
|
||||
| 08:00 – 17:00 | Pikachu and the clock, updated every minute |
|
||||
| 17:00 – 22:00 | Yawning Pikachu and the clock |
|
||||
| 22:00 – 23:30 | Clock shown only during the minutes :00, :15, :30 and :45; power is off in between |
|
||||
| 23:31 – 08:00 | Screen cleared, power off |
|
||||
| 22:00 – 23:30 | Clock shown only during the minutes :00, :15, :30 and :45. In between the power is off, and the last time stays visible (flipdots keep their image without power). |
|
||||
| 23:31 – 08:00 | Screen cleared, power off after 30 s |
|
||||
|
||||
The times are in `logic/schedule.cpp`.
|
||||
|
||||
## Tests
|
||||
|
||||
`pio test -e test_esp32` runs [test/test_esp32](../../test/test_esp32/test_main.cpp) on
|
||||
the PC: the schedule boundaries, the power timer (including `millis()` overflow), the LED
|
||||
pattern and the display controller (power on/off, redraws, both Home Assistant switches).
|
||||
|
||||
## Adding bitmaps
|
||||
|
||||
Convert an image with [image2cpp](https://javl.github.io/image2cpp/) to "Arduino code",
|
||||
horizontal, 1 bit per pixel. Paste the array into `bitmaps.h` and draw it with
|
||||
`display.drawBitmap(x, y, bitmap, w, h, 1)`. The display is 84 × 19 pixels.
|
||||
horizontal, 1 bit per pixel. Paste the array into `display/bitmaps.h` and draw it in
|
||||
`display/frames.cpp` with `_display.drawBitmap(x, y, bitmap, w, h, 1)`. The display is
|
||||
84 × 19 pixels.
|
||||
Reference in new issue
Block a user