Skip to content

Repository files navigation

flyover-alert

check

A Telegram message when an aircraft passes over your house — or over you, wherever your phone is.

Python 3.9+, standard library only. Free, keyless data feeds. Runs on a Mac, a Linux box, or a Windows machine nobody logs into.


What you get

Once a minute the bot asks a public ADS-B feed what is flying within 25 km of a point. For every aircraft it has not reported in the last half hour, one message:

✈️ EJU4521 · easyJet Europe
LIN → CDG · A320
📍 12 km · 34,000 ft · 421 kt
FR24 · FlightAware

When the airline is known, the message arrives as the airline's logo with that text as its caption. The two links open the live track.

Two modes, one process at a time:

flyover_bot.py a fixed point: your home, your office, a spot under the approach
flyover_follow.py wherever you are: share a live location with the bot from Telegram and it follows you until the share expires

Try it in 30 seconds

Without a token it prints instead of sending, so you can see what it finds before creating a bot:

git clone https://github.com/LUCA-MAURI/flyover-alert && cd flyover-alert
FLYOVER_LAT=51.47 FLYOVER_LON=-0.45 python3 flyover_bot.py   # over Heathrow: never quiet
python3 flyover_bot.py --test                                # self-test, no network

Setup

  1. Create a bot with @BotFather and keep the token.
  2. Send /start to your bot once — Telegram does not let a bot message you first — then open https://api.telegram.org/bot<TOKEN>/getUpdates and read message.chat.id. That is your chat id.
  3. cp config.env.example config.env and fill in the point, the token and the chat id. The file is git-ignored.
  4. ./run.sh for the fixed point, ./run.sh flyover_follow.py to follow your phone.

The token and chat id can also live in token.txt and chat_id.txt next to the scripts. That is what the Windows kit does: nothing secret ever goes into a launcher, a package, or a backup of either.

Follow mode. In Telegram, open the bot, paperclip → Location → Share Live Location (15 min, 1 h or 8 h). Alerts come from around your position until the share expires; a one-off pin works as a snapshot. Set FLYOVER_LAT/LON as well and the bot falls back to that point when your location goes stale; leave them unset and it alerts only while you are sharing.

Always on, on Windows

./make_package.sh builds dist/flyover-alert-win.zip. On the Windows machine: extract, put the token and chat id in two text files, set the coordinates in run.bat, run install.bat as Administrator. It registers a scheduled task that starts at boot under SYSTEM, restarts the process if it dies, and is not killed after 72 hours (the Task Scheduler default nobody knows about). win-kit/README.txt is the whole manual.

The package is not built if a self-test fails or if anything about to ship looks like a credential. It never contains token.txt or chat_id.txt.

On macOS or Linux, wrap run.sh in a launchd agent, a systemd unit or a @reboot cron line.

Design notes, each one paid for

Two feeds, one circuit breaker per host. The feed this started on began answering 403 to anonymous callers one night. The breaker did its job and quarantined the host — and wrote that to a log nobody was reading, so the bot was silent for a day. Now there are two independent position feeds, each behind its own breaker, and a route database on a third breaker so a dead lookup cannot stop position polling.

A heartbeat that stops when polling stops. The scheduler restarts a process that dies. It cannot see a process that is alive and has done nothing useful since Tuesday. After every successful poll the bot writes a timestamp; deadman.py checks it is fresh and messages you if not. The Windows kit registers that check every 15 minutes. The heartbeat is written after the work, never before: at the top of the loop it would only prove the loop spins.

Enrichment never blocks the alert. Route and airline come from a lookup that fails for private, military and positioning flights. When it fails, or is quarantined, the alert goes out with what the transponder said.

One report per airframe per half hour. Aircraft are keyed by ICAO hex, not callsign, so a flight that changes callsign is still one flight. Below 500 ft is on the ground, or as good as, and is skipped. The feed is queried in nautical miles with a margin, then filtered precisely with the haversine distance.

One process at a time. Two copies would each get half of the Telegram updates in follow mode, and both would alert. An exclusive bind on 127.0.0.1:49765 is the lock: it works the same on every OS and the kernel releases it when the process dies. Nothing is ever read from that socket.

Security

Everything in a message was broadcast by a transponder or looked up in a public database. None of it is trusted because it looks like a callsign.

  • Upstream text is escaped before it becomes markup and quoted before it becomes a URL. A callsign of <b>"x</b>/../y produces a correct message and a harmless link. The airline code is shape-checked before it is used to build the logo URL that Telegram fetches on your behalf.
  • Follow mode listens only to you. Anyone who finds the bot can write to it. Only location messages from the owner chat move the watched point; everything else is consumed and dropped. Your position is never written to the log — only the fact that it was updated.
  • The token never travels. Environment variable or a local file; the package build refuses to include it; and because some urllib errors quote the URL they failed on — which contains the token — the error path scrubs it before logging.
  • Delivery never raises. One failed message must not stop the poll loop or hide the other aircraft in the same cycle.
  • The heartbeat file is opened O_NOFOLLOW, because on Windows this runs as SYSTEM. See SECURITY.md.

Verify it yourself

Do not take the section above on trust - it is the kind of claim that is easy to make and cheap to get wrong. Everything is checked by standard tools, in one command:

./check.sh
Tool What it covers
self-tests the behaviour each module claims, run for real, no network
ruff lint, latent bugs, and the S security ruleset
bandit Python security scanner (OWASP-oriented)
mypy static types
semgrep dataflow analysis, p/python + p/security-audit
gitleaks credentials, in the tree and in the history
shellcheck the shell scripts

Current status: ALL CLEAR on every one of them.

A tool that is not installed is skipped rather than failing, so the script is usable before you have all of them - but a skipped tool is never counted as a pass. The final line only says ALL CLEAR when every tool actually ran.

What it deliberately does not do

  • No map. The free static-map providers have either shut down, started answering 403, or now want a key. The logo and two links say more than a pin on a tile did.
  • No history. It tells you what is overhead now. FlightRadar24 and FlightAware keep the archive; that is what the links are for.
  • One chat. It is a personal alert, not a service. Multi-user is a different program with a database in it.
  • 60 s cadence, not faster. The feeds ask for one request per second per client; once a minute is well inside that and is enough for aircraft that take ten minutes to cross 25 km.

Related

applog.py and breaker.py are vendored from resilient-poller; deadman.py and notify.py from job-watchdog. The Windows kit is the small-footprint cousin of winservice-kit, for the case where Python is already installed.

Data: adsb.lol, adsb.fi, adsbdb, avs.io. All free and run by volunteers; be polite to them.

MIT licensed.

About

Telegram alert when an aircraft passes over your house, or over your phone. Free ADS-B feeds behind circuit breakers, a heartbeat that proves it is polling, a double-click Windows kit. Python stdlib only.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages