OpenSCAD truss insert that holds the EL512.256-H and a Wemos D1 mini
ESP32 in a 250 x 200 x 30 mm photo frame. The D1 mini snap-tab lips
print without supports: a 45 degree chamfer bridges the gap to the
pocket, only the catch is a short flat overhang, and the tip is blunt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The top pill now stops before the wider ALERT CONDITION RED title, the
printer lines sit higher with room between them and the bottom pill, and
the sweeping rectangles are clipped to the area above those lines.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Interstellar: Gargantua with a time dilation clock (Earth today vs.
Miller's planet), TARS with his settings and remarks about the house,
the Endurance spinning at a solar-driven RPM while a Ranger docks, and
the tesseract's bookshelf with the time in binary dust and the Message's
first word in Morse on a watch.
Your Name: comet Tiamat splitting over Itomori's lake, and
kataware-doki, a countdown to sunset from sun.sun where two silhouettes
stand on the crater rim during the twilight hour.
HomeData gains sunset, sunrise and sun elevation (with an ISO time
parser); wrap() and typed() move to el512_pages.h. Share Tech Mono 22
gets the full Latin set. All pages are in the renderer, checked with
normal, busy and empty data.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tube was 56 px wide while its dome (radius 28) spans 57, so the dome
overshot the right wall by a pixel; tubes are now 57 px. The Nixie digits
at size 110 were up to 60 px wide (plus the 1 px glow) in a 55 px tube;
size 90 fits, and each digit is clipped to the inside of its glass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tools/render_pages.py compiles the page code natively with g++ against
ESPHome's own display and font code and the font bitmaps of the last
`esphome compile`, and draws pages to PNG at chosen moments with sample
data (normal, empty, alert, busy), as a contact sheet, or as one example
per page in docs/images/pages (now shown in the README).
Fixes found with it: Cyber HUD zone names ran into the temperatures,
the breach header label hit the tag and the column marker the matrix
label; KonoSuba subtitle, guild weather icon, cabbage text and all-day
deadline, and hills through the party; Steins;Gate D-mail recipient, the
microwave display, the gadget card value and world line labels; LCARS
room rows, readout bars and data cascade, warp core readouts, and the
captain's log weather wording.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LCARS ship status, the Cerritos duty roster from the agenda, a warp core
driven by solar power with Rutherford's advice, and a captain's log under
a viewscreen. Original pixel art in tools/trek_sprites.py.
When the 3D printer (Moonraker current_print_state, `printer`
substitution) is paused or in error, the panel jumps to LCARS Status in
red alert and holds the rotation until it carries on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rotation already waits while the show plays, and the show returns to
the page it came from when it ends.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The EL512 Plex streams sensor now reads the Plex media players
(media_player.plex_*) every 5 s: who, title, playing/paused, position and
duration, falling back to the server sensor's list without them. The Plex
page shows a play/pause icon, position / duration and a thin progress bar
per stream (dotted while paused), counting on between updates.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Divergence meter (Nixie tubes, world lines and clock), a D-mail sent
through the Phone Microwave using the panel's Message text, the Future
Gadget Lab inventory with live sensors, and a world line chart of today's
solar power. Original pixel art in tools/steins_sprites.py; the sprite
tool is shared between themes and Sprite, sprite(), polar() and arc()
move to el512_pages.h. HomeData gains the message and a 24 h solar
history in 15-minute slots.
The rotation now walks all pages in a random order that is reshuffled
every hour (Still Alive stays out, Now playing is skipped when idle).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Megumin's daily explosion, the Adventurers' Guild quest board (agenda,
weather, solar), Megumin's adventurer card and a party battle against a
giant toad with a live-data battle log. Original 1-bit pixel art lives in
tools/konosuba_sprites.py, which generates konosuba_sprites.h and can
render a preview PNG.
Home data and drawing helpers shared by the themed pages move to
el512_pages.h; the display gains dither_mask() for a dissolve-in intro.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Netrunner HUD, self-solving breach protocol, optics boot-and-scan and a
split HUD with a mini breach matrix, all in the page rotation. The el512
display gains animated_pages / animation_interval (redraw ~15 fps while
shown), page_age_ms() as animation clock, and shift_rows() / invert_rect()
for glitch effects.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- el512_panel.cpp: esp_cpu_get_cycle_count() exists only in ESP-IDF 5;
use cpu_hal_get_cycle_count() on 4.4 (Arduino 2.x), which broke both
PlatformIO environments.
- README: ring-buffer refresh, tear-free status, D1 mini ESP32, new layout
(components/el512, esphome/, home_assistant/), ESPHome setup, Still Alive
paths, and the Wi-Fi blanking findings with wiring advice.
- docs/README: ring, lookup table, double buffer, health counters; tear-free
and memory items done; Wi-Fi blanking and boot blanking as open items.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The panel driver counts ring refills, the largest gap between refills,
frame swaps, swap timeouts and I2S TX FIFO underruns (takeStats()). The
ESPHome component checks them every 10 s and logs a warning only when the
ESP32 side of the signal had a problem, plus a debug summary per minute.
Measured with Wi-Fi on: ~4600 refills/s, max gap < 0.4 ms (lead 1.7 ms),
no underruns or timeouts, so remaining blinks come from the signal being
disturbed on the wires (Wi-Fi transmit bursts), not from the refresh.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Driver (components/el512/el512_panel.*, ESP-IDF only):
- DMA ring of 8 x 4 lines (17 KB) refilled from the I2S EOF interrupt
(IRAM) instead of a 142 KB full-frame stream; ~107 KB heap freed.
- 256-entry lookup table encodes 8 pixels per step.
- Back buffer + displayed buffer, swapped at the start of a frame.
- PlatformIO builds it via lib_extra_dirs (EL512Core); lib/EL512 keeps
the Adafruit GFX front end.
ESPHome external component (platform: el512):
- DisplayBuffer with optional ENABLE / _LOWPWR pins, set_enabled(),
set_low_power(), helper functions for page lambdas.
- still_alive_page: plays the Portal end-credits show, then returns to
the previous page.
Still Alive engine moved to components/el512/still_alive.* with a built-in
5x7 font (from Adafruit GFX, BSD); the PlatformIO demo uses the same code.
The importer writes components/el512/still_alive_data.h and stops at 200 s
(--until-ms), matching the hand-trimmed data.
esphome/el512-panel.yaml: 8 pages (clock, forecast, agenda, dashboard,
now playing, Plex, solar, Still Alive), page select, rotation, display
and low-power switches, message text. home_assistant/packages/el512_panel.yaml:
helper template sensors for forecast, agenda, now playing and Plex streams.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The source page splits some lines into several spans; a browser renders the
whitespace between them as a space, which the importer dropped ("becausewe").
It now adds that space. Regenerated imported.h.
Add a photo of the demo on the panel to the README.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Commit src/still_alive/imported.h instead of ignoring it. The importer now
writes a source reference (SDSkyKlouD/still-alive-web) and a disclaimer
(Jonathan Coulton / Valve, personal non-commercial use, not affiliated) at
the top of the file; the README carries the same disclaimer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- src/still_alive: timed console text, typed scrolling credits and ASCII art,
laid out for 512x256 (41x31 console, 41x9 credits, 41x20 picture).
Plays placeholder content unless imported.h exists.
- tools/import_still_alive.py: generates the git-ignored imported.h (text,
timing, art, credits) from SDSkyKlouD/still-alive-web.
- platformio.ini: envs still_alive (default) and esp32dev (test images,
moved to src/test_images).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Uninverted, the rising BCK edge landed on the boundary between byte pairs,
so the panel sampled data mid-change and the image jittered. Inverted, the
edge sits mid-pair; verified stable on the panel. Also note the row-stripe
brightness drift as an open item.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PCNT measurement showed I2S0 BCK (VCLK) rising once per two bytes in 8-bit
LCD mode, so the panel saw every other byte. Each VCLK is now two identical
bytes at a 10 MHz byte rate (VCLK 5 MHz). The doubled ~142 KB stream is
allocated as 38 per-descriptor chunks.
The test sketch now cycles through 12 labelled test images.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The datasheet numbers columns from 1 (Fig. 3: "row 1", "Last pixel
(512 / 256)") and puts odd columns on TVID, so x = 0 (column 1) now
goes to TVID and x = 1 to VID; the encoder had them swapped.
README wiring now lists the J1/J2 pins and power rails from Table 1,
the 5 V buffer, and a pull-down on ENABLE so the panel stays off while
the ESP32 boots without VCLK. encodeRow() documents its T4/T5 margins.
docs/README.md open items are regrouped into done, hardware checks and
software work. main.cpp counts seconds, not frames.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The datasheet (docs/datasheet, Planar 020-0354-00A) is now stated as the
source of truth. Two-bit mode is PS1 jumper 2 (DCONFIG) removed
(Table 3), not a generic "mode jumper". The README timing table now lists
the Table 5/6 limits beside our values, and the notes add T1-T8, the
8 ns setup/hold from Figure 4 and the input levels from Table 4.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
startI2S() sets up I2S0 in 8-bit parallel (LCD) mode at 5 MHz
(PLL_D2 160 MHz / 32, BCK div 1), routes stream bits 0..3 to
VID/TVID/HS/VS via I2S0O_DATA_OUT16+n and BCK to VCLK, and loops
DMA over an 18-descriptor chain of whole lines. stopI2S() stops TX,
returns the pins to GPIO low and frees the chain.
encodeRow() now stores clock c at c ^ 2 to match the 8-bit mode
byte order (bytes 2, 3, 0, 1 per word, as in bitluni's ESP32Lib).
Builds with no warnings; not yet checked on hardware.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PlatformIO skeleton (esp32dev, Arduino, Adafruit GFX) with a local EL512
library: EL512Panel (1 bpp framebuffer, two-bit-mode row encoder, I2S DMA
refresh stub) and EL512_GFX (Adafruit_GFX subclass). Adds a test sketch,
pin map, README with wiring and timing, and moves the datasheet to
docs/datasheet/.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>