A real-time aircraft tracking application for Raspberry Pi 3B that projects a live map of aircraft overhead onto your ceiling via an HDMI projector.
Ingests ADS-B transponder data from a USB RTL-SDR dongle (via dump1090) or the free OpenSky Network REST API, filters by a configurable geographic area, and renders aircraft on an interactive Leaflet.js map served from a local Flask web server.
- Live aircraft map with callsign, altitude, speed, heading, and trail
- Two data sources: RTL-SDR via dump1090 (local) or OpenSky Network (API)
- Configuration UI — all settings adjustable via a web browser
- Presentation mode — full-screen dark map with a single keypress (
P) - Ceiling projection — vertical flip and/or 180° rotation for projector alignment
- Offline tile cache — pre-download map tiles for your local area
- Geographic filter — only show aircraft within a configurable radius
| Hardware | |
|---|---|
| Raspberry Pi 3B (or newer) | Runs the Python server |
| RTL-SDR USB dongle | Optional — for live local ADS-B reception |
| HDMI projector | Pointed at ceiling for presentation mode |
| Software | |
|---|---|
| Raspberry Pi OS (Bullseye / Bookworm) | |
| Python 3.9+ | |
| dump1090-fa | Optional — RTL-SDR decoder |
git clone <repo-url> ADSB-Visual-Tracker
cd ADSB-Visual-Tracker
chmod +x setup.sh
sudo ./setup.shThe setup script installs system packages, creates a Python virtualenv, installs a systemd service, and optionally configures Chromium kiosk autostart.
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python main.pyOpen http://localhost:5000 in a browser.
Click ⚙ Config in the header (or press C).
Key settings:
- Location — your latitude, longitude, and radius (km) for aircraft filtering
- Data Source — choose OpenSky (API, no hardware) or dump1090 (RTL-SDR dongle)
- Ceiling Projection — enable flip/rotation to correct for your projector mount
Click Save Settings.
Press P (or click ▶ Present) to enter full-screen dark mode. The map fills the entire screen — aim your projector at the ceiling.
Press P or Esc to exit.
No hardware required. The app queries the OpenSky Network public API every 10 seconds.
- Anonymous access: ~10 requests/minute rate limit
- Create a free account at opensky-network.org for higher limits
- Enter your credentials in the Config panel under Data Source
For live, low-latency local reception:
- Install dump1090-fa (the setup script can do this)
- Plug in your RTL-SDR dongle
- Start dump1090:
sudo systemctl start dump1090-fa - In Config, switch Source to
dump1090 (RTL-SDR) - Set host
localhostand port8080
Pre-download map tiles so the map works without internet:
# Using settings from config.json
python cache_tiles.py --from-config
# Or specify area manually
python cache_tiles.py --lat 40.7128 --lon -74.0060 --radius 150 --theme darkTiles are stored in ~/.adsb-tracker/tiles/ and served by the local Flask server.
In the Config panel → Ceiling Projection section:
| Projector position | Setting |
|---|---|
| Sitting on a table pointing up at the ceiling | Enable Flip vertically |
| Mounted upside-down from the ceiling | Enable Rotate 180° |
| Mounted upside-down AND sideways | Enable both |
| Key | Action |
|---|---|
P |
Toggle presentation mode |
Esc |
Exit presentation mode |
C |
Open/close config panel |
R |
Re-center map on home coordinates |
ADSB-Visual-Tracker/
├── main.py # Entry point
├── cache_tiles.py # Offline tile pre-caching utility
├── config.json # Persistent configuration (auto-created)
├── requirements.txt
├── setup.sh # Raspberry Pi setup script
└── app/
├── config_manager.py # Load/save config.json
├── adsb/
│ ├── aircraft_store.py # Thread-safe in-memory aircraft state
│ ├── dump1090_client.py # RTL-SDR via dump1090 JSON API
│ ├── opensky_client.py # OpenSky Network REST API client
│ └── data_manager.py # Background data polling + WebSocket push
└── web/
├── routes.py # REST API + tile proxy
├── socketio_events.py # WebSocket event handlers
└── static/
├── index.html
├── css/style.css
└── js/
├── main.js # App init, keyboard shortcuts, mode switching
├── map.js # Leaflet map, aircraft markers, trails
├── socket.js # Socket.IO client
└── config_panel.js # Config form UI
sudo systemctl status adsb-tracker # Check status
sudo systemctl restart adsb-tracker # Restart after config changes
sudo journalctl -u adsb-tracker -f # Live logsAll settings are in config.json (or the Config panel UI):
{
"location": {
"latitude": 40.7128,
"longitude": -74.0060,
"radius_km": 150
},
"data_source": {
"type": "opensky",
"dump1090_host": "localhost",
"dump1090_port": 8080,
"opensky_username": "",
"opensky_password": "",
"poll_interval_seconds": 10
},
"display": {
"theme": "dark",
"show_trails": true,
"trail_length": 10,
"show_labels": true,
"label_fields": ["callsign", "altitude", "speed"],
"ceiling_flip_vertical": false,
"ceiling_rotate_180": false,
"zoom_level": 9
},
"filters": {
"min_altitude_ft": 0,
"max_altitude_ft": 60000,
"show_ground_vehicles": false
}
}MIT