{"id":49519604,"url":"https://github.com/blindp3w/readsbstats","last_synced_at":"2026-05-30T22:00:38.335Z","repository":{"id":353848989,"uuid":"1221157235","full_name":"blindp3w/readsbstats","owner":"blindp3w","description":"ADS-B flight history \u0026 web UI for readsb","archived":false,"fork":false,"pushed_at":"2026-05-23T23:05:15.000Z","size":37903,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-23T23:23:56.542Z","etag":null,"topics":["ads-b","adsb","aviation","fastapi","flight-tracking","mlat","raspberry-pi","readsb","sqlite","tar1090"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/blindp3w.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-25T20:36:04.000Z","updated_at":"2026-05-23T23:05:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/blindp3w/readsbstats","commit_stats":null,"previous_names":["blindp3w/readsbstats"],"tags_count":55,"template":false,"template_full_name":null,"purl":"pkg:github/blindp3w/readsbstats","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blindp3w%2Freadsbstats","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blindp3w%2Freadsbstats/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blindp3w%2Freadsbstats/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blindp3w%2Freadsbstats/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blindp3w","download_url":"https://codeload.github.com/blindp3w/readsbstats/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blindp3w%2Freadsbstats/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33711018,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-30T02:00:06.278Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ads-b","adsb","aviation","fastapi","flight-tracking","mlat","raspberry-pi","readsb","sqlite","tar1090"],"created_at":"2026-05-01T23:04:19.686Z","updated_at":"2026-05-30T22:00:38.324Z","avatar_url":"https://github.com/blindp3w.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# readsbstats\n\n[![Tests](https://github.com/blindp3w/readsbstats/actions/workflows/test.yml/badge.svg)](https://github.com/blindp3w/readsbstats/actions/workflows/test.yml)\n[![Release](https://img.shields.io/github/v/release/blindp3w/readsbstats)](https://github.com/blindp3w/readsbstats/releases/latest)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\nExtended flight history and track logging for [readsb](https://github.com/wiedehopf/readsb) ADS-B receivers, with a web UI for browsing historical flights and statistics.\n\nDesigned to run alongside readsb, tar1090, and feed clients on a **Raspberry Pi 4** without overwhelming it.\n\nreadsb and tar1090 give you a great live view — readsbstats adds the other half: a persistent SQLite history of every flight, a full-featured browser UI for exploring it, Telegram notifications for military and watchlist aircraft, and a receiver health dashboard backed by months of metrics.\n\n\u003e 🤖 **About this project:** readsbstats was entirely vibecoded with [Claude Code](https://claude.com/claude-code). Every line of code, test, and configuration in this repository was generated by AI under the maintainer's direction — not a single line was written by hand.\n\n## Screenshots\n\n| | |\n|---|---|\n| ![Live map](docs/screenshots/v2/map_v2_2.png) | ![Aircraft gallery](docs/screenshots/v2/gallery_v2_1.png) |\n| Live map — Live / Rewind / HIST modes, bottom command bar, position heatmap, coverage overlay | Gallery — military, interesting, and anonymous (non-ICAO hex) aircraft with photos |\n| ![Statistics](docs/screenshots/v2/statistics_v2_1.png) | ![Flight details](docs/screenshots/v2/flight_details_v2_1.png) |\n| Statistics — summary tiles, hourly activity chart, DOW×hour heatmap, top-N datasets | Flight detail — photo, route, altitude/speed chart, full position log |\n| ![Receiver metrics](docs/screenshots/v2/metrics_v2_2.png) | ![Polar range and top statistics](docs/screenshots/v2/statistics_v2_2.png) |\n| Metrics — 9 health checks (baseline-aware) above 10 time-series charts (ECharts, LTTB) | Statistics — polar coverage range plot and top aircraft types, airlines, routes |\n\n## Features\n\n- Collects aircraft positions every 5 seconds from readsb's `aircraft.json`\n- Groups positions into flights (30-minute silence gap = new flight); tracks ADS-B vs MLAT per position\n- Stores everything in SQLite — no extra database server\n- Aircraft enrichment: registration, type, operator from [tar1090-db](https://github.com/wiedehopf/tar1090-db) (~620k aircraft)\n- Aircraft photos: Planespotters.net → airport-data.com → hexdb.io → Wikipedia type fallback; cached 30 days\n- Military, interesting \u0026 anonymous (non-ICAO hex) aircraft detection, badges, and gallery\n- Route enrichment via [adsbdb.com](https://www.adsbdb.com/) — origin/destination airport per flight\n- Live map with **Live / Rewind / HIST** modes — rewind from \"now\" or jump to any moment within `map_history_hours` via a date+time picker; bottom command bar with playback scrubber, range pills, position heatmap, and coverage range overlay; responsive down to iPhone\n- Telegram notifications for military/interesting/anonymous/watchlist/emergency-squawk events; interactive bot commands\n- Aircraft watchlist — track by ICAO hex, registration, or callsign prefix\n- Receiver metrics dashboard with 10 time-series charts (Apache ECharts canvas, cross-panel hover sync, wheel/pinch zoom, LTTB downsampling) and 9 health checks\n- Optional [DuckDB](https://duckdb.org/) analytical accelerator for heatmap/coverage (`RSBS_USE_DUCKDB=1`)\n- Unit switching: Aeronautical / Metric / Imperial — persisted in browser\n- SQLite crash-safety (`synchronous=FULL` + WAL) with dirty-shutdown detection and weekly/monthly integrity checks via systemd timers\n\n## Requirements\n\n- Raspberry Pi 4 (or any Linux machine) running Ubuntu 22.04 / 24.04\n- [readsb by wiedehopf](https://github.com/wiedehopf/readsb) writing JSON to `/run/readsb/`\n- Python 3.10+\n- nginx (for the `/stats/` reverse proxy)\n\n## Installation\n\n```bash\n# 1. Sync source to the Pi (from your Mac/PC)\nrsync -avz --delete \\\n  --exclude='.git' --exclude='__pycache__' --exclude='*.pyc' \\\n  --exclude='.venv' --exclude='*.egg-info' \\\n  --exclude='docs' --exclude='db' --exclude='.DS_Store' \\\n  --exclude='*.db' --exclude='*.db-wal' --exclude='*.db-shm' \\\n  --exclude='frontend/node_modules' --exclude='frontend/.vite' --exclude='frontend/coverage' \\\n  --exclude='internal_docs' --exclude='.claude' --exclude='CLAUDE.md' \\\n  /path/to/readsbstats/ pi@your-pi:/tmp/readsbstats/\n\n# 2. SSH into the Pi and run the installer as root\nssh pi@your-pi\nsudo bash /tmp/readsbstats/scripts/install.sh\n```\n\nThe installer creates a `readsbstats` system user, sets up `/opt/readsbstats/` with a Python virtualenv, creates the SQLite database, and installs systemd services.\n\nAfter installation, set your receiver coordinates:\n\n```bash\nsystemctl edit readsbstats-collector readsbstats-web\n```\n\n```ini\n[Service]\nEnvironment=\"RSBS_LAT=YOUR_LATITUDE\"\nEnvironment=\"RSBS_LON=YOUR_LONGITUDE\"\n```\n\nThen restart services and open **`http://YOUR_PI_IP/stats/`**.\n\n### nginx setup\n\nAdd one line to your nginx `server {}` block:\n\n```nginx\nserver {\n    include /opt/readsbstats/nginx-readsbstats.conf;\n}\n```\n\nThe conf file proxies `/stats/` to uvicorn at `127.0.0.1:8080` and serves the SPA's hashed asset bundles directly with long-cache headers.\n\n## Resource usage\n\n| Service | CPU quota | Memory limit |\n|---|---|---|\n| collector | 15% | 192 MB |\n| web server | 50% | 1024 MB |\n\nDatabase growth: ~50–150 MB/month at 5-second polling with 90-day position retention.\n\n## Project structure\n\n```\nreadsbstats/\n├── src/readsbstats/            # Python package\n│   ├── collector.py            # Polling daemon, flight detection, writes\n│   ├── web.py                  # FastAPI app, JSON API, SPA catch-all\n│   ├── database.py             # SQLite schema, WAL, migrations\n│   ├── config.py               # RSBS_* env vars\n│   ├── http_safe.py            # SSRF-safe HTTP helpers (HTTPS-only)\n│   ├── photo_sources.py        # Planespotters → airport-data → hexdb → Wikipedia\n│   ├── notifier.py             # Telegram notifications\n│   ├── analytics.py            # DuckDB accelerator (opt-in)\n│   ├── health.py               # Receiver health checks\n│   └── geo.py                  # haversine_nm, bearing\n├── scripts/\n│   ├── install.sh              # First-time installer\n│   ├── update.sh               # Code sync + restart + optional DB update\n│   ├── purge_ghosts.py         # One-shot: remove ghost positions\n│   ├── purge_bad_gs.py         # One-shot: null implausible gs values\n│   └── purge_mlat_gs_spikes.py # One-shot: null MLAT gs spikes\n├── frontend/                   # React 19 + Vite 7 SPA\n├── tests/                      # pytest (1330+ tests) + Playwright UI (81 tests)\n├── static/airspace/            # Bundled airspace GeoJSON\n├── systemd/                    # Service + timer unit files\n└── docs/                       # Public documentation\n    ├── configuration.md        # All RSBS_* environment variables\n    ├── api.md                  # API endpoints + database schema\n    ├── integrations.md         # Telegram setup + ghost/GS filtering\n    ├── operations.md           # Updating, maintenance, useful commands\n    ├── development.md          # Local dev, testing, build, deploy\n    ├── decisions/              # Architecture Decision Records\n    └── screenshots/            # UI screenshots\n```\n\n## Documentation\n\n| Guide | Contents |\n|---|---|\n| [Configuration](docs/configuration.md) | All 70 `RSBS_*` env vars, logging, DuckDB, airspace config |\n| [API Reference](docs/api.md) | All API endpoints, SPA routes, database schema |\n| [Integrations](docs/integrations.md) | Telegram setup, bot commands, ghost/GS filtering |\n| [Operations](docs/operations.md) | Updating code, DB sync, useful commands, backups |\n| [Development](docs/development.md) | Local setup, tests, build, deploy to Pi |\n| [Architecture decisions](docs/decisions/) | ADRs for key technical choices |\n\n## Contributing\n\nBug reports and pull requests are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for setup and style guidelines. This project follows the [Code of Conduct](CODE_OF_CONDUCT.md).\n\n## License\n\nMIT — see [`LICENSE`](LICENSE).\n\nThe bundled frontend (`frontend/dist/`) includes Apache ECharts (Apache-2.0)\nand other open-source libraries. Required attribution lives in\n[`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblindp3w%2Freadsbstats","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblindp3w%2Freadsbstats","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblindp3w%2Freadsbstats/lists"}