Correo: [email protected] - Teléfono: +56979962128

Esta es una guía completa para usar MQTT con Raspberry Pi Pico, programada con MicroPython. MQTT es un protocolo de comunicación ampliamente utilizado en aplicaciones de domótica e IoT para conectar múltiples dispositivos. En este tutorial, aprenderá a elegir y configurar un broker MQTT y a publicar y suscribirse a mensajes MQTT con Raspberry Pi Pico.

 

Raspberry Pi Pico: Introducción a MQTT MicroPython

 

 

Prerrequisitos

Antes de continuar, asegúrese de verificar los siguientes requisitos previos:

Firmware de MicroPython

Para seguir este tutorial, necesitas tener instalado el firmware MicroPython en tu placa Raspberry Pi Pico. También necesitas un IDE para escribir y cargar el código en la placa.

El IDE de MicroPython recomendado para Raspberry Pi Pico es Thonny IDE.

 

Presentamos MQTT

MQTT significa Transporte de Telemetría de Cola de Mensajes. MQTT es un protocolo de mensajería simple diseñado para dispositivos con limitaciones de ancho de banda. Por lo tanto, es la solución ideal para intercambiar datos entre múltiples dispositivos IoT. La comunicación MQTT funciona como un  sistema de publicación  y  suscripción  . Los dispositivos pueden publicar mensajes sobre un tema específico. Todos los dispositivos  suscritos  a ese tema reciben el mensaje.

 

MQTT Publicar Suscribirse

 

Sus principales aplicaciones incluyen el envío de mensajes para controlar salidas, la lectura y publicación de datos desde nodos de sensores y mucho más.

 

Conceptos básicos de MQTT

En MQTT, hay algunos conceptos básicos que debes comprender:

  • Publicar/Suscribirse
  • Mensajes
  • Temas
  • Corredor

 

Publicar/Suscribirse

El primer concepto es el sistema de publicación y suscripción  . En un sistema de publicación y suscripción, un dispositivo puede publicar un mensaje sobre un tema o suscribirse a un tema específico para recibir mensajes. 

 

Publicar Suscribirse Tema MQTT

 

  • Por ejemplo,  el Dispositivo 1  publica sobre un tema;
  • El dispositivo 2  está suscrito al mismo tema   en el que publica el dispositivo 1 ;
  • Entonces,  el dispositivo 2  recibe el mensaje.

 

Mensajes MQTT

Los mensajes son la información que deseas intercambiar entre tus dispositivos.
Pueden ser mensajes como un comando para controlar una salida o datos como lecturas de sensores.

Temas (Topics)

Otro concepto importante son los temas.
Los temas son la forma de registrar interés en los mensajes entrantes o de especificar dónde quieres publicar un mensaje.

Los temas se representan con cadenas de texto separadas por una barra diagonal (/).
Cada barra diagonal indica un nivel del tema.

Por ejemplo, así crearías un tema para una lámpara en tu oficina en casa:

MQTT topic name examples

Nota: los temas (topics) distinguen entre mayúsculas y minúsculas, lo que hace que los siguientes temas sean diferentes entre sí.

MQTT topic name examples and differences

Si quisieras encender una lámpara en tu oficina en casa usando MQTT, puedes imaginar el siguiente escenario:

Raspberry Pi Pico Subscribe to MQTT Topics Example

Un dispositivo publica mensajes de encendido y apagado en el tema home/office/lamp.
Tienes un dispositivo que controla una lámpara (puede ser tu Raspberry Pi Pico u otra placa o dispositivo).
La Pico, que controla tu lámpara, está suscrita a ese mismo tema: home/office/lamp.

Entonces, cuando se publica un nuevo mensaje en ese tema, la Pico recibe los mensajes de on o off y enciende o apaga la lámpara.

El dispositivo que publica los mensajes puede ser otra placa microcontroladora, o una plataforma de automatización del hogar con soporte MQTT, como Node-RED, Home Assistant, Adafruit IO, Domoticz o OpenHAB, por ejemplo.

Broker

Finalmente, otro concepto importante es el broker.

El broker MQTT es responsable de recibir todos los mensajes, filtrarlos, decidir quién está interesado en ellos y luego publicar el mensaje a todos los clientes suscritos.

MQTT Broker overview and how it works

Existen varios brokers que puedes usar. Por ejemplo:

  • Brokers MQTT en la nube: puedes usar soluciones comerciales de broker MQTT como HiveMQ, por ejemplo. No necesitas configurar nada; solo crear una cuenta y listo (este es el que usaremos en este tutorial).

  • Broker MQTT local: puedes instalar un broker MQTT localmente en tu computadora o en tu Raspberry Pi. El broker Mosquitto MQTT alojado en una Raspberry Pi se usa ampliamente en muchos proyectos de hobby, y es la solución que más usamos.

  • Broker MQTT en la nube propio: como alternativa, también puedes instalar un broker MQTT en tu propio servidor en la nube.

En resumen:

  • MQTT es un protocolo de comunicación muy útil en proyectos de Internet de las Cosas (IoT).

  • En MQTT, los dispositivos pueden publicar mensajes en temas específicos y suscribirse a temas para recibir mensajes.

  • Necesitas un broker al usar MQTT. Este recibe todos los mensajes y los envía a los dispositivos suscritos.

Configuración del Broker MQTT

Para usar MQTT, necesitas un broker MQTT. El broker recibe todos los mensajes MQTT y los envía a todos los clientes suscritos.

Soluciones de Broker MQTT

Existen muchas soluciones de broker MQTT que puedes usar. Aquí describimos las que conocemos mejor:

  • Mosquitto MQTT broker instalado en una Raspberry Pi: este es un broker MQTT open-source que puedes instalar localmente en tu Raspberry Pi (la computadora Raspberry Pi, no la placa Pico). Hemos usado esta opción muchas veces y siempre ha funcionado bien.

  • Mosquitto MQTT broker en un servidor en la nube: una excelente alternativa si quieres que tu broker sea accesible desde cualquier lugar del mundo.

  • HiveMQ Broker: es un servicio de broker MQTT en la nube. Solo necesitas crear una cuenta y elegir un plan. Proporcionan un plan gratuito que es suficiente para la mayoría de proyectos IoT de hobby.

Para simplificar, en esta guía usaremos HiveMQ, porque no necesitas instalar ni configurar nada como con Mosquitto. Solo creas una cuenta, configuras un clúster y estás listo para empezar.
Si prefieres usar Mosquitto u otro broker, no hay problema; el código será compatible mientras ingreses los detalles correctos del broker.

Independientemente del broker MQTT que uses, necesitas tener la URL del broker, el usuario y la contraseña antes de continuar con las siguientes secciones.

Configuración del Broker HiveMQ MQTT

En esta sección te mostraremos cómo configurar tu broker HiveMQ MQTT:

  1. Primero, necesitas crear una cuenta. Ve a hivemq.com y haz clic en Start free.

  2. Elige el plan HiveMQ Cloud.

    HiveMQ MQTT broker different plans

  3. Inicia sesión o crea una nueva cuenta y completa los datos para terminar de configurar tu perfil.

  4. Deberías tener un nuevo clúster creado por defecto. Haz clic en Manage Cluster

    HiveMQ Manage Cluster

  5. Copia la URL del clúster en un lugar seguro, porque la necesitarás más adelante.

    HiveMQ Cluster URL

  6. Haz clic en la pestaña Access Management en la parte superior.
  7. Completa el formulario con un nombre de usuario y contraseña. Necesitarás recordar estos datos más adelante para conectarte al broker MQTT. Configura el permiso en Publish and Subscribe (Publicar y Suscribirse).
  8. Finalmente, haz clic en Create Credential (Crear credencial).

 

HiveMQ Access Management

 

Si tus credenciales se crearon correctamente, tu broker MQTT ya está configurado.

username and permission hivemq

Asegúrate de tener la siguiente información antes de continuar con la siguiente sección:

  • Servidor MQTT:

    • URL del clúster (si usas HiveMQ)

    • Dirección IP o URL del broker MQTT (si usas un broker diferente)

  • Usuario MQTT

  • Contraseña MQTT

 

 

Instalando los módulos MQTT para MicroPython

Para escribir código en MicroPython y usar el protocolo de comunicación MQTT, utilizaremos dos módulos MQTT: umqtt.simple.py y umqtt.robust.py.

Sigue los siguientes pasos para subir los módulos a tu Raspberry Pi Pico: Con la Raspberry Pi Pico conectada a tu computadora y con la conexión establecida en Thonny IDE, ve a View > Files (Vista > Archivos).

Thonny IDE View Files

Aparecerá una nueva barra lateral con todos los archivos del sistema de archivos de la Raspberry Pi Pico.

Haz clic derecho en la barra lateral de la Raspberry Pi Pico y selecciona New directory… (Nuevo directorio…).

Este nuevo directorio debe llamarse umqtt. Haz clic en Ok.

Thonny IDE cerating umqtt folder

El nuevo directorio aparecerá en la barra lateral izquierda.

Thonny IDE cerating umqtt folder

Haz clic derecho en la carpeta umqtt y selecciona New file… (Nuevo archivo…).

Este nuevo archivo debe llamarse simple.py.

Thonny IDE Creating umqtt file

Aquí tienes la traducción fiel y ordenada al español:

Copia el código de simple.py en ese nuevo archivo. El código se puede encontrar en el siguiente enlace:

Haz clic aquí para descargar simple.py

# forked from: https://github.com/micropython/micropython-lib/tree/master/micropython/umqtt.simple
import usocket as socket
import ustruct as struct
from ubinascii import hexlify


class MQTTException(Exception):
    pass


class MQTTClient:
    def __init__(
        self,
        client_id,
        server,
        port=0,
        user=None,
        password=None,
        keepalive=0,
        ssl=False,
        ssl_params={},
    ):
        if port == 0:
            port = 8883 if ssl else 1883
        self.client_id = client_id
        self.sock = None
        self.server = server
        self.port = port
        self.ssl = ssl
        self.ssl_params = ssl_params
        self.pid = 0
        self.cb = None
        self.user = user
        self.pswd = password
        self.keepalive = keepalive
        self.lw_topic = None
        self.lw_msg = None
        self.lw_qos = 0
        self.lw_retain = False

    def _send_str(self, s):
        self.sock.write(struct.pack("!H", len(s)))
        self.sock.write(s)

    def _recv_len(self):
        n = 0
        sh = 0
        while 1:
            b = self.sock.read(1)[0]
            n |= (b & 0x7F) << sh
            if not b & 0x80:
                return n
            sh += 7

    def set_callback(self, f):
        self.cb = f

    def set_last_will(self, topic, msg, retain=False, qos=0):
        assert 0 <= qos <= 2
        assert topic
        self.lw_topic = topic
        self.lw_msg = msg
        self.lw_qos = qos
        self.lw_retain = retain

    def connect(self, clean_session=True):
        self.sock = socket.socket()
        addr = socket.getaddrinfo(self.server, self.port)[0][-1]
        self.sock.connect(addr)
        if self.ssl:
            import ssl

            self.sock = ssl.wrap_socket(self.sock, **self.ssl_params)
        premsg = bytearray(b"x10")
        msg = bytearray(b"x04MQTTx04x02")

        sz = 10 + 2 + len(self.client_id)
        msg[6] = clean_session << 1
        if self.user is not None:
            sz += 2 + len(self.user) + 2 + len(self.pswd)
            msg[6] |= 0xC0
        if self.keepalive:
            assert self.keepalive < 65536
            msg[7] |= self.keepalive >> 8
            msg[8] |= self.keepalive & 0x00FF
        if self.lw_topic:
            sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg)
            msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3
            msg[6] |= self.lw_retain << 5

        i = 1
        while sz > 0x7F:
            premsg[i] = (sz & 0x7F) | 0x80
            sz >>= 7
            i += 1
        premsg[i] = sz

        self.sock.write(premsg, i + 2)
        self.sock.write(msg)
        # print(hex(len(msg)), hexlify(msg, ":"))
        self._send_str(self.client_id)
        if self.lw_topic:
            self._send_str(self.lw_topic)
            self._send_str(self.lw_msg)
        if self.user is not None:
            self._send_str(self.user)
            self._send_str(self.pswd)
        resp = self.sock.read(4)
        assert resp[0] == 0x20 and resp[1] == 0x02
        if resp[3] != 0:
            raise MQTTException(resp[3])
        return resp[2] & 1

    def disconnect(self):
        self.sock.write(b"xe0")
        self.sock.close()

    def ping(self):
        self.sock.write(b"xc0")

    def publish(self, topic, msg, retain=False, qos=0):
        pkt = bytearray(b"x30")
        pkt[0] |= qos << 1 | retain
        sz = 2 + len(topic) + len(msg)
        if qos > 0:
            sz += 2
        assert sz < 2097152
        i = 1
        while sz > 0x7F:
            pkt[i] = (sz & 0x7F) | 0x80
            sz >>= 7
            i += 1
        pkt[i] = sz
        # print(hex(len(pkt)), hexlify(pkt, ":"))
        self.sock.write(pkt, i + 1)
        self._send_str(topic)
        if qos > 0:
            self.pid += 1
            pid = self.pid
            struct.pack_into("!H", pkt, 0, pid)
            self.sock.write(pkt, 2)
        self.sock.write(msg)
        if qos == 1:
            while 1:
                op = self.wait_msg()
                if op == 0x40:
                    sz = self.sock.read(1)
                    assert sz == b"x02"
                    rcv_pid = self.sock.read(2)
                    rcv_pid = rcv_pid[0] << 8 | rcv_pid[1]
                    if pid == rcv_pid:
                        return
        elif qos == 2:
            assert 0

    def subscribe(self, topic, qos=0):
        assert self.cb is not None, "Subscribe callback is not set"
        pkt = bytearray(b"x82")
        self.pid += 1
        struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)
        # print(hex(len(pkt)), hexlify(pkt, ":"))
        self.sock.write(pkt)
        self._send_str(topic)
        self.sock.write(qos.to_bytes(1, "little"))
        while 1:
            op = self.wait_msg()
            if op == 0x90:
                resp = self.sock.read(4)
                # print(resp)
                assert resp[1] == pkt[2] and resp[2] == pkt[3]
                if resp[3] == 0x80:
                    raise MQTTException(resp[3])
                return

    # Wait for a single incoming MQTT message and process it.
    # Subscribed messages are delivered to a callback previously
    # set by .set_callback() method. Other (internal) MQTT
    # messages processed internally.
    def wait_msg(self):
        res = self.sock.read(1)
        self.sock.setblocking(True)
        if res is None:
            return None
        if res == b"":
            raise OSError(-1)
        if res == b"xd0":  # PINGRESP
            sz = self.sock.read(1)[0]
            assert sz == 0
            return None
        op = res[0]
        if op & 0xF0 != 0x30:
            return op
        sz = self._recv_len()
        topic_len = self.sock.read(2)
        topic_len = (topic_len[0] << 8) | topic_len[1]
        topic = self.sock.read(topic_len)
        sz -= topic_len + 2
        if op & 6:
            pid = self.sock.read(2)
            pid = pid[0] << 8 | pid[1]
            sz -= 2
        msg = self.sock.read(sz)
        self.cb(topic, msg)
        if op & 6 == 2:
            pkt = bytearray(b"x40x02")
            struct.pack_into("!H", pkt, 2, pid)
            self.sock.write(pkt)
        elif op & 6 == 4:
            assert 0
        return op

    # Checks whether a pending message from server is available.
    # If not, returns immediately with None. Otherwise, does
    # the same processing as wait_msg.
    def check_msg(self):
        self.sock.setblocking(False)
        return self.wait_msg()
 

 

Después de copiar el código en el archivo robust.py, guarda el código. En este momento, deberías tener la carpeta umqtt con los archivos simple.py .

 

Thonny IDE simple.py file created

 

 

Haz clic derecho nuevamente sobre la carpeta umqtt y crea otro archivo seleccionando New file…

Ese nuevo archivo debe llamarse robust.py.

create robust.py thonny ide mqtt

Copia el código de robust.py dentro de ese nuevo archivo. El código lo puedes encontrar en el siguiente enlace:

👉 Descargar robust.py

# forked from: https://github.com/micropython/micropython-lib/tree/master/micropython/umqtt.robust
import utime
from . import simple


class MQTTClient(simple.MQTTClient):
    DELAY = 2
    DEBUG = False

    def delay(self, i):
        utime.sleep(self.DELAY)

    def log(self, in_reconnect, e):
        if self.DEBUG:
            if in_reconnect:
                print("mqtt reconnect: %r" % e)
            else:
                print("mqtt: %r" % e)

    def reconnect(self):
        i = 0
        while 1:
            try:
                return super().connect(False)
            except OSError as e:
                self.log(True, e)
                i += 1
                self.delay(i)

    def publish(self, topic, msg, retain=False, qos=0):
        while 1:
            try:
                return super().publish(topic, msg, retain, qos)
            except OSError as e:
                self.log(False, e)
            self.reconnect()

    def wait_msg(self):
        while 1:
            try:
                return super().wait_msg()
            except OSError as e:
                self.log(False, e)
            self.reconnect()

    def check_msg(self, attempts=2):
        while attempts:
            self.sock.setblocking(False)
            try:
                return super().wait_msg()
            except OSError as e:
                self.log(False, e)
            self.reconnect()
            attempts -= 1
 

 

Después de copiar el código en el archivo robust.py, guarda el archivo.

En este punto, deberías tener la carpeta umqtt con los siguientes archivos dentro:

  • simple.py

  • robust.py

 

MQTT MicroPython modules Thonny IDE

Los módulos requeridos para MQTT se cargaron correctamente en la Raspberry Pi Pico.

Crear un archivo de configuración

Crearemos un archivo de configuración para guardar el SSID, la contraseña y los detalles de tu broker MQTT: URL, usuario y contraseña.

Crea un nuevo archivo llamado config.py en Thonny IDE y copia el siguiente código:

wifi_ssid = 'REPLACE_WITH_YOUR_SSID'
wifi_password = 'REPLACE_WITH_YOUR_PASSWORD'
mqtt_server = b'MQTT_BROKER_URL'
mqtt_username = b'BROKER_USERNAME'
mqtt_password = b'BROKER_PASSWORD'

Reemplaza las variables con tus propios datos.

Si estás usando un broker Mosquitto MQTT local, debes ingresar la dirección IP del broker sin el puerto. Por ejemplo:

mqtt_server = b'192.168.1.79'

Luego, ve a File > Save as… (Archivo > Guardar como…) y selecciona Raspberry Pi Pico. Guarda el archivo como config.py (sobrescribe cualquier archivo existente con el mismo nombre). Este archivo debe guardarse en la raíz de la Raspberry Pi Pico, y no dentro de la carpeta umqtt.

 

 

Publicando mensajes MQTT

En este ejemplo, aprenderás a publicar mensajes MQTT en un tema específico con tu Raspberry Pi Pico.

Como ejemplo, publicaremos las lecturas de temperatura, humedad y presión de un sensor BME280.
De manera alternativa, puedes usar cualquier otro sensor o valores aleatorios para probar el proyecto y los conceptos.

Antes de continuar, asegúrate de que:

  • Conectes un sensor BME280 a la Raspberry Pi Pico. Usa GPIO 4 (SDA) y GPIO 5 (SCL).

  • Subas el módulo BME280.py para controlar el BME280 con tu Raspberry Pi Pico — revisa este tutorial e instala la librería como allí se indica.

 

El siguiente código obtiene los datos del sensor BME280 y publica las lecturas en diferentes temas (topics) MQTT.

 

def publish_mqtt(topic, value):
    client.publish(topic, value)
    print(topic)
    print(value)
    print("Publish Done")

try:
    if not initialize_wifi(config.wifi_ssid, config.wifi_password):
        print('Error connecting to the network... exiting program')
    else:
        # Connect to MQTT broker, start MQTT client
        client = connect_mqtt()
        while True:
            # Read sensor data
            temperature, humidity, pressure = get_sensor_readings()

            # Publish as MQTT payload
            publish_mqtt(MQTT_TOPIC_TEMPERATURE, str(temperature))
            publish_mqtt(MQTT_TOPIC_PRESSURE, str(pressure))
            publish_mqtt(MQTT_TOPIC_HUMIDITY, str(humidity))

            # Delay 10 seconds
            sleep(10)

except Exception as e:
    print('Error:', e)
 

 

Cómo funciona el código

Usamos los siguientes temas MQTT para publicar datos:

  • Para la temperatura — pico/temperature

  • Para la humedad — pico/humidity

  • Para la presión — pico/pressure

El flujo de trabajo para publicar datos es el siguiente:

  1. Conectar la Pico a internet.

  2. Conectarse al broker MQTT.

  3. Después de conectarse al broker, podemos publicar mensajes MQTT de manera continua.

 

Importando librerías

Primero, necesitamos importar las librerías requeridas.
Importamos Pin e I2C del módulo machine, y BME280 para interactuar con el sensor BME280.
El módulo network para conectarnos a Wi-Fi y la clase MQTTClient de umqtt.simple para usar funciones MQTT.

from machine import Pin, I2C
from time import sleep
import network
from umqtt.simple import MQTTClient
import config 
import BME280

 

Temas MQTT

En las siguientes variables guardamos los temas donde queremos publicar nuestros mensajes (lecturas de sensores).

# Constantes para los temas MQTT 
MQTT_TOPIC_TEMPERATURE = 'pico/temperature' 
MQTT_TOPIC_PRESSURE = 'pico/pressure' 
MQTT_TOPIC_HUMIDITY = 'pico/humidity'

Detalles MQTT

En las siguientes líneas configuramos los parámetros MQTT para conectarnos a nuestro broker MQTT. Importamos la URL del servidor, el nombre de usuario y la contraseña desde el archivo config.py.

# Parámetros MQTT 
MQTT_SERVER = config.mqtt_server
MQTT_PORT = 0 
MQTT_USER = config.mqtt_username 
MQTT_PASSWORD = config.mqtt_password 
MQTT_CLIENT_ID = b"raspberrypi_picow" 
MQTT_KEEPALIVE = 7200 
MQTT_SSL = True 
MQTT_SSL_PARAMS = {'server_hostname': MQTT_SERVER}

 

El MQTT_CLIENT_ID debe ser un ID único para identificar al cliente MQTT.
Puedes ponerle el nombre que quieras, pero debe ser único entre los clientes conectados a tu broker.
En este caso, usamos: raspberrypi_picow.

MQTT_CLIENT_ID = b"raspberrypi_picow"

Si estás usando un broker MQTT Mosquitto local, debes establecer el parámetro MQTT_SSL en False:

 

MQTT_SSL = False

 

Sensor BME280

En las siguientes líneas, inicializamos el sensor BME280 y creamos una función llamada get_sensor_readings() que obtiene datos del BME280 y devuelve la temperatura, humedad y presión.

 

# Inicializar comunicación I2C
i2c = I2C(id=0, scl=Pin(5), sda=Pin(4), freq=10000)

# Inicializar sensor BME280
bme = BME280.BME280(i2c=i2c, addr=0x76)

def get_sensor_readings():
temp = bme.temperature[:-1]
hum = bme.humidity[:-1]
pres = bme.pressure[:-3]
return temp, hum, pres

 

Inicializar Wi-Fi

La función initialize_wifi() conecta la Raspberry Pi Pico a una red. Necesitas inicializar el Wi-Fi para poder conectarte al broker MQTT e intercambiar mensajes.

 

def initialize_wifi(ssid, password):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)

# Conectarse a la red
wlan.connect(ssid, password)

# Esperar la conexión Wi-Fi
connection_timeout = 10
while connection_timeout > 0:
if wlan.status() >= 3:
break
connection_timeout -= 1
print('Esperando conexión Wi-Fi...')
sleep(1)

# Comprobar si la conexión fue exitosa
if wlan.status() != 3:
return False
else:
print('¡Conexión exitosa!')
network_info = wlan.ifconfig()
print('Dirección IP:', network_info[0])
return True

 

Conectar a MQTT

La función connect_mqtt() se encarga de conectar con el broker MQTT utilizando los datos del broker que configuraste anteriormente.




def connect_mqtt():
    try: 
          client = MQTTClient(client_id=MQTT_CLIENT_ID, 
                             server=MQTT_SERVER, 
                             port=MQTT_PORT,  
                             user=MQTT_USER, 
                             password=MQTT_PASSWORD, 
                             keepalive=MQTT_KEEPALIVE, 
                             ssl=MQTT_SSL, 
                             ssl_params=MQTT_SSL_PARAMS) 
          client.connect() 
          return client 
       except Exception as e: 
           print('Error connecting to MQTT:', e) 
           raise # Re-raise the exception to see the full traceback

 

Publicar mensajes MQTT


La función publish_mqtt() publica un mensaje en un tema (topic). Pasa como argumentos el topic y el mensaje que quieres enviar.



def publish_mqtt(topic, value):
    client.publish(topic, value)
        print(topic)
        print(value)
        print("Publicación completada")

Publicando lecturas del sensor

Ahora que tenemos todas las funciones y variables definidas, podemos finalmente conectarnos a internet y al broker para comenzar a publicar mensajes.

Primero, intentamos conectarnos al Wi-Fi usando el SSID y la contraseña almacenados en el archivo config.py.

try: 
   if not initialize_wifi(config.wifi_ssid, config.wifi_password): 
   print('Error connecting to the network... exiting program')

 

Si logramos conectarnos al Wi-Fi, podemos conectarnos al broker MQTT.

else: 
    # Conectarse al broker MQTT, iniciar cliente MQTT 
    client = connect_mqtt()

 

Después de conectarnos, obtenemos nuevos datos del sensor y los guardamos en las variables temperature, humidity y pressure.

# Leer datos del sensor
temperature, humidity, pressure = get_sensor_readings()

Finalmente, usamos la función publish_mqtt() para publicar las lecturas en sus temas específicos.
El mensaje debe ser una cadena de texto, así que necesitamos convertir los datos del sensor usando la función str().

# Publicar como payload
MQTT publish_mqtt(MQTT_TOPIC_TEMPERATURE, str(temperature))
publish_mqtt(MQTT_TOPIC_PRESSURE, str(pressure))
publish_mqtt(MQTT_TOPIC_HUMIDITY, str(humidity))

Publicamos nuevas lecturas cada 10 segundos.

sleep(10)

Probando el código

Ejecuta el código anterior en tu Raspberry Pi Pico. Se conectará a internet y empezará a publicar mensajes cada 10 segundos.

RPi Pico Thonny IDE Publish MQTT Messages
Raspberry Pi Pico connected to BME280

Ahora, podemos verificar si podemos recibir los mensajes en un cliente MQTT que esté suscrito a esos temas.
HiveMQ proporciona una interfaz Web Client que te permite suscribirte y publicar en los temas para fines de prueba.

  1. Ve a tu cluster HiveMQ y haz clic en la pestaña Web Client.

  2. Ingresa tu usuario y contraseña del broker MQTT y haz clic en Connect Client.

HiveMQ Web Client Subscribe to Topics

Repite el mismo proceso para pico/humidity y pico/pressure.

Y eso es todo ✅. Has publicado exitosamente mensajes MQTT con la Raspberry Pi Pico.

Ahora, puedes usar cualquier otro cliente MQTT para suscribirte a esos mensajes y recibir los datos.
Por ejemplo, puedes tener nodos en Node-RED o widgets en Adafruit IO suscritos a los temas MQTT y mostrar los datos en gráficos y medidores.

También puedes tener cualquier otro microcontrolador suscrito a esos temas para recibir los datos: puede ser otra Raspberry Pi Pico, un ESP32, un ESP8266 u placa.

Suscribirse a temas MQTT

 

Raspberry Pi Pico subscribing to MQTT messages

 

 

Flujo de trabajo para suscribirse a temas MQTT

  1. Conectar la Raspberry Pi Pico a internet.

  2. Conectarse al broker MQTT.

  3. Suscribirse al tema MQTT.

  4. Crear y asignar una función callback que se ejecute cuando se reciba un mensaje.

  5. Crear un bucle que esté revisando constantemente si hay nuevos mensajes MQTT.

El siguiente código se suscribe al tema pico/led y controla un LED según el mensaje recibido.

# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-w-mqtt-micropython/

from machine import Pin
from time import sleep
import network
from umqtt.simple import MQTTClient
import config

# Define LED
led = Pin('LED', Pin.OUT)

# Constants for MQTT Topics
MQTT_TOPIC_LED = 'pico/led'

# MQTT Parameters
MQTT_SERVER = config.mqtt_server
MQTT_PORT = 0
MQTT_USER = config.mqtt_username
MQTT_PASSWORD = config.mqtt_password
MQTT_CLIENT_ID = b'raspberrypi_picow'
MQTT_KEEPALIVE = 7200
MQTT_SSL = True   # set to False if using local Mosquitto MQTT broker
MQTT_SSL_PARAMS = {'server_hostname': MQTT_SERVER}

# Init Wi-Fi Interface
def initialize_wifi(ssid, password):
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)

    # Connect to the network
    wlan.connect(ssid, password)

    # Wait for Wi-Fi connection
    connection_timeout = 10
    while connection_timeout > 0:
        if wlan.status() >= 3:
            break
        connection_timeout -= 1
        print('Waiting for Wi-Fi connection...')
        sleep(1)

    # Check if connection is successful
    if wlan.status() != 3:
        return False
    else:
        print('Connection successful!')
        network_info = wlan.ifconfig()
        print('IP address:', network_info[0])
        return True

# Connect to MQTT Broker
def connect_mqtt():
    try:
        client = MQTTClient(client_id=MQTT_CLIENT_ID,
                            server=MQTT_SERVER,
                            port=MQTT_PORT,
                            user=MQTT_USER,
                            password=MQTT_PASSWORD,
                            keepalive=MQTT_KEEPALIVE,
                            ssl=MQTT_SSL,
                            ssl_params=MQTT_SSL_PARAMS)
        client.connect()
        return client
    except Exception as e:
        print('Error connecting to MQTT:', e)

# Subcribe to MQTT topics
def subscribe(client, topic):
    client.subscribe(topic)
    print('Subscribe to topic:', topic)
    
# Callback function that runs when you receive a message on subscribed topic
def my_callback(topic, message):
    # Perform desired actions based on the subscribed topic and response
    print('Received message on topic:', topic)
    print('Response:', message)
    # Check the content of the received message
    if message == b'ON':
        print('Turning LED ON')
        led.value(1)  # Turn LED ON
    elif message == b'OFF':
        print('Turning LED OFF')
        led.value(0)  # Turn LED OFF
    else:
        print('Unknown command')
    
try:
    # Initialize Wi-Fi
    if not initialize_wifi(config.wifi_ssid, config.wifi_password):
        print('Error connecting to the network... exiting program')
    else:
        # Connect to MQTT broker, start MQTT client
        client = connect_mqtt()
        client.set_callback(my_callback)
        subscribe(client, MQTT_TOPIC_LED)
        
        # Continuously checking for messages
        while True:
            sleep(5)
            client.check_msg()
            print('Loop running')
except Exception as e:
    print('Error:', e)
 

 

 

Echemos un vistazo rápido a las secciones relevantes del código para este ejemplo.

Si estás usando un broker MQTT Mosquitto local, debes establecer el parámetro MQTT_SSL en False.

MQTT_SSL = False

Suscribirse a temas MQTT

Creamos una función llamada subscribe() que acepta como argumentos el cliente MQTT y el tema al que queremos suscribirnos.

def subscribe(client, topic): 
    client.subscribe(topic) 
    print('Suscrito al tema:', topic)

 

Función Callback

Necesitamos crear una función callback que se ejecutará cuando se reciba un nuevo mensaje en un tema al que estamos suscritos.
Los argumentos topic y message se pasan automáticamente a la función cuando se llama.

def my_callback(topic, message): 
     # Realizar acciones según el tema suscrito y la respuesta 
     print('Mensaje recibido en el tema:', topic) 
     print('Respuesta:', message) 
     # Comprobar el contenido del mensaje recibido 
     if message == b'ON': 
        print('Encendiendo LED') 
        led.value(1) # Encender LED 
     elif message == b'OFF': 
        print('Apagando LED') 
        led.value(0) # Apagar LED 
     else: 
       print('Comando desconocido')

 

En esta función, verificamos el contenido del mensaje.

Si el mensaje es ON, encenderemos el LED incorporado de la Raspberry Pi Pico:

if message == b'ON':
print('Encendiendo LED')
led.value(1) # Encender LED

Si el mensaje es OFF, apagará el LED:

elif message == b'OFF':
print('Apagando LED')
led.value(0) # Apagar LED

Si recibimos cualquier otro mensaje, se imprimirá Comando desconocido:

else:
print('Comando desconocido')

 

Conectarse a Wi-Fi, al Broker MQTT y Revisar Mensajes

Para suscribirse al broker MQTT y revisar constantemente los mensajes entrantes, primero debemos conectarnos a internet.

Las siguientes líneas intentan conectarse a la red:

try:
# Inicializar Wi-Fi
if not initialize_wifi(config.wifi_ssid, config.wifi_password):
print('Error al conectar con la red... saliendo del programa')

 

Si logramos conectarnos, también nos conectamos al broker MQTT:

client = connect_mqtt()

Luego, asignamos la función callback usando set_callback() y pasando como argumento la función que creamos previamente, my_callback:

client.set_callback(my_callback)

Finalmente, podemos suscribirnos a los temas MQTT.
En este caso, nos suscribimos solo a MQTT_TOPIC_LED, pero puedes suscribirte a varios temas:

subscribe(client, MQTT_TOPIC_LED)

Después, creamos un bucle while para revisar constantemente los mensajes entrantes usando el método check_msg():

while True:
sleep(5)
client.check_msg()
print('Bucle en ejecución')

Puedes agregar otras tareas dentro del bucle.
Aquí revisamos los mensajes cada 5 segundos, pero puedes usar un tiempo de retardo más corto o largo según la frecuencia con la que esperas recibir mensajes.

Probando el código

Ejecuta el código anterior en tu Raspberry Pi Pico.
Se conectará a internet y se suscribirá al tema MQTT, listo para recibir mensajes.

 

RPi Pico subscribe to MQTT topics Thonny IDE

 

 

Ahora, vamos a publicar algunos mensajes en el tema pico/led para controlar el LED usando el Web Client de HiveMQ.

  1. Ve al Web Client de tu cluster HiveMQ.

  2. Ingresa tu usuario y contraseña del broker MQTT y haz clic en Connect Client.

 

HiveMQ Web Client

 

 

Desplázate hacia abajo hasta la sección Publish Message.

  • Ingresa pico/led en el campo Topic Name.

  • Escribe ON en el campo Message.

 

HiveMQ publish MQTT message Web Client

 

 

Finalmente, presiona el botón Publish.

Tu Raspberry Pi Pico recibirá el mensaje y encenderá el LED incorporado.

RPi Pico receive Messages via MQTT Thonny IDE
Raspberry Pi Pico W onboard LED on

Vuelve al HiveMQ Web Client y envía un mensaje OFF.

Raspberry Pi Pico W onboard LED off

Preguntas frecuentes

¿Qué es MQTT?

Es un protocolo de comunicación muy usado en domótica e IoT para conectar múltiples dispositivos. Funciona con un modelo de publicación y suscripción, en el que los dispositivos publican mensajes en temas y otros se suscriben para recibirlos.

¿Qué es un broker MQTT?

Es el servidor intermediario que recibe todos los mensajes publicados y los reparte a los dispositivos suscritos al tema correspondiente. Sin broker no hay comunicación: ningún dispositivo habla directamente con otro.

¿Qué son los temas o topics en MQTT?

Son las etiquetas que organizan los mensajes. Un dispositivo publica en un tema y todos los que estén suscritos a ese tema reciben el mensaje. Es lo que permite que muchos dispositivos compartan un mismo broker sin interferirse.

¿Qué broker MQTT puedo usar con la Raspberry Pi Pico W?

El tutorial muestra la configuración con HiveMQ, una de las soluciones de broker disponibles. También hay que instalar los módulos MQTT correspondientes en la placa antes de publicar o suscribirse.

¿Qué necesito antes de empezar con MQTT en la Pico W?

Tener el firmware de MicroPython instalado en la placa y la conexión WiFi funcionando, además de un broker MQTT configurado. Recién con esos tres elementos se pueden publicar y recibir mensajes.

Aprende esto en un curso

Si prefieres verlo en vivo y con alguien que resuelva tus dudas, estos cursos presenciales de MCI Educación cubren el tema de este tutorial: