A lightweight Go service that monitors aircraft in a configurable radius around your location using the adsb.fi public API. Features a terminal UI (TUI) for live aircraft tracking, with headless mode for containerised deployment.
✈️ Real-time aircraft monitoring using adsb.fi API- 🖥️ Terminal UI with live-updating aircraft table (Bubble Tea)
- 📍 Configurable monitoring radius and location
- 🔍 Filter by aircraft model with glob pattern support (e.g.,
A380,B74*,A3??) - 🛬 Closest Point of Approach (CPA) and ETA estimation
- 🧭 Compass bearing in alert notifications
- 🗺️ Flight route lookup via adsbdb (e.g., MEL → BNE)
- 🔔 Notifications via webhook or Pushover
- 📊 Prometheus metrics
- 🐳 Docker Compose and Kubernetes deployment
- 🔧 Configuration via environment variables or YAML
# Install dev tools (Air for hot-reload)
make tools
# Configure
cp .env.example .env
# Edit .env with your location and aircraft types
# Run with hot-reload
make dev
# Or build and run
make run| Key | Action |
|---|---|
tab |
Toggle between watched aircraft and all aircraft |
↑/↓ |
Scroll through aircraft list |
q / ctrl+c |
Quit |
In the "All Aircraft" view, watched aircraft are marked with ◆ and military aircraft with ★.
When no TTY is available (Docker, Kubernetes), the app runs in headless mode with logs to stdout.
| Target | Description |
|---|---|
make build |
Tidy modules and compile |
make run |
Build and run with .env loaded |
make dev |
Hot-reload dev mode via Air |
make tools |
Install dev tools (Air) |
make clean |
Remove build artifacts |
make docker-build |
Build Docker image |
make docker-up |
Build and start via Docker Compose |
make docker-down |
Stop Docker Compose |
make k8s-apply |
Deploy via kustomize |
make k8s-delete |
Tear down kustomize resources |
Configuration can be provided via environment variables (highest priority), YAML file (config.yaml), or defaults.
| Variable | Required | Default | Description |
|---|---|---|---|
LATITUDE |
Yes | - | Decimal latitude of monitoring location |
LONGITUDE |
Yes | - | Decimal longitude of monitoring location |
RADIUS_NM |
No | 25 | Monitoring radius in nautical miles (1-250) |
AIRCRAFT_MODELS |
Yes | - | Comma-separated aircraft types, supports globs (e.g., A380,B74*,E190) |
POLL_INTERVAL_SECONDS |
No | 30 | How often to poll the API |
ALERT_WEBHOOK_URL |
No | - | Webhook URL for alerts |
PUSHOVER_API_TOKEN |
No | - | Pushover application token |
PUSHOVER_USER_KEY |
No | - | Pushover user key |
DEBUG |
No | false | Enable verbose logging |
HIDE_GROUND |
No | false | Hide grounded aircraft from TUI |
WATCH_MILITARY |
No | false | Alert on all military aircraft (via dbFlags) |
PROMETHEUS_ENABLED |
No | true | Enable Prometheus metrics server |
PROMETHEUS_PORT |
No | 8080 | Prometheus metrics port |
API_BASE_URL |
No | https://opendata.adsb.fi/api | adsb.fi API endpoint |
plane-watcher
├── adsb.fi API ──── poll aircraft by location (rate limited: 1 req/sec)
├── adsbdb API ──── lazy flight route resolution (1 lookup/5sec)
├── TUI ─────────── live aircraft table (Bubble Tea) or headless mode
├── Notifier ────── webhook / Pushover alerts on new sightings
└── Prometheus ──── metrics at :8080/metrics
pkg/api— adsb.fi HTTP clientpkg/config— configuration loading (env + YAML via Viper)pkg/monitor— core monitoring, filtering, CPA/bearing calculationpkg/tui— terminal UI (Bubble Tea + Bubbles table)pkg/routes— flight route resolver (adsbdb)pkg/notifier— webhook and Pushover notificationspkg/voicealert— alert message generationpkg/logger— structured logging (Zap)pkg/metrics— Prometheus metricspkg/ratelimit— leaky token bucket rate limiter
Routes are resolved lazily from adsbdb at 1 request per 5 seconds. Results are cached in memory for the session. Aircraft on the ground with no route will be retried once airborne.
| Status | Display |
|---|---|
| Pending lookup | ... |
| No route found | — |
| Resolved | MEL → BNE |
Alert messages include aircraft description, type code, compass bearing, altitude, and speed:
Aircraft spotted: BOEING 737-800 (B738). Bearing: SSW (202°). Altitude: 3600 ft, Speed: 194 kts.
Pushover takes priority if both Pushover and webhook credentials are configured.
# Start
make docker-up
# Logs
docker compose -f docker/compose.yaml logs -f
# Stop
make docker-downConfiguration via config.yaml (mounted into container) and docker/.env for secrets.
make k8s-applyUses kustomize to generate ConfigMap from config.yaml (mounted at /etc/plane-watcher/) and secrets via secretGenerator. Edit kubernetes/kustomization.yaml to configure.
With a TTY (local dev), logs write to plane-watcher.log to keep the TUI clean. Without a TTY (Docker/Kubernetes), logs go to stdout for docker logs / kubectl logs.
MIT