Le module Aérien de KiloDelta affiche maintenant en temps quasi-réel les aéronefs étatiques français sur la carte tactique. Sécurité Civile (Canadair, Dash, Beechcraft, hélicoptères), Gendarmerie, Douanes. Note rapide sur le pipeline que j'ai posé pour y arriver.
Acquisition
L'ADS-B (Automatic Dependent Surveillance-Broadcast) diffuse en 1090 MHz Mode S Extended Squitter la position GPS, le cap, la vitesse sol et l'identifiant ICAO 24 bits de l'aéronef. On ne capte pas ces trames nous-mêmes : on s'appuie sur les agrégateurs communautaires qui couvrent le territoire avec des récepteurs SDR au sol.
Cascade primary → backup : adsb.lol d'abord, adsb.fi en fallback si le primary répond hors délai ou 5xx. Les deux ont une fenêtre de fraîcheur upstream d'environ 30 secondes. C'est le facteur limitant côté physique du pipeline.
Backend KiloDelta
Endpoint public GET /api/v1/aircraft/active qui sert la liste filtrée. Côté serveur, deux mécaniques qui changent tout en charge :
- Cache 5 secondes avec verrou atomique. Si N clients arrivent en simultané, un seul appel amont est émis ; les autres lisent la réponse cachée. Sur un départ de feu avec 4 groupes regardant l'écran, ça divise par 4 les coûts vers adsb.lol et tient les rate-limits.
- Pull-on-demand au lieu d'un timer permanent. Le fetch upstream n'est déclenché que par un client qui demande, jamais en background. Économise les ressources hors saison feu.
Côté discovery, une commande Spark aircraft:discover --from-opensky seed la flotte étatique depuis la base OpenSky : filtre callsign LIKE 'F-Z%' plus les codes opérateurs Gendarmerie (F-MJ*) et Douanes (F-ZBM*). Cron mensuel pour rattraper les nouvelles immat et les radiations. Table aircraft côté MySQL avec admin Bootstrap pour annoter manuellement si besoin.
App Flutter
Provider Riverpod trackedAircraftProvider en autoDispose : le polling 10 secondes ne tourne que tant qu'un écran qui en a besoin est monté (Aérien, Simulation). Sortie de l'écran → autoDispose → Timer cancel → zéro trafic. Le client HTTP est en keepAlive: true séparément pour éviter le pattern dangereux de cancel-loop sur autoDispose + ref.read ponctuel.
Entre deux pulls upstream, l'app fait du dead reckoning pour chaque aéronef : position extrapolée linéaire à partir de la dernière vitesse sol + cap connus, projection sphérique haversine inverse. Le cap est lerpé angulairement (interpolation court-chemin sur 360°) pour éviter le flip à -180/+180. Visuellement, les markers glissent en continu au lieu de sauter d'un kilomètre toutes les 10 secondes.
Filet anti-fantôme côté Dart : on filtre les aéronefs dont seenAt remonte à plus de 90 secondes (3 cycles upstream typiques). Le backend peut continuer à renvoyer un aéronef si son cache TTL est plus long que la réalité ; ce filet ferme la porte au marker figé qui persiste pendant qu'un transpondeur est coupé.
UX
Toggle "aéronefs" sur l'écran Aérien. Icônes distinctes avion / hélico (catégorie ADS-B + heuristique opérateur en fallback). Long-press → fiche détail (type, opérateur, vitesse sol, altitude baro, FL). Bouton fit auto qui calcule la bbox des markers visibles et zoom en conséquence.
Sur l'accueil mission, AircraftStatsCard : compteurs dans un rayon paramétrable autour de l'ignition, ventilés par catégorie (planes/helicopters) et par opérateur (SC, Gendarmerie, Douanes). Liste brute accessible au tap pour identification rapide.
Limites
Latence cumulée pipeline : ~30 s upstream + jusqu'à 10 s polling = pire cas ~40 s entre émission trame ADS-B et affichage. Largement suffisant pour de l'information de situation, insuffisant pour autre chose. Un transpondeur coupé n'apparaît pas — absence d'écho ne signifie pas absence d'aéronef. La couverture sol est inhomogène : antennes denses en plaine, lacunes en haute montagne et hors zone touristique. Sur basse altitude en canyon corse, attendre des trous.
Ce n'est pas un outil de coordination tactique. Pas un substitut radio Air-Sol, pas un substitut GAAr, pas un substitut contact DZ. Conscience situationnelle, point.
Suite
Pose des moyens terrestres sur la même couche via le module géopartage live de mission (v2 en cours). Une fois ciel + sol corrélés sur la même carte, on supprime la friction multi-écrans côté COS. Pas de date.