como-usar-mqtt-en-el-esp8266-esp32

Cómo usar MQTT en ESP32

  • 5 min

MQTT es un protocolo de mensajería ligero basado en publicación y suscripción, muy apropiado para aplicaciones IoT con ESP32 o ESP8266.

En forma muy resumida, MQTT permite que los dispositivos publiquen mensajes en temas y que otros clientes se suscriban a esos temas para recibirlos. Es un patrón muy cómodo cuando tenemos sensores, actuadores, dashboards o servicios hablando entre sí sin conectarse directamente unos con otros.

Por otro lado, en el ecosistema Arduino la librería PubSubClient es una de las opciones más populares para implementar MQTT en microcontroladores. En el ESP32 también podemos usarla para montar ejemplos sencillos de publicación y suscripción.

Vamos a empezar con un ejemplo sencillo, para perderle el miedo. No os dejéis asustar por las siglas y términos. Lo cierto es que la comunicación por MQTT es sencilla y robusta (precisamente ahí reside buena parte de su éxito y popularidad).

Al igual que hicimos con Ajax y Websockets en su momento, vamos a empezar por una sencilla aplicación que reciba un valor numérico. En este primer ejemplo, con recibir el valor de millis() es suficiente para comprobar la comunicación.

Y, como en el resto de ejemplos del curso, vamos a dividir el código en distintos archivos, agrupados por funciones, e intentando que algunos de ellos sean reutilizables entre proyectos sin modificación alguna.

Nuestro sketch principal queda sencillo y fácil de entender. Aquí hay algunas llamadas a funciones definidas en los ficheros, que veremos a continuación.

Pero, en resumen, en el setup iniciamos el WiFi y la comunicación MQTT. Por otro lado, en el ‘loop’, gestionamos los mensajes recibidos por MQTT, a la vez que enviamos el valor de ‘millis()’. Sencillo.

#include <WiFi.h>
#include <SPIFFS.h>
#include <PubSubClient.h>

#include "config.h"  // Sustituir con datos de vuestra red
#include "MQTT.hpp"
#include "ESP32_Utils.hpp"
#include "ESP32_Utils_MQTT.hpp"

void setup(void)
{
  Serial.begin(115200);
  SPIFFS.begin();

  ConnectWiFi_STA(true);

  InitMqtt();
}

void loop()
{
  HandleMqtt();

  PublisMqtt(millis());

  delay(1000);
}
Copied!

Por su parte, el fichero “ESP32_Utils_MQTT.hpp” contiene funciones que genéricas para comunicación en MQTT. Al igual que los otros ficheros ‘Utils’ que hemos usado, está pensado para contener código que podéis reusar entre proyectos con poca o ninguna modificación.

Aquí tenemos estas funciones para InitMqtt(), ConnectMqtt(), y HandleMqtt()

void InitMqtt() 
{
  mqttClient.setServer(MQTT_BROKER_ADRESS, MQTT_PORT);
  SuscribeMqtt();
  mqttClient.setCallback(OnMqttReceived);
}

void ConnectMqtt()
{
  while (!mqttClient.connected())
  {
    Serial.print("Starting MQTT connection...");
    if (mqttClient.connect(MQTT_CLIENT_NAME))
    {
      SuscribeMqtt();
    }
    else
    {
      Serial.print("Failed MQTT connection, rc=");
      Serial.print(mqttClient.state());
      Serial.println(" try again in 5 seconds");

      delay(5000);
    }
  }
}

void HandleMqtt()
{
  if (!mqttClient.connected())
  {
    ConnectMqtt();
  }
  mqttClient.loop();
}
Copied!

Finalmente, en el fichero ‘MQTT.hpp’ hemos definido las funciones que sí son específicas de tu proyecto. En estas funciones está “la chicha” del proyecto, y deberemos adaptarlas en función de las características del mismo.

Así, tenemos en primer lugar las definiciones de la dirección del broker, el puerto (por defecto 1883 está bien), y el nombre del cliente. Recordad que dos clientes con el mismo nombre no deben conectarse al mismo broker.

Por otro lado, tenemos la función SuscribeMqtt que se encarga de sindicar al ESP8266/ESP32 a los topic que queramos escuchar. La función PublisMqtt emite un mensaje por MQTT, en este caso simplemente un número long. Finalmente, la función OnMqttReceived se ejecuta al recibir un mensaje por MQTT y, en este ejemplo, simplemente muestra el contenido por puerto serie.

const char* MQTT_BROKER_ADRESS = "192.168.1.150";
const uint16_t MQTT_PORT = 1883;
const char* MQTT_CLIENT_NAME = "ESP32Client_1";

WiFiClient espClient;
PubSubClient mqttClient(espClient);

void SuscribeMqtt()
{
  mqttClient.subscribe("hello/world");
}

String payload;
void PublisMqtt(unsigned long data)
{
  payload = "";
  payload = String(data);
  mqttClient.publish("hello/world", (char*)payload.c_str());
}

String content = "";
void OnMqttReceived(char* topic, byte* payload, unsigned int length) 
{
  Serial.print("Received on ");
  Serial.print(topic);
  Serial.print(": ");

  content = "";  
  for (size_t i = 0; i < length; i++) {
    content.concat((char)payload[i]);
  }
  Serial.print(content);
  Serial.println();
}
Copied!

Resultado

Para comprobar que todo funciona correctamente subimos todo el código a nuestro ESP8266/ESP32. Si todo ha salido bien, veremos en la consola Serial el valor de ‘Millis()’.

esp32-mqtt-async-resultado

No parece muy impresionante, porque estamos más que acostumbrados a ver el valor ‘millis’, pero pensemos un momento lo que está pasando. En realidad casa segundo el ESP32 está enviando el valor de ‘Millis()’ al broker y este lo distribuye a los clientes conectados.

En este mini ejemplo solo tenemos un cliente conectado, que es a la vez es el emisor. Este recibe el mensaje, lo procesa, y lo muestra por puerto serie. Una forma bastante complicada de mostrar el valor ‘millis’, pero una forma muy buena de comprobar que la comunicación MQTT está funcionando.

Ahora podríais conectar más ESP8266/ESP32 y todos recibirían el valor que hemos emitido de forma (casi) simultánea. Y, por supuesto, todos podrían emitir sus propios mensajes. Un concepto bastante potente ¿Y a que no ha sido nada complicado? Esa es la gracia de los servicios de notificaciones.

Por supuesto, mandar un número no es muy interesante. Pero, ya que sabemos cómo enviar y recibir datos a través de MQTT, y hemos comprobado que funciona nuestra red MQTT, que es el primer paso antes de hacer algo más complicado.

Con esto ya tenemos un ESP32 o ESP8266 enviando y recibiendo mensajes por MQTT. A partir de aquí podemos hacerlo de forma asíncrona, enviar JSON o integrarlo con una interfaz web o un sistema domótico.

Descarga el código

Todo el código de esta entrada está disponible para su descarga en Github.

github-full

Versión para el ESP8266: https://github.com/luisllamasbinaburo/ESP8266-Examples

Versión para el ESP32: https://github.com/luisllamasbinaburo/ESP32-Examples