Skip to main content

Python library for ADS-B decoding and REST API using pyModeS

Project description

ADS-B Decoder and REST API

License: GPL v3 Python 3.12+ PyPI version CI Publish

ADS-B decoder and REST API server using pyModeS for decoding Mode-S and ADS-B messages. Mirrors the jet1090 REST API interface with a Python-based implementation, plus a built-in interactive map.

Map interface demo

Quickstart

The published wheel bundles the React UI; FastAPI serves the API and map on a single port. You only need Python — no Node, no bun, no Docker.

pip install adsb-map
adsb download                                # one-time: aircraft database

# Free Mapbox token: https://account.mapbox.com/access-tokens/
# Either export it in your shell, or drop it in a `.env` file in the directory
# you run `adsb serve` from (template: see .env.example in the repo).
export MAPBOX_TOKEN=pk.your_token_here

adsb serve --source net --connect localhost 30005 beast --lat 40.7 --lon -74.0

Visit http://localhost:8000/. Aircraft show up as markers; click one for its track.

Features

  • pyModeS decoding — DF4/5/17/18/20/21 message types with CPR position decoding
  • Aircraft enrichment — automatic registration / type / description lookup from the tar1090-db project (566k+ records)
  • REST API — FastAPI endpoints under /api/*, jet1090-compatible
  • SQLite storage — aircraft state, position history, reception metadata
  • Interactive map — React + Mapbox GL, served same-origin from the wheel
  • Network data sources — connects to dump1090 / readsb / modesdeco2 over TCP (Beast or raw)

Configuration

Setting Default How to override
Mapbox token (required for map UI) MAPBOX_TOKEN env var, or .env file in CWD
Bind host 0.0.0.0 adsb serve --host
Bind port 8000 adsb serve --port
Database path ./adsb.db adsb serve --db-path
Stale timeout 60s adsb serve --stale-timeout
Receiver lat/lon (none) adsb serve --lat --lon (recommended)

--lat and --lon are strongly recommended: ADS-B position messages use Compact Position Reporting (CPR), which decodes faster and more accurately when given a reference position within ~180 NM of the receiver.

CLI

adsb serve       # API + bundled map UI
adsb download     # download tar1090-db aircraft database
adsb init-db      # create SQLite tables
adsb decode HEX   # decode a single message and store it
adsb cleanup      # remove aircraft not seen in --stale-timeout
adsb db-size      # show DB file size and row counts

Pass --help to any command for the full set of options.

API endpoints

All JSON endpoints live under /api/. The map UI is served at /.

Endpoint Returns
GET /api/all All current aircraft state vectors
GET /api/icao24 List of ICAO24 addresses currently tracked
GET /api/track?icao24={icao24}&since={ts} Trajectory for one aircraft
GET /api/sensors Receiver/sensor info (serials)
GET /api API discovery (welcome JSON)
GET / Bundled map UI
GET /config.js Runtime config shim (exposes MAPBOX_TOKEN to the SPA)

The REST API is self-contained — you can ignore the bundled UI and build your own client (mobile, monitoring system, dashboard, etc.) against /api/*.

Network data sources

The decoder connects to existing ADS-B receivers via TCP:

  • dump1090 — port 30005 (Beast), 30002 (raw)
  • readsb — same ports as dump1090
  • modesdeco2, or any Beast / raw hex feed
adsb serve --source net --connect <host> <port> <beast|raw> --lat <lat> --lon <lon>

The network client runs in a background thread, decodes messages, updates the database, and prunes stale aircraft every 30 seconds.

Develop from source

The repo uses just to run backend and frontend together with hot reload. Install uv, bun, and just, then:

git clone https://github.com/jbencina/adsb-map.git
cd adsb-map
uv sync --dev
uv run adsb download                          # one-time

cp frontend/.env.example frontend/.env        # then set VITE_MAPBOX_TOKEN

# Args after `dev` are passed straight through to `adsb serve`.
just dev --source net --connect localhost 30005 beast --lat 40.7 --lon -74.0

Visit http://localhost:3000/. Vite proxies /api/* and /config.js to the backend on port 8000, so the frontend hits the API as if it were same-origin.

To exercise the production-style single-process bundle locally:

just build                                                # frontend → adsb/static/
MAPBOX_TOKEN=pk.… just serve --source net --connect localhost 30005 beast --lat 40.7 --lon -74.0
# Visit http://localhost:8000/

Tests, linting, formatting

uv run pytest                                 # full test suite
uv run pytest --cov=adsb --cov-report=term-missing
uv run tox                                    # multi-version (3.12, 3.13)

uv run ruff check .                           # lint
uv run ruff format .                          # format
uv run pre-commit install                     # one-time: enable git hooks
uv run pre-commit run --all-files

Frontend: bun run lint, bun run format from frontend/.

Verify the wheel ships the bundled frontend (run before merging changes that touch packaging, the static mount, or the publish workflow):

just build && uv build
unzip -l dist/adsb_map-*.whl | grep adsb/static/
# Expected: index.html + assets/*.js + assets/*.css

Architecture

Backend (adsb/)

Module Responsibility
decoder.py pyModeS-based message decoding, CPR positions, DB enrichment
network.py ADSBNetworkClient — daemon thread reading from dump1090/readsb
api.py FastAPI app — /api/* JSON, bundled SPA at /, runtime /config.js
models.py SQLAlchemy ORM: Aircraft, AircraftPosition, AircraftMetadata
database.py Session/engine management with context-manager pattern
schemas.py Pydantic response models
aircraft_db.py Lazy-loaded singleton CSV (566k+ rows) → registration/type lookup
cli.py Click CLI: serve, download, init-db, decode, cleanup, db-size
static/ Built frontend assets (populated by just build or CI; gitignored)

Frontend (frontend/src/) — React 18 + Vite, compiled and bundled into the wheel during release. End users never need a JS toolchain.

Release flow

CI (.github/workflows/publish.yml) handles all of this on a v* tag push:

  1. bun install && bun run build produces frontend/dist/
  2. frontend/dist/ is staged into adsb/static/
  3. uv build packages the wheel — adsb/static/** is included via the artifacts declaration in pyproject.toml
  4. uv publish --trusted-publishing always ships to PyPI via OIDC (no API tokens stored)

The Mapbox token is not baked into the wheel. At runtime, the server exposes /config.js which reads MAPBOX_TOKEN from its environment (process env, or a .env file in CWD via python-dotenv) and writes window.APP_CONFIG for the SPA. One wheel works for any user — no rebuild per token.

Database schema

Table Purpose
aircraft Current state per aircraft (position, velocity, ID, telemetry, registration/type)
aircraft_positions Historical positions for trajectory rendering
aircraft_metadata Reception metadata (timing, RSSI, receiver serial)

See data/README.md for notes on the aircraft database file.

License

GNU General Public License v3.0 or later (GPL-3.0-or-later). See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

adsb_map-0.2.0.tar.gz (590.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

adsb_map-0.2.0-py3-none-any.whl (587.8 kB view details)

Uploaded Python 3

File details

Details for the file adsb_map-0.2.0.tar.gz.

File metadata

  • Download URL: adsb_map-0.2.0.tar.gz
  • Upload date:
  • Size: 590.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for adsb_map-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f49b4d6bb93cca005ff7c575e81fbe686c536e9ceb98de1a34e765f214416bcd
MD5 743dee38170a12529edd42b2179ba09b
BLAKE2b-256 b8a8ff250244ab9f1e0c3cabe65762dc848381bf362caaf6499273491a863b2f

See more details on using hashes here.

File details

Details for the file adsb_map-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: adsb_map-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 587.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for adsb_map-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 af13e4c437fce5c15129e5b6f0d0d1525daa9ae3874c34059ded252846d0f828
MD5 68bade82ee4613b8df0ee073b1a3bc00
BLAKE2b-256 87b3cb8cb431cfd3b2eb09e1a4541930ee5652b2f4aa857525d4229175cf0da0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page