Files
nixie-clock/CLAUDE.md
T
mangavalkandClaude Opus 5.5 9a7061383c Add Home Assistant controls over MQTT
Upgrade ArduinoHA from 1.3.0 to 2.1.0 and rewrite mqtt.ino for it.
The clock now shows up in Home Assistant (discovery prefix
"homeassistant") with:
- switches Tubes (blank the display, runtime only) and Auto dim
- numbers Day/Night brightness
- light Backlight (on/off, brightness, RGB mapped to the colour wheel)
- select LED effect, button Cathode protect
- sensors Light (LDR) and WiFi signal, plus the upstream sensors when
  the clock has them; master-clock subscriptions are kept

Settings changed from HA are saved to EEPROM 3 s after the last change.
Fixes the unbounded memcpy in the MQTT message handler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 21:37:25 +01:00

98 lines
5.8 KiB
Markdown

# Nixie clock: notes for Claude
An AliExpress WiFi nixie clock (4x IN-12 + 2x IN-3 neon dots, 8x WS2812) that is being
moved from its closed stock firmware to ESP_UniClock (https://github.com/gpeter62/ESP_UniClock)
with ArduinoOTA and Home Assistant (MQTT) support.
## The device
- On the network at **10.1.1.97** (WiFi `dlink-iot`). Since 2026-10-25 it runs ESP_UniClock
(`firmware/uniclock/`, CLOCK_90): web UI on port 80 (JSON at `/getConfiguration`,
`/getCurrentInfos`), ArduinoOTA on UDP 8266 (hostname `nixie-in12`, no password yet).
- Board: RetroModding (Konstantin Repnikov) "NixieIN12v2 HV2.0", stock firmware **SV1.3**
(©2020). ESP-12 (ESP8266, MAC 30:83:98:99:BF:DE, Espressif).
- **Powered by USB-C 5 V only** (no DC jack). Most likely the maker's "v2.0L lightweight
5 volt version". The user says the PCB looks different from the 12 V v2 board.
- **No buttons fitted**, only the light sensor.
- Stock settings (2026-10-25): time zone +01:00, EU DST on, NTP `time.euro.apple.com`,
brightness auto, 24 h. Stock DST might not work: check in late March.
## Stock firmware (from the flash dump)
- `firmware/stock/nixie_stock_SV1.3_full_4MB.bin` (gitignored), SHA-256
`b069f4eb93cf1e9063a30374db4d70508211f07b0a17049bcf9ebdeda65f2985`, verified against the chip
with `verify-flash`. Flash: 4 MB, DIO, 40 MHz.
- Arduino ESP8266 core 2.x (NONOS SDK 2.2.2-dev), built for board `ESP8266_NODEMCU`. App
at 0x1000 (~1 MB slot), SPIFFS at 0x200000. Settings live in SPIFFS as JSON
(`/config.json`, `/wifi.json`, `/light.json`, `/leds.json`, `/alerts.json`, `/hardware.json`).
- **Hidden pages**: `/d` = "Hardware setting" (hidden from the menu by default). It has
checkboxes to hide/show menu items and a **Debug mode** (`dev`) checkbox. With Debug
mode on, `/u` serves the standard ESP8266HTTPUpdateServer upload form, which is web OTA
for `.bin`/`.bin.gz`. `/r` reboots on a plain GET; don't GET unknown paths blindly.
- No pin numbers are visible as strings; confirming the pinout needs disassembly or the
bit-stepping test sketch.
## Pinout
From the 12 V v2 schematic (`docs/schematic_v2_12V.jpg`), checked against the stock firmware
by disassembly (`docs/stock-firmware-pins.md`, tools in `tools/`). "Hardware" = also works
on the clock with UniClock; "Binary" = only confirmed in the stock SV1.3 code.
| Function | GPIO | Source |
|---|---|---|
| 74HC595 DATA / CLOCK (OE tied to GND) | 13 / 14 = HSPI MOSI / SCK (hardware SPI, MSB first) | Hardware |
| 74HC595 LATCH | 15, plain `digitalWrite` (has 1k pull-down) | Hardware |
| WS2812 data | 12 (NeoPixel bit-bang, GRB 800 kHz; 8 fitted, stock assumes 12). `SPI.begin()` turns GPIO12 into MISO: set it back to OUTPUT afterwards | Hardware |
| Photoresistor (LDR, 10k to GND) | ADC (A0) | Hardware |
| BTN1 / BTN2 (not fitted) | 0 / 2, INPUT_PULLUP. Stock: GPIO0 is a button, GPIO2 a motion/presence input that wakes the display | Binary |
| DFPlayer Mini (stock feature) | UART0: GPIO1 TX / GPIO3 RX, 9600 Bd | Binary |
| DS3231M RTC SDA / SCL | 4 / 5: **no I2C device answers** (UniClock scan), so no RTC on this board; NTP only | Hardware |
Two chained 74HC595s make one 16-bit word, all bits active-high (confirmed from the binary;
the high byte is sent first and goes to U2):
- U1 QA..QH = cathodes 0..7 (bits 0..7), U2 QA = cathode 8 (bit 8), QB = cathode 9 (bit 9)
(via 2x ULN2003, shared by all tubes)
- U2 QC = P1 (bit 10) drives **both** IN-3 neon dots. QD..QG = anodes A1..A4 (bits 11..14,
MMBTA42/92). QH = P2 (bit 15) drives the IN-12B **decimal points** on this board (JP2 closed),
not a neon.
- The display is multiplexed: one anode on at a time. **A1 = leftmost tube (hour tens),
A4 = rightmost (minute ones)** (verified on the tubes). The dots are lit in the minute-tens
slot only, as on stock.
## Programming header
Header on the PCB: GND, GPIO0, RST, RXD, TXD, 3.3V. The USB-C port only supplies power.
Flashing is done with a CH340C board on **COM7** (COM3 is another device; leave it alone).
Wiring: GND-GND, adapter TXD -> clock RXD, adapter RXD -> clock TXD, adapter 3.3V not
connected (the clock is powered from its own USB-C). No auto-reset: to enter flash mode, hold
GPIO0 to GND, tap RST to GND, then release GPIO0.
- esptool is installed for the user (`python -m esptool`, v5.6.0). After `--after no-reset`
the stub keeps running at the new baud rate and the next esptool call can't connect: do
everything in one call, or re-enter flash mode.
- Normal updates go over WiFi: `pio run -e nixie_in12_ota -t upload` in `firmware/uniclock/`.
ArduinoOTA does not answer after the clock switched from AP mode to WiFi without a reboot
(first setup); a power cycle fixes it.
- `firmware/stock/` holds the stock flash dump. **Never overwrite or delete it**; it is the
only way back to SV1.3 (`write-flash 0 <dump>`). Dumps are gitignored because the flash
holds the WiFi password; never commit them.
## Constraints
- The 170 V tube supply is live whenever USB-C is connected.
- Hardware is only reachable via the user: anything that needs RST/GPIO0 or looking at the
tubes must be asked of them. Builds can be checked here, but runtime behaviour can't.
- Show the exact plan before making changes to the device (flashing, saving settings).
## Plan
1. Done: dump and inspect the stock firmware.
2. Skipped (the disassembly was enough): bit-stepping test sketch.
3. Done: 74HC595-multiplex driver (`nixie595.ino`) + CLOCK_90 in ESP_UniClock, ArduinoOTA,
EU DST fix. Runs on the clock.
4. Done: Home Assistant over MQTT (broker 10.1.1.175, discovery prefix `homeassistant`).
`mqtt.ino` rewritten for ArduinoHA 2.1.0: switches Tubes/Auto dim, numbers Day/Night
brightness, light Backlight (on/off, brightness, RGB -> UniClock colour wheel), select LED
effect, button Cathode protect, sensors Light/WiFi signal. Broker settings are read at boot.
5. Open: OTA password via `secrets.h`; ArduinoOTA after the AP -> WiFi switch.