Add DemoCraftClient for complete offline demo mode

- DemoCraftClient in demo.py: duck-typed CraftClient replacement with
  8 canned satellites, synthetic pass predictions, and time-varying LEO
  arcs that drive real AOS/TCA/LOS pass events to the camera overlay
- Fix sky map EL signal fidelity: snap _el to _target_el at sweep start
  so 2D scans compute correct per-row RSSI (was using stale elevation)
- Branch on demo_mode in app.py _setup_craft_client() to inject
  DemoCraftClient instead of the HTTP CraftClient
- Add test_demo_craft.py: 5 tests exercising search, passes, tracking,
  and WAITING state through the full TUI without mocks
- Update take_screenshots.py to cover all 8 screens (dashboard, control,
  craft search, craft tracking, signal, system, console, camera)
This commit is contained in:
Ryan Malloy 2026-02-16 11:49:39 -07:00
parent 7035d814a1
commit 3013eeee4c
4 changed files with 518 additions and 13 deletions

View file

@ -141,9 +141,14 @@ class BirdcageApp(App):
def _setup_craft_client(self) -> None:
"""Create a Craft API client and hand it to the control screen."""
from birdcage_tui.craft_client import CraftClient
if self.demo_mode:
from birdcage_tui.demo import DemoCraftClient
client = CraftClient(base_url=self.craft_url)
client = DemoCraftClient()
else:
from birdcage_tui.craft_client import CraftClient
client = CraftClient(base_url=self.craft_url)
try:
control = self.query_one("#control")
if hasattr(control, "set_craft_client"):