docker-planesnitch: Se Chiva de Cada Avión Que Se Atreve a Volar Cerca de Ti

Vivo debajo de un corredor aéreo. Aviones de carga militares, jets gubernamentales, helicópteros de policía, algún squawk de emergencia de vez en cuando, todo eso pasándome por encima de la cabeza y yo sin tener ni idea de qué era nada. Claro, podía abrir Flightradar24 y quedarme mirando un mapa todo el día, pero no soy un jubilado con prismáticos. Quería algo que vigilara el cielo por mí y me pegara un grito cuando apareciera algo interesante.
Así que construí planesnitch. Un container de Docker que sondea APIs ADS-B públicas, contrasta los aviones con tus listas de vigilancia, y dispara alertas a Telegram o a webhooks. Jets militares, espías del gobierno, squawks de emergencia, voladores bajos y turbios, lo que tú le digas que vigile. Varias ubicaciones a la vez. Sin hardware SDR, sin antena, sin gilipolleces. Solo un fichero de configuración y una conexión a internet.

Cómo Funciona

En cada ciclo de sondeo (configurable, 1 minuto por defecto), planesnitch trae datos de aviones de hasta 4 APIs ADS-B públicas, en paralelo:

Deduplica por código hexadecimal ICAO, quedándose con la entrada que más campos de datos tiene. Algunas fuentes devuelven datos enriquecidos, tipo de aeronave, propietario u operador, matrícula, año de fabricación, mientras que otras solo te dan campos ADS-B en crudo. Planesnitch se queda automáticamente con la entrada más rica de cada avión.
Después pasa cada avión por tus listas de vigilancia y tus reglas de alerta. ¿Ha encontrado coincidencia? Formatea un mensaje y se lo lanza a tu bot de Telegram o a tu endpoint de webhook. Los cooldowns por alerta y por avión evitan que te spamee con el mismo C-17 dando vueltas durante 3 horas.
Si tienes tu propio receptor ADS-B con ultrafeeder, también puedes apuntar planesnitch ahí, misma configuración, solo añades una URL de fuente local.

Instalación

# 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/planesnitch

Ya está. Editas la configuración con tus coordenadas y el token de tu bot de Telegram, y ya estás chivándote.

La Configuración

Un solo fichero YAML lo controla todo. Defines dónde estás, qué vigilar, cuándo alertar, y adónde mandarlo.

Ubicaciones

Vigila tantos sitios como quieras. Tu casa, tu oficina, la casa de tu abuela, el Área 51, cada uno con su propio radio de búsqueda.

locations:
  home:
    name: "Home"
    lat: 38.8719
    lon: -77.0563
    radius: 150km
  area51:
    name: "Area 51"
    lat: 37.2350
    lon: -115.8111
    radius: 50nm

Los sufijos de unidades funcionan en todas partes, km, mi, nm, ft, m. Los números pelados caen por defecto en km para distancias y en ft para altitudes.
Agrupación automática de ubicaciones cercanas. Si dos ubicaciones están lo bastante cerca como para que una sola llamada a la API cubra las dos, planesnitch las agrupa automáticamente y hace una única petición upstream en vez de dos. ¿Configuras tu casa y tu oficina las dos con radio de 50km y están a 30km una de otra? Un solo golpe de API, los resultados repartidos a las dos ubicaciones. Define una docena de puntos que se solapen, planesnitch sigue fusionando hasta que un grupo topa con el círculo envolvente máximo, y entonces empieza uno nuevo. Te evita quemarte la cuota de rate limit en consultas redundantes al mismo trozo de cielo.
Cooldowns por fuente. Cada fuente upstream tiene su propio cooldown de rate limit, si adsb.lol empieza a soltar 429, esa fuente se echa atrás según su propio calendario mientras adsb.fi y tu ultrafeeder local siguen sondeando con normalidad. Ningún estrangulamiento de una sola API tumba el flujo entero.

Listas de Vigilancia

Seis tipos de listas de vigilancia le dicen a planesnitch de quién chivarse:

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: 3000ft

Los códigos squawk son los botones del pánico de la aviación, 7700 es emergencia general, 7600 es fallo de radio, 7500 es secuestro, 7400 es emergencia de aeronave no tripulada, 7777 es interceptación militar. El tipo de mierda del que quieres enterarte cuando está pasando a 6 millas de tu casa.
El tipo icao_csv se integra con plane-alert-db, una base de datos curada por la comunidad, con más de 15.000 aeronaves interesantes, mantenida por los buenos degenerados del mundillo del plane spotting:

  • Militares, 8.709 aeronaves
  • Gubernamentales, 1.743 aeronaves
  • Policía, 932 aeronaves
  • Civiles, 4.530 aeronaves destacables
  • Privacidad (PIA), 94 operadores celosos de su intimidad
  • Todo, 15.914 en total

La lista de vigilancia icao_type (v1.6) casa con el designador de tipo ICAO doc 8643, el código de 3-4 caracteres que la aviación usa para identificar el modelo de aeronave en sí, no la matrícula. C17 son todos los C-17 Globemaster del planeta. B738 son todos los 737-800. RFAL son todos los Rafale. AJET son todos los Alpha Jet. Mete los designadores que te interesen en values: y recibes alertas de cada célula de ese tipo que entre en tu radio, sin importar de quién sea ni qué matrícula lleve.
La lista de vigilancia de proximidad es para cazar voladores bajos. Pones un rango de altitud y planesnitch te avisa cuando algo vuela dentro de tu radio por debajo de ese techo. Útil para responder a “qué cojones ha sido eso” cuando algo te hace vibrar las ventanas a las 2 de la mañana.

Alertas

Conectas listas de vigilancia con destinos de notificación. Filtra por ubicación si quieres, si lo omites, se comprueban todas las ubicaciones. Los cooldowns evitan el 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]

Las cadenas de duración admiten s, m, h, así que valen 5m, 1h30m, 90s, o segundos pelados. Alertas distintas pueden irse a canales de Telegram distintos, las emergencias a uno, el spotting militar a otro, los voladores bajos a un tercero.

Notificaciones

Telegram y webhooks. Enruta alertas distintas a destinos distintos:

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"

Fotos de Aviones (v1.6)

Cuando una aeronave tiene designador de tipo ICAO (por ejemplo C17, B738, RFAL), planesnitch se trae la foto de avión correspondiente de doc8643.com y:

  • la adjunta al mensaje de Telegram como foto (el texto de la alerta pasa a ser el pie de foto, y si el pie supera el límite de 1024 caracteres de Telegram se parte en un mensaje de texto seguido de la foto, para que nunca pierdas el cuerpo)
  • incrusta los bytes JPEG (base64) en los payloads de webhook, en el nuevo campo image_base64, null si no hay imagen en caché

Las imágenes se cachean en disco bajo /images dentro del container, monta -v ./images:/images para conservarlas entre reinicios. La caché está indexada por designador de tipo, así que los más de 8.000 C-17 comparten un único fichero de foto. Los fallos se registran como marcadores .notfound, para que los tipos sin foto en doc8643 no se vuelvan a pedir en cada ciclo. Borra el directorio de caché para forzar un refresco.

El directorio de caché usa escrituras atómicas (.tmp más os.replace) y un asyncio.Lock por tipo, para que varias alertas que se disparan a la vez sobre el mismo tipo de aeronave no se pisen unas a otras al descargar. Los designadores de tipo que vienen de los feeds ADS-B upstream se validan contra ^[A-Z0-9]{1,8}$ antes de tocar el sistema de ficheros, nada de recorrido de rutas colado por un campo t envenenado, y cualquier respuesta cuyo content type no sea image/* se rechaza, para que las páginas de challenge HTML de Cloudflare no puedan envenenar la caché.

Renuncia a las Imágenes, por Destino (v1.7)

Las fotos están de lujo para un canal personal de Telegram. Son una puta pesadilla para un receptor de webhook de Home Assistant que tiene que masticar 80 KB de base64 en cada ciclo, o para un chat de spotters a tope donde todo el mundo ya ha visto cómo es un C-17. Así que cada destino de notificación acepta attach_image: false para bajar a solo texto:

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 null

Por defecto es true, así que eres tú quien elige el solo texto. Lo listo del asunto: si todos los destinos de notificación enganchados a una regla de alerta dada se desapuntan, planesnitch se salta por completo la descarga de doc8643 para esa alerta. Ni una llamada de red desperdiciada, ni una lectura de disco desperdiciada, ni un bloqueo cogido para nada. Mezclar destinos con attach_image=true y attach_image=false en la misma alerta sigue descargando una sola vez y sirve a los dos, la caché de fotos es compartida.

Qué Pinta Tienen las Alertas

Las alertas de Telegram vienen formateadas con emojis y con todos los datos que querrías de un vistazo:

🔔 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=ae07e1

Pinchas el enlace y te sale un mapa en tiempo real de la aeronave en globe.adsb.fi. La línea del squawk incluye el significado, planesnitch lleva una base de datos incorporada de significados y ámbitos de los códigos squawk, así que te dice por qué importa ese código.
Los payloads de webhook son arrays JSON con metadatos completos, detalles de la aeronave, motivo de la coincidencia, información de la lista de vigilancia, metadatos del CSV si viene de plane-alert-db, distancia desde la ubicación, y unidades de visualización. Todo lo que necesitas para montarte tus propias integraciones encima.

Unidades de Visualización

Tres preajustes controlan cómo aparecen la altitud, la distancia y la velocidad en las alertas:

display_units: aviation   # ft / nm / kts (default)
display_units: metric     # m / km / km/h
display_units: imperial   # ft / mi / mph

Las conversiones ocurren al enviar. Las cuentas internas son siempre métricas. Usa lo que tenga sentido para tu caso, si eres piloto, unidades aeronáuticas. Si eres un humano normal, métrico. Si eres estadounidense, imperial.

Recarga en Caliente y Salud

Los cambios de configuración se recogen en el siguiente ciclo de sondeo, sin reiniciar el container. Las listas de vigilancia en CSV se refrescan solas cada 24 horas. Un endpoint de salud en el puerto 8080 expone el uptime, la hora del último sondeo y el número de aeronaves, para monitorización y orquestación.

En Resumen

Un container de Docker que vigila el cielo y le chiva a tu Telegram cada aeronave interesante. Jets militares, aviones gubernamentales, squawks de emergencia, voladores bajos y turbios, matrículas concretas, tipos enteros de aeronave, lo que quieras. Varias ubicaciones, varias fuentes, varios destinos de notificación, fotos de aviones de doc8643 pegadas directamente a tus alertas, todo desde un único fichero YAML.
Sin hardware SDR. Sin antena. Sin receptor dedicado. Solo APIs ADS-B públicas y un fichero de configuración paranoico.

Ahora Con Skill de Agente

El repo trae un skill de agente en .agents/skills/planesnitch/, publicado en ClawHub por CI en los pushes de tag. Documenta toda la superficie de vigilancia, los CSV militares, gubernamentales y policiales de plane-alert-db, los squawks de emergencia 7500/7600/7700, las listas propias de hex y de tipos ICAO, los umbrales de altitud para voladores bajos, o simplemente “todo” si te odias a ti mismo, a lo largo de todas las APIs ADS-B gratuitas de las que puede tirar.
Así que, en vez de explicarle tu propio chivato de aviones a un asistente cada vez, él instala el skill y ya sabe qué mandos existen.
Cógelo aquí: github.com/psyb0t/docker-planesnitch
Con licencia WTFPL, porque chivarse de aviones no debería exigir un contrato de licencia.

Cómo Instalarlo En Tu Agente

Para que tu asistente pueda montar el chivato de aviones sin que tú le vayas narrando la configuración. Todo lo que hay bajo .agents/ está catalogado en un solo marketplace, así que son dos comandos:

claude plugin marketplace add psyb0t/agents
claude plugin install planesnitch@psyb0t

Codex usa el mismo marketplace con un verbo distinto, codex plugin add planesnitch@psyb0t, porque no existe codex plugin install. También encuentra el skill por su cuenta en un checkout del repo, ya que escanea .agents/skills/ de forma nativa sin nada instalado en absoluto.