2026-10-25 20:24:32 +01:00
# Nixie clock: notes for Claude
2026-10-25 22:18:39 +01:00
An AliExpress WiFi nixie clock (4x IN-12 + 2x IN-3 neon dots, 4x WS2812, one under each tube) that is being
2026-10-25 20:24:32 +01:00
moved from its closed stock firmware to ESP_UniClock (https://github.com/gpeter62/ESP_UniClock)
with ArduinoOTA and Home Assistant (MQTT) support.
## The device
2026-10-25 21:23:10 +01:00
- 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).
2026-10-25 20:24:32 +01:00
- 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.
2026-10-25 20:29:05 +01:00
## 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.
2026-10-25 20:42:56 +01:00
## Pinout
2026-10-25 20:24:32 +01:00
2026-10-25 20:42:56 +01:00
From the 12 V v2 schematic (`docs/schematic_v2_12V.jpg` ), checked against the stock firmware
2026-10-25 21:23:10 +01:00
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.
2026-10-25 20:24:32 +01:00
2026-10-25 20:42:56 +01:00
| Function | GPIO | Source |
|---|---|---|
2026-10-25 21:23:10 +01:00
| 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 |
2026-10-25 22:18:39 +01:00
| WS2812 data | 12 (NeoPixel bit-bang, GRB 800 kHz; 4 fitted, stock assumes 12). `SPI.begin()` turns GPIO12 into MISO: set it back to OUTPUT afterwards | Hardware |
2026-10-25 21:23:10 +01:00
| Photoresistor (LDR, 10k to GND) | ADC (A0) | Hardware |
2026-10-25 20:42:56 +01:00
| 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 |
2026-10-25 21:23:10 +01:00
| DS3231M RTC SDA / SCL | 4 / 5: **no I2C device answers** (UniClock scan), so no RTC on this board; NTP only | Hardware |
2026-10-25 20:24:32 +01:00
2026-10-25 20:42:56 +01:00
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)
2026-10-25 21:23:10 +01:00
- 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.
2026-10-25 20:42:56 +01:00
- The display is multiplexed: one anode on at a time. **A1 = leftmost tube (hour tens),
2026-10-25 21:23:10 +01:00
A4 = rightmost (minute ones)** (verified on the tubes). The dots are lit in the minute-tens
slot only, as on stock.
2026-10-25 20:24:32 +01:00
## 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.
2026-10-25 21:23:10 +01:00
- 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.
2026-10-25 22:18:39 +01:00
- Normal updates go over WiFi: `pio run -e nixie_in12_ota -t upload` in `firmware/uniclock/`
(web UI files: `-t uploadfs` ). After the first switch from AP mode to WiFi the clock restarts
once by itself, so ArduinoOTA/MQTT start on the real network.
- `/getCurrentInfos` (no password) has `uptime` and `heap` ; with `LOOP_DIAG` in CLOCK_90 also
`stalls` (main-loop gaps of 250 ms or more, by step name).
2026-10-25 20:24:32 +01:00
- `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
2026-10-25 21:23:10 +01:00
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.
2026-10-25 21:37:25 +01:00
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.
2026-10-25 22:18:39 +01:00
5. Done (2026-10-25): tube flicker fixed (the bit-banged WS2812 update blocks interrupts, so
it is now only sent when the pixels change, and only in the dark gap between tubes; this also
fixed digits that seemed to hang). Saving the firmware URL no longer starts an update.
Optional web password, cathode-protect random start, LED gamma.
6. Open: the user can create `secrets.h` (gitignored, never read it) for OTA and web passwords.