- 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)
147 lines
4.1 KiB
Python
147 lines
4.1 KiB
Python
"""Take screenshots of all TUI screens in demo mode for documentation.
|
|
|
|
Generates SVG snapshots of every screen and sub-mode including overlays.
|
|
All data comes from DemoDevice and DemoCraftClient — no hardware or
|
|
network required.
|
|
|
|
Usage:
|
|
cd tui && uv run python scripts/take_screenshots.py
|
|
"""
|
|
|
|
import asyncio
|
|
|
|
from birdcage_tui.app import BirdcageApp
|
|
from birdcage_tui.screens.control import ControlScreen
|
|
from birdcage_tui.widgets.craft_panel import CraftPanel
|
|
|
|
OUT_DIR = "/home/rpm/claude/ham/satellite/winegard-travler/site/public/screenshots"
|
|
|
|
|
|
async def _screenshot_basic_tabs():
|
|
"""F1 Dashboard, F2 Control (manual), F3 Signal, F4 System."""
|
|
tabs = {
|
|
"f1": "dashboard",
|
|
"f2": "control",
|
|
"f3": "signal",
|
|
"f4": "system",
|
|
}
|
|
for key, name in tabs.items():
|
|
app = BirdcageApp()
|
|
app.demo_mode = True
|
|
|
|
async with app.run_test(size=(120, 40)) as pilot:
|
|
await pilot.pause()
|
|
await pilot.press(key)
|
|
await pilot.pause()
|
|
await asyncio.sleep(1.5)
|
|
|
|
path = f"{OUT_DIR}/tui-{name}.svg"
|
|
app.save_screenshot(path)
|
|
print(f"Saved {path}")
|
|
|
|
|
|
async def _screenshot_craft_search():
|
|
"""F2 Control > Craft sub-mode with search results."""
|
|
app = BirdcageApp()
|
|
app.demo_mode = True
|
|
|
|
async with app.run_test(size=(120, 40)) as pilot:
|
|
await pilot.pause()
|
|
await pilot.press("f2")
|
|
await pilot.pause()
|
|
|
|
control = app.query_one("#control", ControlScreen)
|
|
control.switch_mode("craft")
|
|
await pilot.pause()
|
|
|
|
# Trigger a search — uses DemoCraftClient
|
|
panel = app.query_one("#ctrl-craft-panel", CraftPanel)
|
|
panel.post_message(CraftPanel.SearchRequested(""))
|
|
await asyncio.sleep(1.0)
|
|
|
|
path = f"{OUT_DIR}/tui-craft-search.svg"
|
|
app.save_screenshot(path)
|
|
print(f"Saved {path}")
|
|
|
|
|
|
async def _screenshot_craft_tracking():
|
|
"""F2 Control > Craft sub-mode actively tracking the Moon."""
|
|
app = BirdcageApp()
|
|
app.demo_mode = True
|
|
|
|
async with app.run_test(size=(120, 40)) as pilot:
|
|
await pilot.pause()
|
|
await pilot.press("f2")
|
|
await pilot.pause()
|
|
|
|
control = app.query_one("#control", ControlScreen)
|
|
control.switch_mode("craft")
|
|
await pilot.pause()
|
|
|
|
# Start tracking the Moon (always above horizon in demo)
|
|
panel = app.query_one("#ctrl-craft-panel", CraftPanel)
|
|
panel.post_message(
|
|
CraftPanel.TrackRequested(
|
|
target_type="celestial",
|
|
target_id="moon",
|
|
name="Moon",
|
|
min_el=5.0,
|
|
)
|
|
)
|
|
await asyncio.sleep(2.5)
|
|
|
|
path = f"{OUT_DIR}/tui-craft-tracking.svg"
|
|
app.save_screenshot(path)
|
|
print(f"Saved {path}")
|
|
|
|
control._stop_craft_tracking()
|
|
await pilot.pause()
|
|
|
|
|
|
async def _screenshot_console():
|
|
"""F5 Console overlay."""
|
|
app = BirdcageApp()
|
|
app.demo_mode = True
|
|
|
|
async with app.run_test(size=(120, 40)) as pilot:
|
|
await pilot.pause()
|
|
await asyncio.sleep(1.0)
|
|
|
|
await pilot.press("f5")
|
|
await pilot.pause()
|
|
await asyncio.sleep(0.5)
|
|
|
|
path = f"{OUT_DIR}/tui-console.svg"
|
|
app.save_screenshot(path)
|
|
print(f"Saved {path}")
|
|
|
|
|
|
async def _screenshot_camera():
|
|
"""F6 Camera overlay."""
|
|
app = BirdcageApp()
|
|
app.demo_mode = True
|
|
|
|
async with app.run_test(size=(120, 40)) as pilot:
|
|
await pilot.pause()
|
|
await asyncio.sleep(1.0)
|
|
|
|
await pilot.press("f6")
|
|
await pilot.pause()
|
|
await asyncio.sleep(0.5)
|
|
|
|
path = f"{OUT_DIR}/tui-camera.svg"
|
|
app.save_screenshot(path)
|
|
print(f"Saved {path}")
|
|
|
|
|
|
async def main():
|
|
await _screenshot_basic_tabs()
|
|
await _screenshot_craft_search()
|
|
await _screenshot_craft_tracking()
|
|
await _screenshot_console()
|
|
await _screenshot_camera()
|
|
print(f"\nAll screenshots saved to {OUT_DIR}/")
|
|
|
|
|
|
asyncio.run(main())
|