Flight Tracker: optional airport weather (METAR/TAF/PIREP/SIGMET)#176
Conversation
Adds an opt-in "metar" rotation view that shows aviation weather for user-chosen airports using the free NOAA Aviation Weather Center API (no API key). Per airport it rotates a color-coded decoded METAR card (flight-category badge: VFR/MVFR/IFR/LIFR), a raw METAR page, and optional TAF and PIREP pages, plus a trailing SIGMET/AIRMET page. - New metar_fetcher.py: cache-first, serve-stale AWC client. METAR/TAF batched by ids; PIREP per-airport; SIGMET global. Never raises to the caller. - manager.py: new rotation view + granular slot, config read in __init__/on_config_change, independent fetch cadence in update(), timed page-rotation display, and content gating so an empty/unfetched slot is skipped. - renderer.py: decoded METAR card + raw/TAF/PIREP/SIGMET pages, adaptive to 64x32 / 128x32 / 128x64 / 256x32. - config_schema.json: nested "metar" object; "metar" added to rotation_views. manifest bumped 1.10.0 -> 1.11.0; registry synced. - Tests for normalization (hPa->inHg, ceiling), TAF batching/merge, serve-stale, PIREP, and SIGMET parsing. NOTAMs are intentionally excluded (they require separate FAA OAuth credentials, unlike the key-free weather endpoints). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ka1E5TT1Ai9cuKV9j7g4C
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (10)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds optional airport weather support to the ledmatrix-flights plugin, including NOAA AWC retrieval, METAR rotation configuration, weather rendering, incremental refresh integration, tests, documentation, and release metadata updates. ChangesAirport Weather Feature
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant FlightTrackerPlugin
participant MetarFetcher
participant NOAA_AWC_API
participant FlightRenderer
FlightTrackerPlugin->>MetarFetcher: service queued weather refresh
MetarFetcher->>NOAA_AWC_API: fetch METAR, TAF, PIREP, and SIGMET data
NOAA_AWC_API-->>MetarFetcher: return aviation weather payloads
MetarFetcher-->>FlightTrackerPlugin: return normalized weather data
FlightTrackerPlugin->>FlightRenderer: render selected weather page
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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 |
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 234 |
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.
The weather view (METAR/TAF/PIREP/SIGMET) rendered in the plugin's blocky PressStart2P + 4x6 fonts, which are hard to read for the long weather strings at small panel sizes. Switch the weather cards to the cleaner, more legible 5x7 face already used elsewhere in the project (elections, masters, f1-scoreboard) and rendered normally (no pixel snapping) so it reads like text. - renderer.py: load a dedicated 5x7 head/body font for the weather view (sized to panel height) and use it in all weather render helpers; other views are unchanged. - Bundle assets/fonts/5by7.regular.ttf in the plugin so the face resolves on-device (the core repo ships PressStart2P/4x6, not 5x7 — the other plugins that use 5x7 bundle their own copy too). - manifest bumped 1.11.0 -> 1.11.1; registry synced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ka1E5TT1Ai9cuKV9j7g4C
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@plugins/ledmatrix-flights/manager.py`:
- Around line 2324-2353: The METAR refresh path in `_refresh_metar_data()` is
still doing blocking network work inside `update()`, which can stall the
aircraft loop when cache entries expire or requests slow down. Refactor this
flow so the weather fetch is decoupled from the main update path—either move the
full refresh into a background worker/thread or split the per-airport
PIREP/SIGMET work across multiple cycles using the same kind of incremental
pattern used by `_background_fetch_fr24_details`. Keep `update()` limited to
scheduling work, and preserve the existing `_last_metar_fetch`,
`metar_update_interval`, and `self.metar_enabled` gating logic.
- Around line 312-323: FlightTrackerPlugin.__init__ currently calls
_apply_metar_config() unguarded, so a bad METAR setup can abort plugin
construction. Wrap that initialization in the same try/except pattern used by
on_config_change(), and on failure log the exception and leave the METAR feature
disabled while allowing the rest of the plugin to continue starting. Keep the
fix localized around _apply_metar_config and the METAR state fields initialized
in __init__.
In `@plugins/ledmatrix-flights/metar_fetcher.py`:
- Around line 41-57: Guard the `int()` conversion for `pirep_distance_nm` in
`MetarFetcher.__init__` the same way `update_interval_minutes` is handled, so a
malformed config value cannot raise during plugin setup. Wrap the cast in
`try/except (TypeError, ValueError)` with a safe default, and keep the fallback
behavior local to `MetarFetcher` since it is constructed unguarded from
`FlightTrackerPlugin.__init__` via `_apply_metar_config()`.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f77cc477-ce20-40d5-aae4-24171771cffc
⛔ Files ignored due to path filters (1)
plugins/ledmatrix-flights/assets/fonts/5by7.regular.ttfis excluded by!**/*.ttf
📒 Files selected for processing (8)
plugins.jsonplugins/ledmatrix-flights/README.mdplugins/ledmatrix-flights/config_schema.jsonplugins/ledmatrix-flights/manager.pyplugins/ledmatrix-flights/manifest.jsonplugins/ledmatrix-flights/metar_fetcher.pyplugins/ledmatrix-flights/renderer.pyplugins/ledmatrix-flights/test/test_metar_fetcher.py
Resolves the CodeRabbit review findings on the METAR feature: - Perf: the weather refresh is now serviced incrementally — at most one HTTP request per update() cycle via a small work queue (_service_metar / _build_metar_work / _run_metar_step) — instead of doing METAR+TAF plus a PIREP call per airport plus SIGMET all in one cycle. A slow or failed weather request can no longer stall the aircraft loop for more than a single request. Preserves the _last_metar_fetch / metar_update_interval / enabled + visibility gating. - Robustness: __init__ now guards _apply_metar_config() (like on_config_change already did) via a new _disable_metar() fallback, so a bad weather config only disables the feature instead of aborting plugin construction. on_config_change guards it separately too. - Robustness: guard the pirep_distance_nm int() cast in MetarFetcher so a malformed config value falls back to the default rather than raising during construction (+ regression test). - Docs: add docstrings to the new renderer/fetcher helpers (docstring coverage). manifest bumped 1.11.1 -> 1.11.2; registry synced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ka1E5TT1Ai9cuKV9j7g4C
Two pilot-focused enhancements to the METAR view: - Observation age: the decoded card shows how old the report is (e.g. "14m", "1h48"). When it's stale (older than ~75 min — a likely missed hourly update) the age turns amber with a "!" so old weather is never read as current. Uses the obsTime already in the fetched data; computed at render time, no extra fetch. - Unit options: new metar.altimeter_unit (inhg|hpa), temp_unit (c|f), wind_unit (kt|mph|kmh|ms) and visibility_unit (sm|m|km) let weather display in US (A30.01 / 10SM / kt / degC) or international style (Q1013 / metres / etc.). Canonical values stay inHg/degC/kt/SM; the renderer converts for display, so the fetcher/cache are unchanged. Adds test/test_metar_render.py (unit conversions + age formatting + all panel sizes render). manifest bumped 1.11.2 -> 1.12.0; registry synced; README documents both. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ka1E5TT1Ai9cuKV9j7g4C
The 5x7 weather text looked soft/blurry because the face anti-aliases at every size (and was being drawn smoothed). Draw the weather cards in 1-bit "mono" mode (draw.fontmode = "1") so glyphs snap to the LED grid with no anti-aliasing, and bump the size a little (13/9 on 32px-tall panels, 16/12 on taller) so the small decoded fields and wrapped raw METAR/TAF stay legible. Same bundled 5x7 font, no stretching; other flight-tracker views are untouched. manifest bumped 1.12.0 -> 1.12.1; registry synced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ka1E5TT1Ai9cuKV9j7g4C
Replace the soft, anti-aliased 5x7 TTF with the 6x10 bitmap (.bdf) font from the LEDMatrix font set for the weather cards. FreeType renders a .bdf pixel-exact at its native size (10px), so the METAR/TAF/PIREP/SIGMET text is sharp on the LED grid with no anti-aliasing and no stretching blur. - Bundle assets/fonts/6x10.bdf; drop the now-unused 5by7.regular.ttf. - Load it via the existing font resolver at its fixed pixel size, with a fallback to the existing small font if a Pillow/FreeType build lacks BDF support (so font loading can never crash the plugin). - Use a tight, measured line advance (the 6x10 cell is 10px but the inked glyphs are ~8px) so the decoded card still fits a header + two field rows on a 32px-tall panel; verified crisp and complete at 64x32 / 128x32 / 128x64 / 256x32. Other flight-tracker views are unchanged. manifest 1.12.1 -> 1.12.2; registry synced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ka1E5TT1Ai9cuKV9j7g4C
Resolves conflicts after #173 (phase-1 LICENSE) and #176 (flights airport-weather) landed on main: - ledmatrix-flights/manifest.json: main advanced to 1.12.2 (still MIT). Re-applied the GPL-3.0 license flip on top and bumped to 1.12.3, preserving the weather-feature version history. - plugins.json: regenerated from manifests (deterministic). flights -> 1.12.3, stocks -> 2.3.1 (both GPL-3.0). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F9Saiat9CQmNi3DeDdvacB
Summary
Adds an optional, pilot-focused Airport Weather add-on to the Flight Tracker plugin: a new opt-in
metarrotation view that shows METAR (color-coded decoded card + raw page), TAF, PIREP, and SIGMET/AIRMET for airports you choose, using the free NOAA Aviation Weather Center API (aviationweather.gov) — no API key or account required. Requested by a pilot who wanted the current METAR for an airport of their choice, baked into the existing plugin rather than a standalone one.Type of change
Plugin(s) affected
ledmatrix-flightsRelated issues
N/A
Test plan
The core repo (harness,
BasePlugin, TTF fonts) and theaviationweather.govhost are both unavailable in the CI/dev sandbox, so testing was done with targeted automated checks rather than the boxes below:test/test_metar_fetcher.py, 8/8): METAR normalization (flight category, ceiling from cloud layers, altimeter hPa→inHg with an inHg pass-through guard, present weather), METAR+TAF batching/merge, cache-first + serve-stale on network error, PIREP and SIGMET parsing.test/test_overhead_card.py, 13/13) — unchanged, confirms existing rendering still works after the additions._resolve_metar_airports(IATA→ICAO, dedup, 4-letter passthrough, junk dropped),_view_has_content('metar'), and_build_metar_pagespage ordering/toggles.scripts/check_module_collisions.py) passes;config_schema.jsonandmanifest.jsonvalidate as JSON; registry synced.Not exercised in this environment: live NOAA fetch (host blocked by sandbox egress policy — parsing is unit-tested against the documented AWC response shape), real hardware, and the LEDMatrix emulator.
Required for plugin changes
versioninmanifest.json(1.10.0 → 1.11.0); registry syncedclass_namematches (FlightTrackerPlugin, unchanged)entry_pointmatches (manager.py, unchanged)README.md(new Airport Weather section + config keys)config_schema.jsonupdated — new nestedmetarobject withdefault/description/constraints for every option;metaradded to therotation_viewsenum + labelsupdate_registry.py(plugins.json→ 1.11.0)Notes for reviewer
client_id/client_secretand token management, and are verbose on a small matrix. Left as a documented follow-up.metarview is a rotation slot likemap/stats(runtime-only, not in manifestdisplay_modes); weather fetches on their own slow cadence inupdate()(default 10 min, cached, gated on visibility) so they never slow the aircraft loop;on_config_changerebuilds the fetcher live. New modulemetar_fetcher.pyis plugin-unique and imported at the top ofmanager.py, satisfying the cross-plugin module-collision rule.🤖 Generated with Claude Code
https://claude.ai/code/session_012ka1E5TT1Ai9cuKV9j7g4C
Generated by Claude Code
Summary by CodeRabbit
New Features
Documentation