MQTT gestionado en la nube

Seguimiento de vehículos con MQTT: topics, payloads y un mapa de flota en vivo

Construye un seguimiento de vehículos con MQTT que funcione con enlaces celulares irregulares: diseño de topics, payloads GPS compactos, ajuste del keep alive, detección de desconexiones y un mapa web en vivo.

Ilustración del seguimiento de vehículos con MQTT con furgonetas de reparto que envían posiciones GPS por red celular a un broker en la nube y a un mapa de flota en vivo
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

El seguimiento de vehículos con MQTT funciona bien porque el protocolo se diseñó exactamente para este tipo de enlace: dispositivos pequeños que envían mensajes pequeños con frecuencia por redes poco fiables y de pago por uso. En esta guía diseñarás una estructura de topics para una flota, elegirás payloads GPS compactos, ajustarás el keep alive y las sesiones para rastreadores celulares, detectarás vehículos desconectados y construirás un mapa en vivo en el navegador que se actualiza directamente desde suscripciones MQTT en ConnectMQ.

Por qué MQTT encaja con la telemática de flotas

Un rastreador celular en una furgoneta de reparto, ya sea en Bogotá, Ciudad de México o Valencia, se pasa la vida cambiando de celda, entrando en túneles y perdiendo cobertura en estacionamientos subterráneos. Cada reconexión cuesta tiempo, energía y datos. MQTT ayuda de varias formas:

  • Una conexión persistente en lugar de una nueva petición HTTP por posición, de modo que cabeceras y handshakes se pagan una sola vez.
  • Sobrecarga fija pequeña por mensaje, algo que importa cuando se factura cada kilobyte.
  • Keep alive y Last Will dan al servidor una señal clara cuando un vehículo se queda en silencio.
  • QoS 1 con sesiones persistentes permite que los comandos lleguen a un vehículo que perdió cobertura brevemente.
  • Fan-out mediante suscripciones: la misma posición alimenta el mapa de un despachador, un servicio de geocercas y un escritor de histórico sin que el rastreador haga nada extra.

Para repasar las garantías de entrega, consulta los niveles de QoS de MQTT explicados.

Diseño de topics para el seguimiento de vehículos

Empieza con una jerarquía que refleje cómo consulta la gente los datos: por flota, después por vehículo y después por tipo de dato.

fleet/{fleetId}/vehicle/{vehicleId}/position     posiciones GPS en vivo
fleet/{fleetId}/vehicle/{vehicleId}/status       online/offline (retenido)
fleet/{fleetId}/vehicle/{vehicleId}/event        contacto, frenada brusca, puerta abierta
fleet/{fleetId}/vehicle/{vehicleId}/diag         tensión de batería, calidad de señal
fleet/{fleetId}/vehicle/{vehicleId}/cmd          comandos al rastreador

Así, el mapa de un despachador puede suscribirse a fleet/north/vehicle/+/position, un servicio de alertas a fleet/+/vehicle/+/event y un panel de operaciones a fleet/+/vehicle/+/status. Mantén los identificadores cortos y estables: un ID de vehículo como v0142 en lugar de una matrícula completa con espacios. Evita poner información de identificación personal, como el nombre de un conductor, en los nombres de los topics.

Diseño del payload

Los mensajes de posición son la mayor parte de tu tráfico, así que merecen atención.

Campo Clave Ejemplo Notas
Marca de tiempo t 1792137600 Segundos Unix según la hora GNSS, no la hora de recepción del servidor
Latitud la 41.01224 5 decimales equivalen aproximadamente a un metro
Longitud lo 28.97601 Misma precisión
Velocidad s 48 km/h, entero
Rumbo h 270 Grados, entero
Calidad del fix q 3 0 = ninguno, 2 = 2D, 3 = 3D
Satélites n 9 Útil para filtrar fixes malos

El payload resultante ocupa unos 90 bytes:

{"t":1792137600,"la":41.01224,"lo":28.97601,"s":48,"h":270,"q":3,"n":9}

Reglas prácticas:

  1. Incluye siempre la marca de tiempo del dispositivo. Los mensajes almacenados durante una zona sin cobertura llegan tarde; el mapa y el histórico deben ordenar por la hora del fix.
  2. Agrupa al vaciar el buffer. Al salir de un túnel, publica un mensaje con un array de fixes almacenados en lugar de cientos de mensajes individuales.
  3. Informa de forma adaptativa. Cada 5 a 15 segundos en movimiento, cada pocos minutos con el vehículo estacionado y de inmediato ante cambios de rumbo significativos.
  4. Descarta los fixes malos en el dispositivo. Si la calidad del fix es 0, no publiques ninguna posición.

Keep alive, sesiones y QoS en enlaces celulares

  • Keep alive: de 60 a 120 segundos es un punto de partida razonable en redes celulares. Los valores más cortos detectan antes las caídas, pero mantienen el módem despierto; los timeouts del NAT del operador también pueden cerrar en silencio las conexiones inactivas, así que no lo alargues tanto que el mapeo NAT caduque antes.
  • QoS: QoS 0 es aceptable para posiciones de alta frecuencia en las que el siguiente fix sustituye al anterior; QoS 1 para eventos y comandos que no se pueden perder.
  • Sesiones persistentes: conéctate con clean start a false y una caducidad de sesión (MQTT 5), por ejemplo de 10 a 30 minutos, para que los comandos enviados durante una caída corta se entreguen al reconectar.
  • Caducidad de mensajes: pon caducidad a comandos como "desbloquear puertas" para que un vehículo que vuelve una hora después no ejecute una instrucción antigua.
  • Last Will: registra un will offline retenido en el topic de estado y publica un online retenido después de conectarte.

Simular un rastreador en Python

Antes de que llegue el hardware, simula un vehículo. Este script circula en línea, usa un Last Will y publica posiciones con paho-mqtt 2.x. Apunta al servidor MQTT público gratuito para que puedas ejecutarlo de inmediato; ese servidor es para pruebas y prototipos, así que para uso real cambia a tus propias credenciales y al puerto 8883.

import json
import math
import time
import uuid

import paho.mqtt.client as mqtt

HOST = "broker.connectmq.com"
PORT = 1883
PREFIX = f"connectmq/demo/{uuid.uuid4().hex[:6]}"
VEHICLE = "v0142"
BASE = f"{PREFIX}/fleet/north/vehicle/{VEHICLE}"

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id=f"sim-{VEHICLE}-{uuid.uuid4().hex[:6]}",
                     protocol=mqtt.MQTTv5)
client.will_set(f"{BASE}/status", "offline", qos=1, retain=True)


def on_connect(client, userdata, flags, reason_code, properties):
    print("Connected:", reason_code, "| topic prefix:", PREFIX)
    client.publish(f"{BASE}/status", "online", qos=1, retain=True)


client.on_connect = on_connect
client.connect(HOST, PORT, keepalive=90)
client.loop_start()

lat, lon, heading = 41.0100, 28.9700, 45.0
try:
    while True:
        lat += 0.0003 * math.cos(math.radians(heading))
        lon += 0.0003 * math.sin(math.radians(heading))
        heading = (heading + 3) % 360
        fix = {"t": int(time.time()), "la": round(lat, 5), "lo": round(lon, 5),
               "s": 42, "h": int(heading), "q": 3, "n": 9}
        client.publish(f"{BASE}/position", json.dumps(fix), qos=0)
        time.sleep(5)
except KeyboardInterrupt:
    client.publish(f"{BASE}/status", "offline", qos=1, retain=True).wait_for_publish()
    client.loop_stop()
    client.disconnect()

Apunta el prefijo que se imprime; lo necesitarás para el mapa. El broker público permite 10 mensajes por segundo por cliente y 8 niveles de topic, así que el topic completo connectmq/demo/xxxxxx/fleet/north/vehicle/v0142/position (8 niveles) cabe justo. Acorta la jerarquía si añades más niveles. Recuerda que el área pública puede leerla cualquiera: usa solo coordenadas simuladas.

Un mapa de flota en vivo a partir de suscripciones

El mapa no es más que un cliente MQTT en el navegador que se suscribe a las posiciones y mueve marcadores. Esta página usa MQTT.js sobre Secure WebSocket y Leaflet.

// map.js - carga Leaflet y MQTT.js en tu página y añade un contenedor con id "map"
const PREFIX = "connectmq/demo/REPLACE_WITH_PREFIX";
const map = L.map("map").setView([41.01, 28.97], 13);
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
  attribution: "OpenStreetMap contributors",
}).addTo(map);

const markers = new Map();
const client = mqtt.connect("wss://broker.connectmq.com:8084/mqtt", {
  clientId: "fleet-map-" + Math.random().toString(16).slice(2, 10),
  protocolVersion: 5,
});

client.on("connect", () => {
  client.subscribe(`${PREFIX}/fleet/+/vehicle/+/position`);
  client.subscribe(`${PREFIX}/fleet/+/vehicle/+/status`);
});

client.on("message", (topic, payload) => {
  const parts = topic.split("/");
  const vehicleId = parts[parts.length - 2];
  const kind = parts[parts.length - 1];

  if (kind === "position") {
    const fix = JSON.parse(payload.toString());
    let m = markers.get(vehicleId);
    if (!m) {
      m = L.marker([fix.la, fix.lo]).addTo(map).bindTooltip(vehicleId);
      markers.set(vehicleId, m);
    }
    m.setLatLng([fix.la, fix.lo]);
    m.setTooltipContent(`${vehicleId} - ${fix.s} km/h`);
  } else if (kind === "status") {
    const m = markers.get(vehicleId);
    if (m) m.setOpacity(payload.toString() === "online" ? 1 : 0.4);
  }
});

En producción, autentica el mapa con credenciales emitidas por tu backend en lugar de incrustar una contraseña compartida en la página y, si hay muchos espectadores del mapa abiertos a la vez, plantéate un pequeño backend que se suscriba una sola vez y sirva las posiciones a los navegadores.

Almacenar el histórico y las geocercas

ConnectMQ es el broker, no una base de datos, así que el histórico y las geocercas se ejecutan como tus propios clientes MQTT. Un servicio en Python o Node.js suscrito a fleet/+/vehicle/+/position puede escribir en PostgreSQL con PostGIS o en una base de datos de series temporales, y un segundo servicio puede comprobar cada fix contra los polígonos de las geocercas y publicar en el topic de eventos. Con Serverless (Paid) o superior, las suscripciones compartidas como $share/geo/fleet/+/vehicle/+/position permiten que varias instancias se repartan la carga. Las reglas de alerta por umbral del portal también resultan prácticas para comprobaciones sencillas, como que la tensión de batería del diagnóstico baje de un límite.

Gestionar la falta de cobertura en el dispositivo

Los rastreadores pasan bastante tiempo sin cobertura, así que el firmware necesita un plan para ello. Mantén un buffer circular de fixes recientes en flash o en RAM, dimensionado para la ausencia de cobertura más larga que esperes, por ejemplo una hora de fixes a una frecuencia reducida. Cuando vuelva la conexión, publica primero la posición actual para que el mapa en vivo se actualice de inmediato y después vacía el buffer por lotes con sus marcas de tiempo originales. Los consumidores que escriben histórico deben hacer upsert por vehículo y marca de tiempo, para que un lote entregado dos veces con QoS 1 no cree puntos duplicados.

Checklist para producción

  1. Credenciales y client ID únicos por rastreador, TLS en el 8883.
  2. Marca de tiempo del dispositivo en cada fix; envío por lotes tras las caídas.
  3. Intervalo de envío adaptativo.
  4. Estado retenido con Last Will.
  5. Sesiones persistentes y caducidad de mensajes para los comandos.
  6. Nada de datos personales en los nombres de los topics.
  7. Backoff con jitter en la reconexión para toda la flota.

La parte ESP32 de un rastreador se trata en rastreador GPS con ESP32 y MQTT, y MQTT para apps móviles cubre las apps para conductores o despachadores. Para las opciones de hosting, consulta la guía de broker MQTT en la nube.

Sigue a tu flota con ConnectMQ

Crea un broker Serverless gratuito en app.connectmq.com sin tarjeta de crédito, apunta a él tus rastreadores o el simulador por TLS y observa cómo llegan las posiciones en el explorador de topics en vivo. ConnectMQ es un broker MQTT gestionado, con planes Serverless (Paid) y Dedicated a medida que crece tu flota.

Preguntas frecuentes

¿Con qué frecuencia debe publicar su posición por MQTT un rastreador de vehículos?

Cada 5 a 15 segundos en movimiento y cada pocos minutos con el vehículo estacionado es un punto de partida habitual. Ajústalo según tu caso de uso y tu plan de datos.

¿Qué QoS debo usar para las posiciones GPS?

QoS 0 suele bastar para posiciones frecuentes, porque el siguiente fix sustituye al anterior. Usa QoS 1 para eventos y comandos que deben llegar.

¿Cómo sé cuándo un vehículo se desconecta?

Registra un Last Will retenido con offline en el topic de estado del vehículo y publica un online retenido después de conectarte.

¿Puede ConnectMQ almacenar el histórico de ubicaciones?

No, el broker enruta mensajes. Ejecuta tu propio servicio suscriptor para escribir las posiciones en una base de datos como PostgreSQL con PostGIS.

Artículos relacionados

Broker MQTT BYOC: el modelo Bring Your Own Cloud explicado

Un broker MQTT BYOC se ejecuta en tu cuenta cloud, pero lo opera un proveedor. Descubre cómo funciona el modelo, cómo se reparten las responsabilidades y cómo preparar tu cuenta.

9 min de lectura

Alternativa a Google Cloud IoT Core: opciones y migración tras su cierre

Google retiró Cloud IoT Core en agosto de 2023. Esta guía compara las alternativas realistas, traduce los conceptos de IoT Core a MQTT estándar y muestra cómo mover los dispositivos a un broker MQTT gestionado sin dejar de enviar datos a Google Cloud.

9 min de lectura

Mensajes MQTT por segundo: cómo estimar y medir el rendimiento

Planificar el rendimiento de MQTT se reduce a unas pocas fórmulas y una medición honesta. Aprende a estimar los mensajes entrantes y salientes por segundo, a tener en cuenta los picos y a trasladar el resultado a un plan de broker.

8 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.