Inicio » Blog » MQTT: Protocolo de Mensajería para IoT — Guía Técnica Completa

MQTT: Protocolo de Mensajería para IoT — Guía Técnica Completa

Dirigido a desarrolladores de firmware y arquitectos de sistemas con experiencia intermedia en redes.

1. ¿Qué es MQTT y por qué importa en IoT?

MQTT (Message Queuing Telemetry Transport) es un protocolo de mensajería ligero basado en el patrón publish/subscribe, diseñado para entornos con ancho de banda limitado, alta latencia o dispositivos con recursos restringidos. Fue creado por IBM en 1999 y estandarizado por OASIS en 2014 (v3.1.1) y 2019 (v5.0).

Opera sobre TCP/IP y su overhead es mínimo: la cabecera fija tiene solo 2 bytes, lo que lo hace ideal para redes celulares (LTE/4G), conexiones satelitales o enlaces serie.

2. Arquitectura MQTT: Componentes Clave

La arquitectura MQTT se basa en tres actores principales:

Componentes:

  • Broker: servidor central que recibe, filtra y distribuye mensajes. Nunca procesa el contenido.
  • Publisher: cliente que publica mensajes en un topic.
  • Subscriber: cliente que se suscribe a uno o más topics y recibe los mensajes.
  • Topic: cadena jerárquica que actúa como canal de enrutamiento (ej. factory/line1/temperature).

3. Conceptos Fundamentales

3.1 Topics y Wildcards

Los topics son cadenas UTF-8 separadas por /. Los suscriptores pueden usar comodines:

  • + → un nivel (ej. factory/+/temp captura factory/line1/temp y factory/line2/temp)
  • # → todos los niveles restantes (ej. factory/#)

3.2 Quality of Service (QoS)

NivelNombreGarantíaUso típico
QoS 0At most onceSin confirmación, puede perderseTelemetría no crítica
QoS 1At least onceConfirmado, puede duplicarseAlarmas, eventos
QoS 2Exactly onceEntrega exacta, mayor overheadTransacciones críticas

3.3 Retain y Clean Session

  • Retain flag: el broker almacena el último mensaje de un topic. Un nuevo suscriptor lo recibe inmediatamente al conectarse.
  • Clean Session = false: el broker persiste las suscripciones y mensajes QoS 1/2 pendientes entre reconexiones. Esencial para dispositivos móviles o con conectividad intermitente.
  • Last Will and Testament (LWT): mensaje que el broker publica automáticamente si el cliente se desconecta de forma inesperada.

4. Ejemplos de Código Python

4.1 Publisher básico con paho-mqtt

import paho.mqtt.client as mqtt
import json
import time

BROKER = "broker.hivemq.com"
PORT = 1883
TOPIC = "factory/line1/temperature"

client = mqtt.Client(client_id="teltonika-rut955-01", clean_session=False)
client.username_pw_set("user", "password")

# Last Will Testament: notifica desconexión inesperada
client.will_set(
    topic="factory/line1/status",
    payload=json.dumps({"status": "offline", "device": "RUT955-01"}),
    qos=1,
    retain=True
)

client.connect(BROKER, PORT, keepalive=60)
client.loop_start()

payload = {
    "device_id": "RUT955-01",
    "timestamp": int(time.time()),
    "temperature": 72.4,
    "unit": "celsius",
    "location": "factory/line1"
}

# Publicar con QoS 1 y retain=True
result = client.publish(
    topic=TOPIC,
    payload=json.dumps(payload),
    qos=1,
    retain=True
)
result.wait_for_publish()
print(f"[OK] Publicado en {TOPIC}: {json.dumps(payload, indent=2)}")

client.loop_stop()
client.disconnect()

4.2 Subscriber con callback y wildcards

import paho.mqtt.client as mqtt
import json

def on_connect(client, userdata, flags, rc):
    codes = {0: "Conectado", 1: "Versión incorrecta", 5: "No autorizado"}
    print(f"Conexión: {codes.get(rc, f'Error {rc}')}")
    # Suscribirse a todos los sensores de la fábrica
    client.subscribe("factory/#", qos=1)

def on_message(client, userdata, msg):
    try:
        data = json.loads(msg.payload.decode())
        print(f"[{msg.topic}] QoS={msg.qos} Retain={msg.retain}")
        print(f"  device_id : {data.get('device_id')}")
        print(f"  timestamp : {data.get('timestamp')}")
        print(f"  value     : {data.get('temperature')} {data.get('unit','')}")
    except json.JSONDecodeError:
        print(f"Payload no JSON: {msg.payload}")

client = mqtt.Client(client_id="dashboard-subscriber-01", clean_session=False)
client.on_connect = on_connect
client.on_message = on_message

client.connect("broker.hivemq.com", 1883, keepalive=60)
client.loop_forever()  # Bloquea y procesa mensajes indefinidamente

4.3 Publicación con TLS/SSL y QoS 2

import paho.mqtt.client as mqtt
import ssl, json, time

client = mqtt.Client(client_id="rubustel-r2000-secure")

# Configurar TLS con certificados de cliente
client.tls_set(
    ca_certs="/etc/mqtt/ca.crt",
    certfile="/etc/mqtt/client.crt",
    keyfile="/etc/mqtt/client.key",
    tls_version=ssl.PROTOCOL_TLSv1_2
)
client.tls_insecure_set(False)

client.connect("mqtt.empresa.com", 8883, keepalive=30)

payload = {
    "device": "R2000-EDGE-07",
    "ts": int(time.time()),
    "gps": {"lat": 40.4168, "lon": -3.7038},
    "signal": {"rssi": -78, "technology": "LTE"},
    "io": {"din1": True, "dout1": False, "analog1": 3.3}
}

# QoS 2: entrega exactamente una vez (crítico para comandos)
client.publish(
    topic="fleet/truck007/telemetry",
    payload=json.dumps(payload),
    qos=2
)
client.loop(timeout=5.0)
client.disconnect()
print("Publicado con QoS 2 sobre TLS")

5. Escenarios de Uso en IoT

A continuación se presentan tres escenarios reales con arquitectura MQTT:

6. Implementaciones Gratuitas de MQTT

ImplementaciónVersión MQTTLicenciaConexiones máx.ClusteringPersistenciaIdeal para
Eclipse Mosquitto3.1.1 / 5.0EPL 2.0 (Open Source)~100k (single node)❌ No nativoArchivos planosDesarrollo, edge, Raspberry Pi
EMQ X (EMQX) CE3.1.1 / 5.0Apache 2.01M+ por nodo✅ Sí (Erlang)PostgreSQL/MySQLProducción, alta escala
HiveMQ CE3.1.1Apache 2.0~25k❌ LimitadoEn memoriaPruebas, desarrollo Java
VerneMQ3.1.1 / 5.0Apache 2.01M+✅ Sí (Erlang)LevelDBAlternativa a EMQX
NanoMQ3.1.1 / 5.0MIT~100k❌ NoSQLiteEdge computing, IoT embebido

Recomendación práctica: Para entornos de producción con >10k dispositivos, usa EMQX CE. Para desarrollo local y edge, Mosquitto es la opción más ligera y documentada.

7. Configuración en Routers Teltonika y Rubustel

7.1 Teltonika RUT955 — Configuración vía UCI (OpenWrt)

El RUT955 incluye un cliente MQTT nativo basado en mosquitto_pub. La configuración se realiza desde la WebUI o por SSH:

# Acceso SSH al router
ssh root@192.168.1.1

# Instalar cliente MQTT si no está disponible
opkg update && opkg install mosquitto-client-ssl

# Publicar telemetría manualmente (prueba)
mosquitto_pub \
  -h "mqtt.empresa.com" \
  -p 8883 \
  --cafile /etc/ssl/ca.crt \
  -u "rut955-user" \
  -P "secretpassword" \
  -t "factory/line1/rut955/telemetry" \
  -m '{"device":"RUT955-01","ts":1700000000,"temp":72.4}' \
  -q 1 \
  --retain

Configuración persistente en /etc/config/mqtt (UCI):

uci set mqtt.@mqtt[0].enabled='1'
uci set mqtt.@mqtt[0].broker='mqtt.empresa.com'
uci set mqtt.@mqtt[0].port='8883'
uci set mqtt.@mqtt[0].topic='factory/line1/rut955/telemetry'
uci set mqtt.@mqtt[0].qos='1'
uci set mqtt.@mqtt[0].tls='1'
uci set mqtt.@mqtt[0].cafile='/etc/ssl/ca.crt'
uci set mqtt.@mqtt[0].interval='30'  # segundos entre publicaciones
uci commit mqtt
/etc/init.d/mqtt restart

7.2 Rubustel R2000 — Configuración vía WebUI / CLI

El R2000 soporta MQTT nativo desde el firmware 3.x. Configuración por CLI:

# Conectar por SSH
ssh admin@192.168.1.1

# Configurar cliente MQTT
set mqtt broker_address mqtt.empresa.com
set mqtt broker_port 8883
set mqtt client_id R2000-EDGE-07
set mqtt username rubustel-user
set mqtt password secretpassword
set mqtt tls enable
set mqtt ca_cert /etc/ssl/ca.crt
set mqtt publish_topic fleet/truck007/telemetry
set mqtt publish_interval 30
set mqtt qos 1
set mqtt retain enable
commit

7.3 Payload JSON de Ejemplo — Teltonika RUT955

{
  "device_id": "RUT955-01",
  "firmware": "RUT9_R_00.07.04.5",
  "timestamp": 1700000000,
  "uptime_sec": 86400,
  "network": {
    "wan_ip": "203.0.113.45",
    "technology": "LTE",
    "operator": "Vodafone ES",
    "rssi_dbm": -78,
    "rsrp_dbm": -95,
    "signal_bars": 3
  },
  "system": {
    "cpu_load_pct": 12,
    "ram_free_mb": 48,
    "temperature_c": 42
  },
  "io": {
    "din1": false,
    "din2": true,
    "dout1": false,
    "analog_in_v": 12.4
  },
  "gps": {
    "lat": 40.4168,
    "lon": -3.7038,
    "alt_m": 667,
    "speed_kmh": 0,
    "fix": true
  }
}

7.4 Payload JSON de Ejemplo — Rubustel R2000

{
  "device": "R2000-EDGE-07",
  "model": "Rubustel R2000-4L",
  "ts": 1700000000,
  "connection": {
    "type": "4G",
    "apn": "internet.empresa.com",
    "rssi": -82,
    "lac": "1A2B",
    "cell_id": "3C4D5E"
  },
  "serial_data": {
    "port": "RS485",
    "protocol": "Modbus RTU",
    "register_40001": 724,
    "register_40002": 1013
  },
  "alarms": {
    "power_loss": false,
    "high_temp": false,
    "link_down": false
  }
}

8. Flujo de Conexión MQTT — Diagrama de Secuencia

9. Buenas Prácticas y Consideraciones de Seguridad

  • Autenticación: usa siempre usuario/contraseña o certificados X.509. Nunca dejes el broker sin autenticación en producción.
  • TLS obligatorio: puerto 8883 para conexiones cifradas. El puerto 1883 (sin TLS) solo para redes aisladas.
  • Diseño de topics: usa jerarquías claras: {organización}/{sitio}/{dispositivo}/{tipo_dato}. Evita topics genéricos como data o sensor.
  • QoS adecuado: no uses QoS 2 por defecto; el overhead de 4 mensajes por publicación puede saturar redes lentas.
  • ACLs en el broker: restringe qué clientes pueden publicar/suscribirse a qué topics. Un sensor no debería poder suscribirse a comandos de otros dispositivos.
  • Monitorización: suscríbete a $SYS/# en Mosquitto para métricas del broker (conexiones activas, mensajes/segundo, bytes transferidos).

10. Resumen

MQTT es el protocolo de facto para IoT industrial gracias a su eficiencia, flexibilidad y soporte de patrones asíncronos. La combinación de routers industriales (Teltonika RUT955, Rubustel R2000) como publishers de telemetría, brokers robustos (EMQX, Mosquitto) y payloads JSON estructurados permite construir arquitecturas escalables, resilientes y seguras para cualquier caso de uso: desde monitorización de planta hasta flotas vehiculares y smart grids.