mangavalkandClaude Opus 5.5 8415dee347 Add native unit tests for the Nano firmware
- New native environment: pio test -e native
- test/mocks: fake Arduino core, EEPROM and recording BROSE9323 driver
- test/test_nano: 25 tests covering every command, bitmaps, bad input,
  flip time storage and the periodic full redraw
- Board environments ignore tests so they are never uploaded

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:24:13 +02:00

Flipdot Display

Firmware for an 84 × 19 Brose flipdot display (three 28 × 19 panels) that runs as a Home Assistant–controlled clock.

The system uses two microcontrollers:

 ┌──────────────┐   WiFi / MQTT   ┌────────────────┐   UART 115200   ┌──────────────┐   GPIO   ┌──────────────┐
 │ Home         │ ◄─────────────► │ ESP32          │ ──────────────► │ Arduino Nano │ ───────► │ Brose        │
 │ Assistant    │                 │ (controller)   │  text commands  │ (driver)     │          │ flipdot      │
 └──────────────┘                 └───────┬────────┘                 └──────▲───────┘          │ panels 84x19 │
                                          │ GPIO 13                         │                  └──────▲───────┘
                                          ▼                                 │     power               │
                                   ┌─────────────┐                          │                         │
                                   │ Relay       │ ─────────────────────────┴─────────────────────────┘
                                   └─────────────┘

The relay powers both the panels and the Nano. When the relay is off, the Nano is off too, and it boots again each time the relay switches on. Only the ESP32 runs all the time.

Part Folder What it does
Arduino Nano src/nano Drives the panel's row and column electronics directly. Keeps a frame buffer and flips only the dots that changed. Takes simple text commands over serial.
ESP32 src/esp32 Connects to WiFi, gets the time over NTP, shows a clock with Pikachu bitmaps, exposes switches to Home Assistant over MQTT, switches display power with a relay and supports OTA updates.
BROSE9323 driver lib/BROSE9323 Shared Adafruit_GFX display driver. On the Nano it toggles GPIO pins. On the ESP32 (-D ESPSERIAL) it turns every drawing call into a serial command for the Nano.

Because the driver is an Adafruit_GFX subclass on both boards, the ESP32 can use the normal GFX API (print, drawBitmap, fillScreen, ...). Each call is sent to the Nano and drawn there.

Repository layout

platformio.ini          one PlatformIO project, multiple environments
lib/BROSE9323/          shared flipdot driver (used by both targets)
src/nano/               Arduino Nano firmware
src/esp32/              ESP32 firmware
  secrets.example.h     template for WiFi / MQTT credentials
test/test_nano/         unit tests for the Nano firmware (run on the PC)
test/mocks/             fake Arduino, EEPROM and display driver for the tests
archive/                old, unused sketches kept for reference
CLAUDE.md               project notes for Claude Code

Building and flashing

Install PlatformIO (the VS Code extension is easiest) and open this folder.

  1. Copy src/esp32/secrets.example.h to src/esp32/secrets.h and fill in your WiFi and MQTT details. secrets.h is gitignored.
  2. Check the COM ports and the OTA IP in platformio.ini.
  3. Build or upload:
Environment Board Upload method
nano Arduino Nano (ATmega328P) USB (COM10)
esp32 ESP32 DevKit v1 OTA over WiFi (10.1.1.198)
esp32_usb ESP32 DevKit v1 USB (COM11). Use it for the first flash or for recovery.
pio run                          # build nano + esp32
pio run -e nano -t upload        # flash the Nano
pio run -e esp32 -t upload       # flash the ESP32 over the air
pio run -e esp32_usb -t upload   # flash the ESP32 over USB
pio device monitor -e nano       # serial monitor
pio test -e native               # run the Nano unit tests on the PC

The unit tests need gcc/g++ on your PATH. On Windows you can get it from MSYS2 or Strawberry Perl.

In VS Code you can also pick the environment in the PlatformIO status bar.

Tip: The ESP32 → Nano wire goes to the Nano's RX pin, which the Nano's USB chip also uses. Disconnect that wire before you flash the Nano over USB, or the upload may fail.

Wiring between ESP32 and Nano

The ESP32 talks to the Nano on UART2 (Serial2, 115200 baud). The ESP32's own Serial (UART0, USB) is free for debug output.

ESP32 Nano Notes
GPIO 17 (TX2) D0 (RX) Display commands
GPIO 16 (RX2) D1 (TX) READY and ERR replies. Use a 5 V → 3.3 V voltage divider (e.g. 1 kΩ / 2 kΩ), because the ESP32 is not 5 V tolerant. Optional: without it, the ESP waits a fixed 3 s after power-on.
GND GND Common ground
GPIO 13 Relay input Relay powers the panels and the Nano (LOW = on)

How it works

  1. ESP32 boot. The ESP32 connects to WiFi and starts ArduinoOTA. After a crash or unexpected reset it stays in an OTA panic window for 15 seconds, so you can flash a fix before the main code runs again. It then switches the display relay on, waits for the Nano's READY message (at most 3 s), starts NTP and connects to MQTT.
  2. Clock loop (every second).
    • 08:00–22:00: Pikachu with a thought bubble showing HH:MM. A yawning Pikachu is shown from 17:00.
    • 22:00–23:30: the clock is only shown during the minutes :00, :15, :30 and :45. 30 seconds after each of those minutes, the relay turns the display off.
    • 23:31–08:00: the screen is cleared and power is cut after 30 seconds.
  3. Home Assistant switches (MQTT discovery):
    • FlipDot Display Clock: off shows a Nintendo logo instead of the clock.
    • FlipDot Display Power: off clears the display and cuts power through the relay.
  4. Nano. The Nano reads commands from the serial line and updates its frame buffer. On D it flips only the dots that changed. Every 2 minutes it redraws the whole screen to fix dots that did not flip.

The serial protocol is described in src/nano/README.md.

TODO

  • Rewire the Nano link to UART2. The firmware now uses Serial2 (GPIO 16/17) instead of Serial (GPIO 1/3). Move the ESP32 TX wire from GPIO 1 to GPIO 17 before you flash this firmware, or the display gets no data. See Wiring between ESP32 and Nano.
  • Add the reply wire: Nano D1 (TX) → voltage divider → ESP32 GPIO 16 (RX2). With it, the ESP sends the first frame as soon as the Nano is ready, instead of after 3 s.
  • Check the boot timing. Build the Nano with MEASURE_REFRESH to see how long a full redraw takes. If the reply wire isn't fitted, check that 3 s (NANO_BOOT_TIMEOUT) is enough for the Nano to boot.
S
Description
No description provided
Readme
41 MiB
0 Stars 1 Watchers 0 Forks
Languages
C++ 71.6%
C 23.4%
Python 5%