Adds CLOCK_90 and the nixie595.ino driver: two 74HC595s on hardware SPI (GPIO13/14, latch GPIO15), multiplexed from an IRAM-only timer1 ISR. Neon dots on P1; P2 is the decimal-point line on this board. Also: - NeoPixel on any ESP8266 pin via bit-bang (GPIO12), and take the pin back after SPI.begin() claimed it as MISO - ArduinoOTA (USE_ARDUINO_OTA), with an OTA upload env in platformio.ini - DST: EU end date (last Sunday of October) instead of the first Sunday of November, and recompute the time from the rules when DST is toggled instead of shifting it by 1 h - forward declarations so PlatformIO's .ino conversion compiles - FIRMWARE_SERVER can be overridden; empty for CLOCK_90 Verified on the clock: tubes, order, dots, LEDs, LDR, NTP time with DST. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.5 KiB
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 (hostnamenixie-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-256b069f4eb93cf1e9063a30374db4d70508211f07b0a17049bcf9ebdeda65f2985, verified against the chip withverify-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,/userves the standard ESP8266HTTPUpdateServer upload form, which is web OTA for.bin/.bin.gz./rreboots 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-resetthe 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 uploadinfirmware/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
- Done: dump and inspect the stock firmware.
- Skipped (the disassembly was enough): bit-stepping test sketch.
- Done: 74HC595-multiplex driver (
nixie595.ino) + CLOCK_90 in ESP_UniClock, ArduinoOTA, EU DST fix. Runs on the clock. - Next: Home Assistant controls over MQTT (display on/off, brightness, LEDs; upstream MQTT
only publishes sensors), OTA password via
secrets.h.