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 hablaodo 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.

Anuncio:

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.

Para seguir realizar este tutorial necesitaréis tener instalado un broker MQTT, o acceso a uno de los múltiples servicios en la nube. Aquí tenéis una entrada sobre cómo instalar Mosquitto en vuestro ordenador.

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.

Así, nuestro sketch principal queda sencillo y fácil de entender.

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

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.

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.

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

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.

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()'.

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.

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

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

Si te ha gustado esta entrada y quieres leer más sobre ESP8266 o el ESP32 puedes consultar la sección tutoriales de ESP8266/32
5 2 votes
Article Rating

Anuncio:

Previous LilyGo T5 4.7, una gran pantalla e-ink para tus proyectos
Next Cómo controlar hasta 16 GPIO por I2C con extensor PCF8575 y Arduino
0 Comments
Inline Feedbacks
View all comments