--- title: "The Birdcage TUI" description: A six-screen terminal interface for controlling Winegard satellite dishes — from a $75 RV salvage find to something that looks like it belongs in a ground station. sidebar: order: 8 badge: text: New variant: tip --- import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; Mission control for less than dinner for two. ![Birdcage TUI — all screens shown in demo mode](/screenshots/tui-collage.png) Somewhere inside every Winegard Carryout G2 is a 2013-vintage NXP Cortex-M4 running firmware 02.02.48, driving two Allegro A3981 stepper motors and a Broadcom BCM4515 DVB-S2 tuner through 12 submenus and over 100 undocumented commands. In 2026, it takes commands from a Python TUI built on [Textual](https://textual.textualize.io/) and doesn't seem to mind. Gabe Emerson ([KL1FI](https://github.com/saveitforparts)) went first — publishing control scripts for five different Winegard variants, proving that a $50–200 RV salvage yard dish could replace a $500–2000 commercial amateur radio rotator. Chris Davidson ([cdavidson0522](https://github.com/cdavidson0522/winegard-sky-scan)) figured out the G2's RS-422 wiring and discovered `azscanwxp` — the firmware's built-in radio telescope mode. Birdcage is what happens when you take all of that and give it a proper interface. ## Quick Start ```bash # Demo mode — no hardware, no clone, no install uvx birdcage-tui --demo # With camera capture support (Pillow + astropy) uvx --with 'birdcage-tui[camera]' birdcage-tui --demo # Connect to a real dish uvx birdcage-tui --port /dev/ttyUSB0 --firmware g2 ``` ```bash # Clone and install cd tui/ uv sync # Demo mode uv run birdcage-tui --demo # Connect to a real dish uv run birdcage-tui --port /dev/ttyUSB0 --firmware g2 ``` ### Extras The base install includes everything except image processing. Optional extras add camera capabilities: | Extra | Install | What it adds | |-------|---------|-------------| | *(base)* | `uvx birdcage-tui` | Full TUI, all 6 screens, demo mode | | `camera` | `uvx --with 'birdcage-tui[camera]' birdcage-tui` | JPEG annotation (Pillow) + FITS export for radio astronomy (astropy) | The camera screen (F6) works without the `camera` extra — it falls back to minimal JPEG output. The extra adds annotated frames and FITS file export for integration with DS9, CASA, and other astronomy tools. ## Six Screens Navigate between screens with **F1**–**F4** keys, plus **F5** and **F6** overlays. Click the tab bar at the top or use the hotkeys. The device status bar at the bottom persists across all screens — connection state, serial port, firmware version, and current menu prompt are always visible. ### F1 — Dashboard ![Birdcage TUI Dashboard screen showing action cards for dish operations](/screenshots/tui-dashboard.png) The launch pad. Four action cards — **Point Dish**, **Monitor Signal**, **Scan Sky**, and **Stow** — each jump to the relevant screen with a single click. It's the screen you see on connect, and the one you come back to when you're done adjusting. ### F2 — Control ![Birdcage TUI Control screen showing compass rose, step size selector, and manual controls](/screenshots/tui-control.png) Where you actually point the dish. Four modes across the top: **Manual**, **Presets**, **Track**, and **Craft**. Track mode starts a rotctld server on port 4533 so external controllers — [Gpredict](/guides/satellite-tracking/#configuring-gpredict) or a remote [Craft](https://space.warehack.ing) instance — can drive the dish with live satellite tracking. Craft mode talks to the [space.warehack.ing](https://space.warehack.ing) API directly — no rotctld needed. In Manual mode, a compass rose shows current azimuth with a bearing indicator. AZ and EL readouts update live — the G2's stepper resolution is 0.009° azimuth (40,000 steps/rev) and 0.014° elevation (24,960 steps/rev). Arrow keys nudge the dish, with a step size selector (0.1° to 10°) that multiplies each keypress. AZ and EL sparklines give immediate visual feedback: flat lines mean the dish is parked, slopes mean it's slewing, and the noise floor after arrival tells you how much stepper backlash you're dealing with. Below the sparklines, velocity controls let you tune motor speed on the fly — set AZ and EL max velocity in °/s and hit Apply. The firmware stores these in STEP> as microsteps/sec, but the TUI handles the conversion. Home AZ, Home EL, and E/R (engage/release motors) round out the bottom toolbar. #### Craft Mode ![Birdcage TUI Craft mode showing search results for satellites and celestial bodies](/screenshots/tui-craft-search.png) Craft mode connects directly to the [space.warehack.ing](https://space.warehack.ing) API for satellite and celestial body tracking — no rotctld server, no external controller. Type a name in the search bar and the catalog returns matches with NORAD ID, type, and group. Select a target from the results table, then hit **Track** to start following it at 1 Hz. ![Birdcage TUI Craft mode tracking the Moon at AZ 145.00° EL 32.01°](/screenshots/tui-craft-tracking.png) The status panel shows the tracking lifecycle: **IDLE** (nothing selected), **TRACKING** (target above minimum elevation, dish is moving), or **WAITING** (target below the minimum elevation floor — the dish holds position until the target rises). Sat AZ and Sat EL update each second with the target's computed position. The **Passes** button fetches upcoming pass predictions for LEO targets — rise time, peak elevation, and duration. Pass state transitions (WAITING → TRACKING at AOS, TRACKING → WAITING at LOS) feed into the Camera overlay's automatic trigger system, so you can capture images at acquisition of signal, closest approach, or loss of signal without manual intervention. ### F3 — Signal ![Birdcage TUI Signal screen showing RSSI gauge, DVB and ADC sparklines](/screenshots/tui-signal.png) Signal strength from two sources: the BCM4515 DVB tuner's RSSI (bounded, averaged) and the raw ADC reading (single-shot). Three modes: **Monitor** (live gauges), **Sweep** (automated peaking), and **Sky Map** (2D RSSI heatmap from `azscanwxp` scans). In Monitor mode, the gauge uses sub-character Unicode block elements (▏▎▍▌▋▊▉█) for smooth visual resolution. The Receiver panel alongside shows tuner frequency, symbol rate, LNB voltage/polarity, lock status, and SNR. On a live dish with the LNA enabled (`lnbdc odu`), the noise floor sits around RSSI 500 (ADC) or 230–490 (DVB, polarity-dependent). ### F4 — System ![Birdcage TUI System screen showing firmware ID, A3981 diagnostics, and motor dynamics](/screenshots/tui-system.png) The system dashboard with three tabs: **Hardware**, **Motors**, and **NVS Config**. The Hardware tab shows the firmware identity banner — version 02.02.48, K60 MCU at 96 MHz, antenna ID "12-IN G2" — and A3981 stepper driver diagnostics: fault pin status for both drivers (AZ/EL DIAG: OK or FAULT), step size mode (AUTO means the driver handles microstepping transitions automatically), and current control mode. The NVS Config tab provides a scrollable browser of all 134 non-volatile storage values. Current, saved, and default columns let you see what's been modified. Refresh and Export buttons at the bottom do what you'd expect. ### F5 — Console ![Birdcage TUI Console screen showing firmware console with command prompt](/screenshots/tui-console.png) Raw firmware console access with guardrails. Type commands directly to the dish's serial interface, see responses with color-coded prompt tracking (`TRK>`, `MOT>`, `DVB>`, `NVS>`, etc.). Command history with up/down arrows. The safety gates matter here: the console warns before sending `q` at root level (which kills the firmware shell — requires power cycle to recover), before `reboot`, and before NVS writes. The firmware doesn't have an "are you sure?" prompt. Birdcage does. ### F6 — Camera ![Birdcage TUI Camera overlay showing capture status, output format, and pass-event trigger buttons](/screenshots/tui-camera.png) A modal overlay for image capture during satellite passes. Toggle it with **F6** or dismiss with **Escape** — it floats over whichever screen you're on. Three trigger modes: - **Manual** — press **c** to capture a single frame on demand - **Interval** — set a timer and capture automatically at a fixed cadence - **Pass events** — fire on AOS (acquisition of signal), TCA (time of closest approach), or LOS (loss of signal) transitions from the Craft or Track tracking loops Each capture produces a JPEG frame paired with a JSON sidecar containing dish position, target name, timestamp, trigger type, and tracking state at the moment of capture. The status bar at the top of the overlay shows the active camera, capture count, last capture time, output formats, and which triggers are armed. ## Demo Mode Pass `--demo` and Birdcage substitutes a `DemoDevice` for the serial bridge. The simulator models: - **Motor physics** — position changes at ~10°/s with configurable settling noise (±0.05° random perturbation to simulate stepper backlash) - **RSSI signal** — Gaussian model centered on a target position, so signal strength increases as you point closer to the simulated source - **All 12 submenus** — `TRK>`, `MOT>`, `DVB>`, `NVS>`, `A3981>`, `ADC>`, `OS>`, `STEP>`, `PEAK>`, `EE>`, `GPIO>`, `LATLON>`, `DIPSWITCH>`. Menu navigation with `mot`, `dvb`, `nvs`, etc. and `q` to go back all work correctly - **Full NVS dump** — the complete 134-entry table from firmware 02.02.48, captured from a live unit on 2026-02-12 - **Satellite catalog** — 8 canned objects (ISS, NOAA 19, SO-50, TEVEL-2, AO-91, Moon, Sun, Jupiter) with time-varying LEO arcs that cycle through AOS → TCA → LOS transitions on ~10-minute periods. Camera pass-event triggers fire on these transitions. Every screen, every widget, every button works in demo mode. It's the same code path — the only difference is what's on the other end of the bridge. ## The Story The hardware was never the hard part. RV satellite dishes show up at salvage yards for $50–200 because the RV got totaled or the owner switched to Starlink. The mechanicals are built to survive highway speeds and hailstorms. The motors are Allegro A3981 stepper drivers with 1/16 microstepping — more precise than most amateur radio rotators at ten times the price. The gap was always software. Gabe Emerson (KL1FI) bridged it first. Five repositories for five Winegard variants — the Trav'ler (HAL 0.0.00 and HAL 2.05), the Trav'ler Pro, the original Carryout, and the Carryout G2. Python scripts that send `a 0 180` to point azimuth south and `a 1 45` to tilt elevation to 45°. A rotctld bridge so Gpredict could drive the dish. Proof that the idea worked. Chris Davidson took the G2 further — mapped the RS-422 wiring (four wires, not two, and polarity matters or you get garbled data at the correct baud rate), discovered the `azscanwxp` command buried in the motor submenu, and turned a TV satellite dish into an RF imager. Birdcage picks up where they left off. We reverse-engineered over 100 commands across 12 firmware submenus using automated probing and interactive exploration. We documented the full NVS table (134 entries), the GPIO pin map, the SPI bus layout (4 MHz to the motor drivers, 6.857 MHz to the DVB tuner), the DiSEqC 2.x interface, and the boot sequence from bootloader through motor calibration to prompt. The TUI is what ties it together. Not because a terminal interface is fashionable, but because when you're on a roof with a laptop and a USB-to-RS422 adapter, you want something that runs over SSH and shows you everything at once. A 2013 microcontroller. A 2026 terminal. A dish that costs less than the cable to connect it. That's the project.