J’habite sous un couloir aérien. Avions cargo militaires, jets gouvernementaux, hélicoptères de police, le squawk d’urgence occasionnel, tout ça me passe au-dessus de la tête et je n’avais aucune idée de ce que c’était. Bien sûr, je pouvais ouvrir Flightradar24 et fixer une carte toute la journée, mais je ne suis pas un retraité avec des jumelles. Je voulais un truc qui surveille le ciel à ma place et qui me gueule dessus quand quelque chose d’intéressant se pointe.
Alors j’ai construit planesnitch. Un container Docker qui interroge des API ADS-B publiques, confronte les avions à tes listes de surveillance, et balance des alertes vers Telegram ou des webhooks. Jets militaires, barbouzes gouvernementales, squawks d’urgence, avions volant bas et louches, tout ce que tu lui dis de guetter. Plusieurs emplacements en même temps. Pas de matériel SDR, pas d’antenne, pas de conneries. Juste un fichier de config et une connexion internet.
Comment Ça Marche
À chaque cycle d’interrogation (configurable, 1 minute par défaut), planesnitch récupère des données d’avions auprès de jusqu’à 4 API ADS-B publiques, en parallèle:
Il déduplique par code hexadécimal ICAO, en gardant l’entrée qui a le plus de champs de données. Certaines sources renvoient des données enrichies, type d’appareil, propriétaire ou exploitant, immatriculation, année de construction, alors que d’autres te donnent juste des champs ADS-B bruts. Planesnitch garde automatiquement l’entrée la plus riche pour chaque avion.
Ensuite il fait passer chaque avion par tes listes de surveillance et tes règles d’alerte. Une correspondance trouvée? Il formate un message et le balance à ton bot Telegram ou à ton endpoint de webhook. Des cooldowns par alerte et par avion l’empêchent de te spammer au sujet du même C-17 qui tourne en rond pendant 3 heures.
Si tu fais tourner ton propre récepteur ADS-B avec ultrafeeder, tu peux aussi pointer planesnitch dessus, même config, tu ajoutes juste une URL de source locale.
Installation
# Grab the config and edit it
curl -sL
https://raw.githubusercontent.com/psyb0t/docker-planesnitch/main/config.yaml.example
-o config.yaml
# Optional: download military/gov/police watchlists
mkdir -p csv
BASE=https://raw.githubusercontent.com/sdr-enthusiasts/plane-alert-db/main
curl -sLo csv/plane-alert-mil.csv $BASE/plane-alert-mil.csv
curl -sLo csv/plane-alert-gov.csv $BASE/plane-alert-gov.csv
curl -sLo csv/plane-alert-pol.csv $BASE/plane-alert-pol.csv
# Run it
docker run
-v ./config.yaml:/app/config.yaml:ro
-v ./csv:/csv:ro
psyb0t/planesnitchC’est tout. Tu édites la config avec tes coordonnées et le token de ton bot Telegram, et te voilà en train de balancer.
La Config
Un seul fichier YAML pilote tout. Tu définis où tu es, ce qu’il faut guetter, quand alerter, et où envoyer.
Emplacements
Surveille autant d’endroits que tu veux. Ta maison, ton bureau, chez ta grand-mère, la Zone 51, chacun avec son propre rayon de recherche.
locations:
home:
name: "Home"
lat: 38.8719
lon: -77.0563
radius: 150km
area51:
name: "Area 51"
lat: 37.2350
lon: -115.8111
radius: 50nmLes suffixes d’unités marchent partout, km, mi, nm, ft, m. Les nombres nus retombent sur km pour les distances et sur ft pour les altitudes.
Regroupement automatique des emplacements proches. Si deux emplacements sont assez près pour qu’un seul appel d’API les couvre tous les deux, planesnitch les regroupe automatiquement et fait une seule requête en amont au lieu de deux. Tu configures ta maison et ton bureau tous les deux avec un rayon de 50km et ils sont à 30km l’un de l’autre? Un seul appel d’API, les résultats distribués aux deux emplacements. Définis une douzaine de points qui se chevauchent, planesnitch continue de fusionner jusqu’à ce qu’un groupe bute sur le cercle englobant maximal, puis il en démarre un nouveau. Ça t’évite de cramer ton quota de rate limit en requêtes redondantes sur le même bout de ciel.
Cooldowns par source. Chaque source en amont a son propre cooldown de rate limit, si adsb.lol se met à balancer des 429, cette source-là se met en retrait selon son propre calendrier pendant qu’adsb.fi et ton ultrafeeder local continuent d’interroger normalement. Aucun étranglement d’une seule API ne met tout le flux par terre.
Listes de Surveillance
Six types de listes de surveillance disent à planesnitch qui balancer:
watchlists:
# Emergency squawk codes
emergencies:
type: squawk
values: ["7500", "7600", "7700", "7400", "7777"]
# 8,709 military aircraft from community database
military:
type: icao_csv
source: plane-alert-mil.csv
# Government aircraft
government:
type: icao_csv
source: plane-alert-gov.csv
# Stalk specific aircraft by ICAO hex
my_planes:
type: icao
values: ["4ca123", "a12345"]
# Stalk by aircraft type — any A400M, Rafale, or Alpha Jet
cool_jets:
type: icao_type
values: ["A400", "RFAL", "AJET"]
# Everything within radius
everything:
type: all
# WTF just buzzed my house
low_flyers:
type: proximity
min_altitude: 0ft
max_altitude: 3000ftLes codes squawk sont les boutons panique de l’aviation, 7700 c’est urgence générale, 7600 c’est panne radio, 7500 c’est détournement, 7400 c’est urgence d’aéronef sans pilote, 7777 c’est interception militaire. Le genre de merde que tu veux connaître quand ça se passe à 6 miles de chez toi.
Le type icao_csv s’intègre à plane-alert-db, une base de données entretenue par la communauté, avec plus de 15 000 appareils intéressants, tenue par les braves dégénérés du milieu du plane spotting:
- Militaires, 8 709 appareils
- Gouvernementaux, 1 743 appareils
- Police, 932 appareils
- Civils, 4 530 appareils notables
- Vie privée (PIA), 94 exploitants soucieux de leur intimité
- Tout, 15 914 au total
La liste de surveillance icao_type (v1.6) matche sur le désignateur de type ICAO doc 8643, le code de 3-4 caractères que l’aviation utilise pour identifier le modèle d’appareil lui-même, pas l’immatriculation. C17, c’est tous les C-17 Globemaster de la planète. B738, c’est tous les 737-800. RFAL, c’est tous les Rafale. AJET, c’est tous les Alpha Jet. Balance les désignateurs qui t’intéressent dans values: et tu reçois des alertes pour chaque cellule de ce type qui entre dans ton rayon, peu importe à qui elle appartient ou quelle immatriculation elle porte.
La liste de surveillance de proximité sert à choper les avions qui volent bas. Tu règles une plage d’altitude et planesnitch t’alerte quand quoi que ce soit vole dans ton rayon sous ce plafond. Pratique pour répondre à “c’était quoi ce bordel” quand un truc fait vibrer tes fenêtres à 2h du mat.
Alertes
Tu relies les listes de surveillance à des cibles de notification. Filtre par emplacement si tu veux, si tu l’omets, tous les emplacements sont vérifiés. Les cooldowns évitent le spam:
alerts:
- name: "Emergency Alert"
watchlists: [emergencies]
cooldown: 1m
notify: [tg_emergencies]
- name: "Military Spotter"
watchlists: [military, government]
cooldown: 5m
notify: [tg_spotting]
- name: "Everything at Home"
locations: [home]
watchlists: [everything]
cooldown: 1m
notify: [tg_main]Les chaînes de durée acceptent s, m, h, donc 5m, 1h30m, 90s, ou des secondes brutes, tout marche. Des alertes différentes peuvent partir vers des canaux Telegram différents, les urgences vers l’un, le spotting militaire vers un autre, les vols à basse altitude vers un troisième.
Notifications
Telegram et webhooks. Route des alertes différentes vers des destinations différentes:
notifications:
tg_emergencies:
type: telegram
bot_token: "123456:ABC-DEF"
chat_id: "-100123456789"
tg_spotting:
type: telegram
bot_token: "123456:ABC-DEF"
chat_id: "-100987654321"
my_webhook:
type: webhook
url: "https://example.com/hook"
headers:
Authorization: "Bearer xxx"Photos d’Avions (v1.6)
Quand un appareil a un désignateur de type ICAO (par exemple C17, B738, RFAL), planesnitch va chercher la photo d’avion correspondante sur doc8643.com et:
- l’attache au message Telegram comme photo (le texte de l’alerte devient la légende de la photo, et si la légende dépasse la limite de 1024 caractères de Telegram, elle est coupée en un message texte suivi de la photo, pour que tu ne perdes jamais le corps)
- embarque les octets JPEG (base64) dans les payloads de webhook, dans le nouveau champ
image_base64,nulls’il n’y a pas d’image en cache
Les images sont mises en cache sur disque sous /images à l’intérieur du container, monte -v ./images:/images pour les garder d’un redémarrage à l’autre. Le cache est indexé par désignateur de type, donc les plus de 8 000 C-17 partagent un seul fichier photo. Les échecs sont enregistrés comme marqueurs .notfound, pour que les types sans photo sur doc8643 ne soient pas redemandés à chaque cycle. Supprime le répertoire de cache pour forcer un rafraîchissement.
Le répertoire de cache utilise des écritures atomiques (.tmp plus os.replace) et un asyncio.Lock par type, pour que plusieurs alertes qui se déclenchent en même temps sur le même type d’appareil ne se marchent pas dessus pendant la récupération. Les désignateurs de type venus des flux ADS-B en amont sont validés contre ^[A-Z0-9]{1,8}$ avant la moindre touche au système de fichiers, pas de traversée de chemin glissée par un champ t empoisonné, et toute réponse dont le content type n’est pas image/* est rejetée, pour que les pages de challenge HTML de Cloudflare ne puissent pas empoisonner le cache.
Refus des Images, par Cible (v1.7)
Les photos, c’est parfait pour un canal Telegram personnel. C’est un putain de cauchemar pour un récepteur de webhook Home Assistant qui doit mâcher 80 Ko de base64 à chaque cycle, ou pour un chat de spotters bondé où tout le monde a déjà vu à quoi ressemble un C-17. Donc chaque cible de notification accepte attach_image: false pour redescendre en texte seul:
notifications:
tg_main:
type: telegram
bot_token: "..."
chat_id: "..."
attach_image: false # plain sendMessage, no photo
my_webhook:
type: webhook
url: "https://example.com/hook"
attach_image: false # image_base64 will be nullLe défaut est true, c’est donc à toi de choisir le texte seul. Le truc malin: si toutes les cibles de notification rattachées à une règle d’alerte donnée se désistent, planesnitch saute entièrement la récupération doc8643 pour cette alerte. Pas d’appel réseau gâché, pas de lecture disque gâchée, pas de verrou pris pour rien. Mélanger des cibles attach_image=true et attach_image=false sur la même alerte récupère quand même une seule fois et sert les deux, le cache photo est partagé.
À Quoi Ressemblent les Alertes
Les alertes Telegram sont formatées avec des emojis et toutes les données que tu voudrais d’un coup d’œil:
🔔 Emergency Alert
🚨 squawk 7700 (EMERGENCY)
✈️ RYR1234
🛩️ BOEING 737-800 | EI-ABC | 2015
💼 RYANAIR
📍 45.5000, 28.1000 | 3,200 ft
📏 6 nm from home
💨 280 kts
🗺️ https://globe.adsb.fi/?icao=4ca123🔔 Military Spotter
✈️ TEDDY64
🛩️ BOEING C-17A Globemaster III | 94-0067 | 1994
💼 USAF
🏷️ USAF — USAF
📍 37.9306, -78.7019 | 12,350 ft
📏 99 nm from home
💨 413 kts
📡 squawk 1613
🗺️ https://globe.adsb.fi/?icao=ae07e1Clique sur le lien et tu obtiens une carte en temps réel de l’appareil sur globe.adsb.fi. La ligne de squawk inclut la signification, planesnitch a une base de données intégrée des significations et des portées des codes squawk, il te dit donc pourquoi ce code compte.
Les payloads de webhook sont des tableaux JSON avec des métadonnées complètes, détails de l’appareil, raison de la correspondance, infos sur la liste de surveillance, métadonnées CSV si ça vient de plane-alert-db, distance depuis l’emplacement, et unités d’affichage. Tout ce qu’il te faut pour construire tes propres intégrations par-dessus.
Unités d’Affichage
Trois préréglages contrôlent la façon dont l’altitude, la distance et la vitesse apparaissent dans les alertes:
display_units: aviation # ft / nm / kts (default)
display_units: metric # m / km / km/h
display_units: imperial # ft / mi / mphLes conversions se font à l’envoi. Les maths internes sont toujours en métrique. Utilise ce qui a du sens pour ta situation, si tu es pilote, les unités aéronautiques. Si tu es un humain normal, le métrique. Si tu es américain, l’impérial.
Rechargement à Chaud et Santé
Les changements de config sont pris au cycle d’interrogation suivant, sans redémarrer le container. Les listes de surveillance en CSV se rafraîchissent automatiquement toutes les 24 heures. Un endpoint de santé sur le port 8080 expose l’uptime, l’heure de la dernière interrogation et le nombre d’avions, pour la supervision et l’orchestration.
En Résumé
Un container Docker qui surveille le ciel et balance chaque appareil intéressant sur ton Telegram. Jets militaires, avions gouvernementaux, squawks d’urgence, avions volant bas et louches, immatriculations précises, types d’appareils entiers, ce que tu veux. Plusieurs emplacements, plusieurs sources, plusieurs cibles de notification, des photos d’avions doc8643 attachées directement à tes alertes, le tout depuis un seul fichier YAML.
Pas de matériel SDR. Pas d’antenne. Pas de récepteur dédié. Juste des API ADS-B publiques et un fichier de config paranoïaque.
Maintenant Avec un Skill d’Agent
Le repo livre un skill d’agent dans .agents/skills/planesnitch/, publié sur ClawHub par la CI aux pushs de tags. Il documente toute la surface de surveillance, les CSV militaires, gouvernementaux et de police de plane-alert-db, les squawks d’urgence 7500/7600/7700, les listes personnalisées de hex et de types ICAO, les seuils d’altitude pour les vols à basse altitude, ou juste “tout” si tu te détestes, à travers toutes les API ADS-B gratuites dans lesquelles il peut puiser.
Du coup, au lieu d’expliquer ton propre mouchard à avions à un assistant à chaque fois, il installe le skill et sait déjà quels boutons existent.
Va le chercher: github.com/psyb0t/docker-planesnitch
Sous licence WTFPL, parce que balancer des avions ne devrait pas exiger un contrat de licence.
L’Installer Dans Ton Agent
Pour que ton assistant puisse monter le mouchard à avions sans que tu lui récites la config. Tout ce qui est sous .agents/ est catalogué dans un seul marketplace, donc ça fait deux commandes:
claude plugin marketplace add psyb0t/agents
claude plugin install planesnitch@psyb0tCodex utilise le même marketplace avec un verbe différent, codex plugin add planesnitch@psyb0t, parce qu’il n’existe pas de codex plugin install. Il trouve aussi le skill tout seul dans un checkout du repo, puisqu’il scanne .agents/skills/ nativement sans que rien ne soit installé.