Files
nixie-clock/CLAUDE.md
T
mangavalkandClaude Opus 5.5 5fbae6247c Fix tube flicker and review fixes
- The bit-banged WS2812 update disables interrupts (about 30 us per
  pixel), which made the lit tube stay on longer and flash. neoShow()
  now only sends when the pixels changed (fixed colour was resent every
  second) and waits for the dark gap between tubes; the bit-bang strip
  has no headroom pixels. This also fixed digits that seemed to hang.
- 4 WS2812 on this board, one per tube (not 8)
- Saving the firmware URL in the web UI no longer starts an HTTP
  update; never update from an empty URL
- Restart once after the first switch from AP mode to WiFi, so
  ArduinoOTA and MQTT start on the real network
- Optional web UI password (WEB_USER/WEB_PASSWORD in secrets.h);
  /getConfiguration returns the stored WiFi and MQTT passwords
- Cathode protect: random mode now starts at a random tube (the +-1
  start digits were swapped and then overwritten)
- Apply the unused gamma table to wheel colours
- LOOP_DIAG (off by default): main-loop stalls in /getCurrentInfos,
  which now also reports uptime and free heap

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

104 lines
6.4 KiB
Markdown

# Nixie clock: notes for Claude
An AliExpress WiFi nixie clock (4x IN-12 + 2x IN-3 neon dots, 4x WS2812, one under each tube) 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; 4 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/`
(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).
- `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. 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.