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:
parent
7035d814a1
commit
3013eeee4c
4 changed files with 518 additions and 13 deletions
|
|
@ -1,21 +1,31 @@
|
|||
"""Take screenshots of all TUI screens in demo mode for documentation."""
|
||||
"""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
|
||||
|
||||
SCREENS = {
|
||||
"f1": "dashboard",
|
||||
"f2": "control",
|
||||
"f3": "signal",
|
||||
"f4": "system",
|
||||
}
|
||||
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 main():
|
||||
for key, name in SCREENS.items():
|
||||
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
|
||||
|
||||
|
|
@ -23,7 +33,6 @@ async def main():
|
|||
await pilot.pause()
|
||||
await pilot.press(key)
|
||||
await pilot.pause()
|
||||
# Let workers populate data.
|
||||
await asyncio.sleep(1.5)
|
||||
|
||||
path = f"{OUT_DIR}/tui-{name}.svg"
|
||||
|
|
@ -31,4 +40,107 @@ async def main():
|
|||
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())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue