diff --git a/.gitignore b/.gitignore index 63e9435..5374ac8 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ wheels/ # Auto-generated by RGBMatrixEmulator at runtime emulator_config.json + +# Environment / secrets +.env diff --git a/CONTEXT.md b/CONTEXT.md index 48250f6..b88862d 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -16,9 +16,22 @@ Per-flight card visible on the matrix: - **Flight Number** (e.g., "2337") - **Route** (origin → destination airport codes, e.g., "SFO → LAX") - **Aircraft Type** (e.g., "B738") -- **Metrics**: Altitude (ft), Speed (knots), Track/heading (°), Vertical Rate (ft/min) +- **Metrics**: Altitude (ft), Speed (knots), Track (°), Vertical Rate (ft/min) - **Airline Logo** (optional): Small icon downsampled from airline-logos database +## Track vs Heading + +- **Track**: The aircraft's actual path over the ground, measured in compass degrees. Affected by wind — differs from heading when there's a crosswind. +- **Heading**: The direction the aircraft's nose is pointing. AeroAPI returns heading, not track — stored in the `track` field as an approximation. + +## Flight Data Fields + +- **altitude**: Current altitude in feet. +- **speed**: Current ground speed in knots. +- **track**: Ground track in degrees (see Track vs Heading above). +- **vertical_rate**: Rate of climb or descent in feet per minute. Positive = climbing, negative = descending. +- **callsign**: The flight identifier broadcast by the aircraft (e.g., "UAL2337"). + ## Display Layout (64 columns × 32 rows) ``` diff --git a/Makefile b/Makefile index 923673a..c586897 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,16 @@ -.PHONY: run test lint +.PHONY: run debug test lint fixtures run: ## Run the emulator smoke test uv run python -m jetset +debug: ## Run with debug logging + JETSET_DEBUG=1 uv run python -m jetset + test: ## Run all tests uv run pytest -v lint: ## Lint and format check uv run ruff check src/ + +fixtures: ## Save live AeroAPI response as test fixture + uv run python scripts/save_fixtures.py diff --git a/docs/features/20250610-2316-nearby-flights/prd.html b/docs/features/20250610-2316-nearby-flights/prd.html new file mode 100644 index 0000000..ef72497 --- /dev/null +++ b/docs/features/20250610-2316-nearby-flights/prd.html @@ -0,0 +1,331 @@ + + +
+ + ++ I want to see live aircraft flying near my home displayed on a 64×32 LED matrix panel. + The display should feel like a miniature airport departure board — cycling through nearby + flights with their airline, flight number, route, altitude, and speed. When no flights are + nearby, I still want to see recent flights that passed through. +
++ A Python application that periodically fetches nearby aircraft from a flight tracking API, + renders each flight as a card on the LED matrix, and cycles through them. The display + uses a dot-matrix aesthetic with Departure Mono to match the departure-board feel. + The flight data source is swappable via an abstract interface — the first adapter targets + the OpenSky Network's free REST API. +
+Protocol with a single method: fetch_nearby(lat, lon, range_mi) → list[Flight]. The main loop receives the configured adapter via dependency injection — no direct imports of concrete adapters.
Uses the states/all REST endpoint with bounding-box parameters. State vectors are parsed into Flight objects. Flights below 1,000 ft are filtered. Callsign parsing extracts airline codes via prefix matching. Errors return an empty list — the display never crashes from a fetch failure.
Immutable dataclass with fields for airline, flight number, route, aircraft type, altitude, speed, track, vertical rate, and callsign. Display helpers derive formatted strings. FlightBuffer is a fixed-size ring buffer (default 5) with callsign deduplication.
The Departure Mono font (OTF) is rendered via Pillow at the appropriate pixel size, then blitted pixel-by-pixel onto the matrix canvas. This avoids BDF conversion and works identically on emulator and real hardware. Flight card layout uses orange, cyan, dim white, and green for visual hierarchy. Airline logo is displayed in the top-right corner.
+Sourced from github.com/sexym0nk3y/airline-logos (993 PNGs, 90×90 each, indexed by ICAO airline code). A setup script downloads and caches them locally. Each logo is downscaled to ~20×16 px and blitted into the top-right corner of the flight card. Missing logos are silently skipped.
+Matrix creation tries RGBMatrixEmulator first, then rgbmatrix. Same code runs on emulator and Pi with zero changes.
Single config.yaml with sections for home (lat, lon, range_mi), display (cols, rows, cycle_sec, refresh_sec), and api (source, credentials). Loaded into a frozen dataclass at startup.
When no flights are in range, display recent flights from the history buffer. If buffer is empty (first run), show a static "NO DATA" message.
++ Renderer and display testing is deferred — they require the emulator or hardware. +
+