fix(tide-display): load bitmap fonts at their own size, and document everything - #370
Conversation
…everything The font picker worked or not by coincidence. A .bdf exists at exactly one pixel size and FreeType rejects any other, so 4x6.bdf loaded because its native 6 happens to equal the default font_size, while 5x7.bdf silently fell back to the default face -- and the two would swap over if font_size were set to 7. Hashing one render per face showed 4x6-font.ttf and 5x7.bdf producing the same image; after the fix all five are distinct. Same fix already landed for clock-simple and news, which share this loader. The README was a 70-line stub with none of the plugin's four screens shown. It now covers all 18 settings with real rendered screenshots of every screen, taken from recorded NOAA responses for station 8443970 on 2 September 2026, and explains the thing you actually have to do first: find your station ID. Two behaviours that were undocumented and look like faults: a station without a live water-level sensor falls back to predictions rather than erroring, which is the common case; and unit conversion is done by NOAA rather than locally, so the metric heights are authoritative rather than a rounding of the imperial ones. The 32-row stats screen draws the range line and the percentage close enough to overlap at some values. Recorded as an observation with the images to show it, not diagnosed -- the chart and schedule screens are unaffected and 64 rows clears it. Tooling: the HTTP replay can now match on query parameters, not just the URL. NOAA puts three endpoints behind one URL and distinguishes them by params, and without this every request returned whichever fixture matched first. It also caught a mistake of mine: with the fixture ignoring the units parameter, metric mode rendered the imperial numbers with an "m" suffix and looked exactly like a missing conversion. Recording both unit systems and matching on the parameter shows the real metric predictions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Comparing against the old README by eye turned up three things my heading heuristic passed over -- it matched incidental words rather than content, so 'Popular Station IDs' looked covered because the new file happens to say 'station' elsewhere. Restored, each verified against the source first: - Disabling every screen shows all four rather than nothing. _build_enabled_modes returns 'modes or list(self.MODES)', with a comment saying the plugin should never go dark. Worth stating, since the obvious reading of four booleans is that turning them all off leaves a blank panel. - The ten-station starter table. Finding a station ID is the one thing a new user has to do, and a handful of known-good IDs saves a trip to NOAA's map. - Caching, and what happens when NOAA is unreachable. Predictions sit under a stable per-station key and refetch on a date change; the live level is cached for six minutes; and STALE_MAX_DAYS serves the last good predictions for up to two days offline before falling back to a placeholder, because tides shift about fifty minutes a day and older times would be confidently wrong. The audit is a floor, not a guarantee -- it catches dropped config keys reliably and dropped prose only sometimes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Not up to standards ⛔🔴 Issues
|
| Category | Results |
|---|---|
| Security | 1 medium |
🟢 Metrics 14 complexity
Metric Results Complexity 14
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
…ted the screens render_preview.py drew its own mock versions of all four screens, with a header asking that its palette "must match manager.py". Nothing enforced that, so its seven committed preview_*.png files could drift from what the plugin actually draws and no check would notice -- and they shipped to every Pi on install, about 115KB of images the display never reads. The README's screenshots now come from scripts/render_docs_assets.py, which runs the real plugin against recorded NOAA responses and is verifiable with --check, so the mock generator no longer buys anything the repo does not have a better version of. Worth contrasting with geochron, which has a render_preview.py of its own and does it correctly: it imports geochron_renderer, the same module manager.py draws with, so its previews cannot disagree with the plugin. That is the pattern to copy if a standalone generator is wanted here again -- factor the drawing out and have both call it, rather than keeping a second copy of the palette. Nothing else in the repo referenced the removed files. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Took you up on the offer and removed The case for removing rather than keeping: the script drew its own mock versions of all four screens, with a header asking that its palette "must match manager.py". Nothing enforced that, so its committed previews could drift from actual output with no check to notice — and they shipped to every Pi on install, ~115KB the display never reads. Worth contrasting with geochron, which has a Nothing else in the repo referenced the removed files (checked across Separately, per your ask, I've started filing findings as issues rather than leaving them in PR descriptions — #371, #372, #373 here and ChuckBuilds/LEDMatrix#517 for the core font root cause. |
…ns (#374) Completes the sweep. A .bdf exists at exactly one pixel size and FreeType rejects any other with "invalid pixel size", so every bitmap face in these two pickers failed at the configured font_size and silently fell back to the default -- choosing one appeared to do nothing, with only a log warning nobody reads. Bitmap faces are now retried at the size the file's PIXEL_SIZE header declares. cozette.bdf is also removed from mqtt-notifications' picker. The file is shipped by neither the core nor the plugin, so selecting it could only ever fall back. youtube-stats never listed it. Same fix already landed for clock-simple (#362), news (#369) and tide-display (#370), which carry copies of this loader. That is five plugins with one bug, so the root cause is filed against the core as ChuckBuilds/LEDMatrix#517: FontManager.resolve_font degrades to the default face for any .bdf without signalling it, which is why each plugin had to work around it separately. Verification is unit-level rather than by render, because neither plugin draws text without credentials -- mqtt-notifications needs a broker and youtube-stats an API key, so the hash-comparison used on the other plugins produces identical "no data" screens either way. Instead the loader's own path is exercised directly: _bdf_pixel_size returns 7 for 5x7.bdf and 6 for 4x6.bdf, ImageFont.truetype fails for both at size 8, and succeeds at the reported native size. That is exactly the branch the fix takes. The harness passes 8/8 for both. mqtt-notifications could not be harnessed at all before this: it fails to instantiate without paho-mqtt, which is in its requirements.txt but not in the core's environment, so anyone running check_plugin without installing it first sees eight load errors rather than a result. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The replay shim gained a feature on each side and they had to be combined rather than chosen between: main added params_contain (#370, for an API that puts several endpoints behind one URL), while this branch added body_file and changed _match to return a response object rather than a bare body (so poster art can be served as bytes). Resolved so _match filters on params first, then serves either a file as bytes or the JSON body, always wrapped in a _ReplayResponse; both callers pass the request params through. Also dropped a sentinel line the merge duplicated. Verified after resolving: --check reproduces jellyfin's five body_file-driven images and tide-display's params_contain-driven ones byte-identically, so neither side's feature was lost. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Tenth plugin in the README pass.
The font picker worked by coincidence
A
.bdfexists at exactly one pixel size and FreeType rejects any other. So4x6.bdfloaded — its native 6 happens to equal the defaultfont_size: 6— while5x7.bdfsilently fell back to the default face. Setfont_size: 7and the two would swap over.Same fix as #362 and #369. That's four plugins now;
mqtt-notificationsandyoutube-statsstill carry it — happy to sweep both in one PR if you'd prefer that to finding it plugin by plugin.The README was a 70-line stub
None of the plugin's four screens were shown. It now covers all 18 settings with real screenshots of every screen, from recorded NOAA responses for Boston, and leads with the thing you actually have to do first — find your station ID.
Two behaviours that were undocumented and look like faults:
englishormetric, so both are authoritative figures rather than one rounded from the other.A mistake the tooling caught
The HTTP replay can now match on query parameters, not just the URL — NOAA puts three endpoints behind one URL and tells them apart by params, so without it every request got whichever fixture matched first.
That directly caught an error of mine. With the fixture ignoring
units, metric mode rendered the imperial numbers with an "m" suffix — 9.7ft became "9.7m". It looked exactly like a missing unit conversion, and I was a step from writing it up as a bug. Reading the code showed the plugin correctly mapsimperial→englishand lets NOAA convert; the fault was entirely in my fixture. Recording both unit systems shows the real values (9.7ft / 3.0m).One observation, not a diagnosis
On a 32-row panel the stats screen draws the range line and the percentage close enough to overlap at some values. It's in the README with images showing it, described as what it is rather than diagnosed — the chart and schedule screens are unaffected, and 64 rows clears it.
A note on
render_preview.pyThe plugin ships its own preview generator that re-implements the screens, with a header noting its palette "must match manager.py" — so its
preview_*.pngfiles can drift from real output without anything failing. The README images here come from running the actual plugin instead. I've left the script and its PNGs alone and just noted the difference; say the word if you'd like them removed, since they also ship to users' Pis on install.Verification
check_plugin.py --plugin tide-display— 32/32 PASS (8 sizes × 4 modes)render_docs_assets.py --plugin tide-display --check— images match🤖 Generated with Claude Code