The epd4in0e panel's palette has no gray at all (just black/white/
yellow/red/blue/green -- see epd4in0e.py's putpalette), so any gray
RGB fill gets Floyd-Steinberg dithered into a black/white checkerboard
across the whole glyph body. At the small font sizes most of these
screens use (Navidrome's artist/album/genre/source lines, Departures'
direction/platform columns, Weather's description/forecast labels,
Clock's date line, the placeholder messages), that reads as blurry,
half-rendered text -- same root cause already fixed in Journey.
Switched every gray fill/outline to solid black across navidrome.py,
weather.py, departures.py, clock.py, and picture.py. Left the
intentionally-faint row-divider hairlines (228,228,228) alone --
those are meant to almost disappear, not readable text. Removed
departures.py's now-unused MUTED constant.
Screen.poll_interval was a fixed class attribute the scheduler read
directly -- added Screen.get_poll_interval(settings) so a screen can make
it settings-driven instead. WeatherScreen overrides it to read a new
"update_minutes" field (default 30, matching the old hardcoded value).
New number input on the Weather settings page.
Caught a real edge case while testing: `raw or 30` treats an explicit 0
as falsy and silently replaces it with 30 instead of clamping to the
1-minute floor. Not reachable via the UI (min="1" on the input) but the
method should still be correct standalone -- fixed with an explicit
None-check instead.
New screens/weather_icons.py: vector icons drawn with PIL primitives using
the panel's actual 6-color palette (black/white/yellow/red/blue/green, from
epd4in0e's own getbuffer() quantization table) -- sun with rays, line-art
clouds, blue rain/snow, yellow lightning bolt, fog bands. Replaces the old
monochrome unicode-glyph approach entirely (also sidesteps font coverage
gaps -- that's what caused the earlier tofu-box bug).
Forecast row given significantly more vertical space per request. Caught
two real bugs while building this:
- Current-conditions block height was guessed independently of the space
allocated to it, so it overflowed into the forecast row for real content.
Now derives the space it needs from actual measured text/icon size
instead of assuming both fit.
- `scale * 0.045 if has_forecast else 0.05` -- conditional-expression
precedence bug, silently evaluated to a bare 0.05 (not scale * 0.05) in
the else branch, crashing font loading with size=0 when forecast is
empty. Only surfaced by testing that specific case.
- Sun icon's rays extended past the nominal icon_size box used for layout
math, throckwing off vertical centering when no forecast is shown.
- scheduler: "Show X now" was a true one-shot -- reverted on the very next
5s tick, causing the flash-to-X-then-flash-back-to-clock behavior. Now
pins for 5 minutes (still preemptable by Navidrome priority, which stays
authoritative). Added a "Resume automatic" action/button and status
display showing what's pinned and until when.
- weather: daily forecast strip (3/5/7 days, selectable in settings) below
current conditions, via Open-Meteo's daily= params in the same request.
Fixed a bad symbol choice along the way -- DejaVu Sans has no glyph for
the partly-cloudy emoji, was rendering as a tofu box; swapped to the
plain cloud symbol, verified glyph coverage for the whole WMO code table.
- Panel is mounted sideways: render landscape (600x400), rotate to the
panel's native portrait orientation right before writing to hardware.
- Web UI: card-based layout, dark mode, active nav highlighting, save
confirmation toasts, error banners.
- Rotation: separate enabled/disabled toggle (off pins to the first screen
in the list) and the interval is now in minutes instead of raw seconds.
Migrates existing config.json from the old interval_seconds field.
- Weather: type a city name instead of hunting down coordinates, resolved
via Open-Meteo's free geocoding API. Manual lat/long still available as
a fallback.