MQTT es un protocolo ligero de mensajería para dispositivos IoT y conexiones poco estables.
Cuando queremos conectar un dispositivo a internet, nuestro primer instinto suele ser usar peticiones HTTP (GET/POST), como vimos en el capítulo anterior.
Pero HTTP es un protocolo “pesado” y “verboso”. Está pensado para documentos grandes. Para un sensor que solo quiere decir “estoy a 25°C”, HTTP es como enviar una carta certificada en un camión blindado solo para decir “Hola”.
Para el Internet de las Cosas (IoT), una de las opciones más usadas es MQTT (Message Queuing Telemetry Transport).
Sus ventajas son claras:
- Ligero: Cabeceras minúsculas (2 bytes).
- Rápido: Latencia casi instantánea.
- Modelo Pub/Sub: Desacopla al que envía del que recibe.
Arquitectura: broker y publicación/suscripción
En MQTT, los dispositivos no se conectan entre sí. No hay una conexión directa entre tu sensor de temperatura y tu móvil.
En su lugar, existe una figura central llamada Broker.
- El Broker: Es el “servidor de correo” o “tablón de anuncios”. Su único trabajo es recibir mensajes y repartirlos a quien le interese. (Ejemplos: Mosquitto, HiveMQ, EMQX).
- Publicar (Publish): Un dispositivo envía un mensaje a un Tema (Topic). Ej: “El sensor publica
25en el temacasa/salon/temperatura”. - Suscribirse (Subscribe): Un dispositivo le dice al Broker: “Avísame cada vez que llegue algo al tema
casa/salon/temperatura”.
El sensor publica, el Broker recibe y reenvía el mensaje inmediatamente a tu móvil (que estaba suscrito). El sensor no sabe ni le importa quién lo está escuchando.
La librería umqtt.simple
El repositorio oficial micropython-lib ofrece una implementación ligera llamada umqtt.simple. No todos los firmwares la incluyen, así que conviene comprobarlo antes de importar el módulo.
Si no está instalada, puedes añadirla mediante mip desde una placa con red o mediante mpremote desde el ordenador:
import mip
mip.install("umqtt.simple")
mpremote mip install umqtt.simplePublicar datos
Vamos a configurar nuestro microcontrolador para que envíe un dato cada 5 segundos.
Para este ejemplo usaremos un broker público gratuito (broker.hivemq.com o test.mosquitto.org), así no necesitas instalar nada en tu PC.
import network
import time
from machine import unique_id
from ubinascii import hexlify
from umqtt.simple import MQTTClient
# 1. Configuración de Red (Asumimos que ya estás conectado al WiFi)
# ... (código de conexión WiFi visto en capítulos anteriores) ...
# 2. Configuración MQTT
mqtt_server = "broker.hivemq.com"
client_id = hexlify(unique_id()) # Generamos ID único basado en la MAC
topic_pub = b"luisllamas/curso/temp"
def conectar_mqtt():
try:
print(f"Conectando a Broker {mqtt_server}...")
client = MQTTClient(client_id, mqtt_server)
client.connect()
print("¡Conectado!")
return client
except OSError as e:
print("Error al conectar. Reiniciando...")
time.sleep(5)
machine.reset()
# 3. Programa Principal
client = conectar_mqtt()
while True:
try:
# Simulamos una lectura de sensor
mensaje = b"25.4"
print(f"Publicando {mensaje} en {topic_pub}")
# Publicamos el mensaje
client.publish(topic_pub, mensaje)
time.sleep(5)
except OSError as e:
print("Error en el bucle, intentando reconectar...")
client = conectar_mqtt()
Para comprobarlo puedes usar en tu PC un cliente como MQTT Explorer y suscribirte al tema luisllamas/curso/temp. Los datos llegarán al instante.
Suscribirse a comandos
Ahora queremos lo contrario: controlar un LED desde fuera. Nuestra placa se suscribirá al tema luisllamas/curso/luz.
Aquí la lógica cambia un poco. Necesitamos una función Callback. Esta función es la que se ejecutará automáticamente cuando llegue un mensaje.
from machine import Pin
from umqtt.simple import MQTTClient
import ubinascii
import machine
import time
# LED en el pin 2
led = Pin(2, Pin.OUT)
mqtt_server = "broker.hivemq.com"
client_id = ubinascii.hexlify(machine.unique_id())
topic_sub = b"luisllamas/curso/luz"
# --- La función Callback ---
# Esta función se llama cuando llega un mensaje
def sub_cb(topic, msg):
print(f"Mensaje recibido en {topic}: {msg}")
if msg == b"ON":
led.value(1)
print("LED Encendido")
elif msg == b"OFF":
led.value(0)
print("LED Apagado")
def conectar_y_suscribir():
client = MQTTClient(client_id, mqtt_server)
# IMPORTANTE: Asignar el callback antes de conectar
client.set_callback(sub_cb)
client.connect()
client.subscribe(topic_sub)
print(f"Suscrito a: {topic_sub}")
return client
# --- Bucle Principal ---
client = conectar_y_suscribir()
while True:
try:
# check_msg() comprueba si hay mensajes nuevos en el buffer
# Si hay, llama automáticamente a sub_cb()
# Es NO BLOQUEANTE (si no hay nada, sigue rápido)
client.check_msg()
# Aquí podemos hacer otras cosas mientras escuchamos...
time.sleep(0.1)
except OSError:
print("Desconexión detectada. Reconectando...")
client = conectar_y_suscribir()
check_msg() vs wait_msg()
Este es un punto crítico donde muchos fallan:
client.wait_msg(): Es bloqueante. El programa se detiene ahí y no hace NADA MÁS hasta que llegue un mensaje. Útil si solo esperas órdenes.client.check_msg(): Es no bloqueante. Mira si hay algo; si no, sigue. Es lo que debes usar si quieres parpadear un LED o leer sensores mientras esperas órdenes MQTT.
QoS: calidad de servicio
MQTT permite definir con qué fiabilidad queremos entregar el mensaje. En umqtt.simple podemos especificarlo, aunque el Broker también debe soportarlo.
- QoS 0 (At most once): Dispara y olvida. Si se pierde, se perdió. Es el más rápido.
- QoS 1 (At least once): Garantiza que llega, pero puede llegar duplicado. Requiere confirmación (ACK).
# Publicar con QoS 1
client.publish(topic, mensaje, qos=1)
Mensajes retenidos
Imagina que el sensor publica la temperatura cada hora. Si conectas el móvil cinco minutos después de la publicación, ¿tienes que esperar otros 55 minutos para conocerla?
No si usas el flag Retain.
Si publicas con retain=True, el Broker guarda el último mensaje de ese tema. Cualquier dispositivo nuevo que se suscriba recibirá inmediatamente ese último valor guardado.
# En umqtt.simple, publish(topic, msg, retain=False, qos=0)
client.publish(topic_pub, b"ON", retain=True)
Con MQTT, ya no tenemos dispositivos aislados, sino un ecosistema conectado en tiempo real. Es la base para crear paneles en Home Assistant, Node-RED o tu propia aplicación.