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

Cómo usar MQTT en el ESP8266/ESP32

Iniciamos una nueva serie de entradas sobre el ESP8266/ESP32, donde vamos a ver la comunicación mediante protocolo MQTT, que como sabemos es muy apropiado para aplicaciones de IoT.

Para los que no conozcáis MQTT os remito a esta serie de entradas donde hemos hablado ya bastante de ello. En forma muy resumida, mencionamos que es uno de los múltiples protocolos de comunicación bajo patrón Publisher/Suscriber, muy adecuado a para procesadores de bajos recursos.

Por otro lado, en esta entrada vimos la librería Pubsub, como la más popular para implementar MQTT en el entorno de Arduino. Ya adelantamos que volveríamos a hablar de ellas en la sección del ESP8266/ESP32.

Para empezar esta serie de entradas 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 entradas sobre el ESP8266/ESP32 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);
}

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();
}

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 = "ESP8266Client_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();
}

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.

En la próxima entrada veremos cómo realizar este proceso de forma asíncrona, y en el siguiente la mejoraremos enviando un fichero Json que contenga información más relevante. ¡Hasta la próxima!

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