Commit Graph
5 Commits
Author SHA1 Message Date
kemal 3c99cd53e3 Weather glyphs: sun, umbrella, snowflake, switched by the data
Three references were requested as 8x8 animations. Copying their frames does
not work and I measured it rather than asserting it: at 8x8 the sun is a
2025:1 area reduction and its rays vanish, the umbrella loses canopy and
handle, and the snowflake averages into the background. Downsampled they move
0.0037, 0.0175 and 0.0027 per frame against 0.0177 for the aurora already on
the panel, so frame-copying would have been a downgrade. The sun source is
only 3 frames and the umbrella 4. These are hand-drawn at 8x8 instead, taking
the palette and subject from the references, which also keeps three artists'
frames out of an Apache-2.0 repo.

Transitions are now the data. _pick_glyph reads rain probability, Kalman
temperature, solar elevation and cloud index and selects sun, umbrella or
snowflake; a change preempts whatever is on screen and crossfades immediately,
so the panel dissolves because the weather moved, not because a timer expired.
Between changes the informational scenes still rotate. Verified switching live:
sunny -> sun, rain forecast -> umbrella, temperature to 0.4 C -> snowflake,
clearing -> sun.

Getting them to read took two failed passes, both recorded in comments. First
version blew the canopy to white and fused the snowflake into a blob, because
seventeen arc samples over ten pixels overlap 1.7 deep. Dropping alpha made
them muddy instead. The fix was sampling density, not brightness.

Profiled again since these share the board: the glyphs first cost 11 to 13% of
a core. Making plot() write scalar components rather than a 3-vector slice, and
expressing the sun's eight-fold rays as one angular field instead of 56 splats,
took the sun from 275 to 43 us and the worst scene overall from 13.2% to 8.0%.
2026-08-15 23:15:50 +01:00
kemal e05667d75b Make the matrix frame rate configurable
24 fps costs about 11% of one core on a Zero 2 W, measured on the board. That
is a reasonable default for something you look at, but it is a decorative load
sharing a 512 MB machine with the forecaster, so it should be the owner's
choice. server.led_fps is clamped to 4..30.

Particle fall speed now divides by the configured rate rather than the module
constant, so rain falls at the same real-world speed whatever the frame rate,
instead of slowing down when you turn the frame rate down.
2026-08-15 23:04:05 +01:00
kemal 30944c2978 Rewrite the LED matrix as an animated instrument
The old display drew static glyphs, held them, and cut to the next, which looks
like a microwave clock. This is a continuous 24 fps renderer.

Three things do most of the work. Gamma, because LED duty cycle is linear and
perception is not, so ungamma'd gradients band and dim colours vanish.
Sub-pixel rendering, so a dot at x=3.4 lights two pixels and motion glides
rather than steps. Crossfades, so scenes dissolve over 1.3 s and nothing ever
cuts.

Added temporal dithering after finding the framebuffer is RGB565: 32 levels of
red and blue, which after gamma leaves very few steps exactly where an aurora
and a star field live. A Bayer pattern rotated each frame alternates between
adjacent hardware levels, measured landing on 1.75, 4.31 and 8.06 where the
panel can only display integers. The panel is also dimmed by measured lux on a
log curve, so at night it is a glow rather than a searchlight.

Five scenes, each a reading rather than decoration. Aurora: hue is temperature,
curtain drift direction is pressure tendency, contrast is humidity. Solar sky:
sun at its true azimuth and elevation over a dawn/day/dusk gradient, becoming a
twinkling star field and moon after sunset. Precipitation: drop count from rain
probability, snow below 1.5 C with sideways sway, lightning with exponential
afterglow when stormy. Forecast ribbon: six horizons scrolling, height is the
predicted delta, pale caps are the conformal half-width so uncertainty is
visible. Barometer: a breathing ring whose period is the tendency.

Profiled because it shares a 512 MB board with the station. The first ribbon
cost 330 us a frame, about 16% of a core scaled to a Zero 2 W; vectorising it
into fields rather than 84 sub-pixel splats brought the worst scene to 7.6%.
Verified 23.6 fps sustained with zero malformed frames.
2026-08-15 23:00:35 +01:00
kemal dbbea1a95f chore: enforce ruff config and fix lint findings 2026-08-15 20:45:02 +01:00
kemal 06ce53bc44 Initial release: Ashvale Station 1.0.0 2026-08-15 20:43:51 +01:00