Cómo comunicar un ESP32 con una página web a través de MQTT Deja un comentario

Nueva entrada sobre comunicación con el ESP8266 y ESP32. Esta vez nos toca ver cómo comunicar una página web servida desde el ESP32 a través de MQTT.

Ya hemos visto Cómo usar MQTT asíncrono y Cómo enviar texto en formato Json a través de MQTT. Estas comunicaciones eran entre dispositivos, entre backends. Ahora queremos comunicarlo con una web servida al cliente, con el frontend.

Esto no suele (o no debería) ser tan frecuente, porque tenemos muchas formas de comunicar un ESP8266/ESP32 actuando backend con el frontent. Así hemos visto llamadas Ajax y comunicación por Websockets.

Pero, si nuestro sistema está usando MQTT, puede ser útil emplear el mismo sistema para informar al frontend. Así que, en definitiva, queremos hacer un cliente web para el protocolo MQTT, y servir este cliente desde el propio ESP32.

Anuncio:

Aquí es donde nos encontramos el primer problema, cómo podemos comunicar una página web, que vive en su “mundo web” de llamadas HTTP, con una comunicación por MQTT.

Comunicar una web por MQTT

Una página web se comunica a través de HTTP, que es un protocolo que actúa sobre la capa de Aplicación (capa 7 del modelo OSI). Esta, a su vez, opera sobre TCP que actúa sobre la capa de transporte (capa 4). Es decir, salvo ciertas excepciones o cambios en el futuro (HTTP 3?) una página web sólo puede comunicarse a través de peticiones HTTP, websockets, o WebRTC.

¿Y MQTT como encaja en esto? MQTT es un protocolo también de la capa de Aplicación (capa 7) que generalmente opera sobre TCP/IP. Resumiendo, MQTT tira directamente contra un socket y no va a entrar en una petición HTTP.

¿Entonces no podemos conectarlos? Bueno, aquí vienen los websockets al rescate. Podemos configurar MQTT para que funcione sobre websockets, que como hemos dicho, sí podemos manipular desde una página web.

Pero antes necesitamos configurar nuestro broker para que acepte websockets. Si esto es posible, o cómo configurarlo, dependerá del broker que estemos usando. En el resto de la entrada vamos a verlo como si tuviéramos una instalación local de Mosquitto como vimos en esta entrada.

Y, por otro lado, vamos a necesitar una librería de JavaScript que nos permita leer esta comunicación MQTT a través de websockets desde la página web servida.

Configurar Mosquitto para usar Websockets

Si estamos usando Mosquitto como broker MQTT, la comunicación por websockets viene desactivada por defecto. Así que deberemos activarla en la configuración para podernos comunicar desde una página web.

Para ello, editamos el fichero de ‘mosquitto.conf’, que tendréis en la carpeta donde hayáis instalado Mosquitto. Aquí buscad la sección “Extra listeners” y descomentáis las líneas de websockets, quitando el símbolo ‘#’ del principio de la línea.

# =================================================================
# Extra listeners
# =================================================================
...
listener 9001
protocol websockets
...

Así hemos añadido un listener extra para Mosquitto, a través de websockets actuando en el puerto 9001.

Librería Paho JavaScript Client

El otro componente que necesitamos para nuestra comunicación es una librería de JavaScript para MQTT. Existen varias librerías, pero la más empleada es la librería Paho JavaScript Client de Eclipse.

Es una librería que está disponible en varios lenguajes, incluidos Java, JavaScript, Python, C/C++, Rust y Golang. Más información en la página del proyecto https://www.eclipse.org/paho

Vamos al código

Ahora que hemos configurado nuestro broker para aceptar comunicación por websockets, y con nuestra librería Paho JS Client, toca juntarlo todo para ver un ejemplo.

El programa que subiremos al ESP32, encargado de hacer la comunicación MQTT, es básicamente igual al de la entrada anterior. Por tanto, únicamente vamos a comentar las diferencias, y en caso de dudas podéis consultar el tutorial anterior.

El código del bucle principal del programa queda de la siguiente forma.

#include 
#include 
#include 
#include 
#include 

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

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

  delay(500);

  WiFi.onEvent(WiFiEvent);
  InitMqtt();

  ConnectWiFi_STA();
  InitServer();
}

void loop()
{
  PublishMqtt();

  delay(1000);
}

Donde la diferencia es que hemos añadido una llamada a ‘InitServer()’ para poder servir la página web desde el ESP32. Además, hemos añadido los includes pertinentes.

La otra diferencia es el fichero ‘Server.hpp’, donde hemos metido la lógica asociada a servir la página web.

AsyncWebServer server(80);

void InitServer()
{ 
	server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.html");

	server.onNotFound([](AsyncWebServerRequest *request) {
		request->send(400, "text/plain", "Not found");
	});

	server.begin();
	Serial.println("HTTP server started");
}

Simplemente estamos sirviendo una página web desde SPIFFS, algo que ya hemos visto en el resto de entradas de la serie.

Ahora vamos a lo realmente nuevo, que es la página que estamos sirviendo, y que debe actuar como un cliente de comunicación MQTT. En fichero ‘index.html’ tendría la siguiente forma.





  ESP32 MQTT
  
  
  
  
  



  

En el fichero ‘API.js’ tenemos encapsuladas las funciones asociadas al flujo de trabajo de nuestra aplicación.

function onConnect() {

  var options = {
    qos: 0,
    onSuccess: onSubSuccess,
    onFailure: onSubFailure
  };
  client.subscribe('hello/world', options);
}

function onFailure(message) {
  console.log(message)
}

function onConnectionLost(responseObject) {
  if (responseObject.errorCode !== 0) {
    console.log("onConnectionLost:" + responseObject.errorMessage);
  }
}

function onMessageArrived(message) {
  console.log(message)
  var topic = message.destinationName;
  var payload = message.payloadString;

  let json = JSON.parse(payload);

  var element = document.getElementById('app');
  var newElement = document.createElement('div');
  newElement.appendChild(document.createTextNode(json.data));
  element.appendChild(newElement);
}

function onSubFailure(message) {
  console.log(message)
}

function onSubSuccess(message) {
  console.log(message)
}

A destacar, en el método ‘onConnect()’ nos suscribimos al topic ‘hello/world’. Por su parte, el método ‘onMessageArrived’ recibe un texto formateado como JSON, lo parsea, y usa un poquito de Vanilla JavaScript para añadir el contenido del mensaje a la página web. El resto de funciones de este ejemplo únicamente muestran por consola los datos para debug.

Finalmente, la lógica de nuestra página la tenemos en el fichero ‘app.js’ que tiene la siguiente forma.

function createGuid() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    var r = Math.random() * 16 | 0,
      v = c === 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

client = new Paho.MQTT.Client("192.168.1.150", 9001, createGuid())

var options = {
  onSuccess: onConnect,
  onFailure: onFailure
};

client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;

client.connect(options);

Como vemos, hemos definido un cliente de MQTT con la librería Paho, donde especificamos la dirección de nuestro broker, el puerto de escucha para websokets, y un identificador único para el cliente.

Para el identificador hemos usado una función que genera GUID de forma aleatoria, aunque podríamos haber usado cualquier otra, siempre que no repitamos identificador de cliente.

Por último, hemos asociado cada los eventos del cliente de MQTT a nuestras funciones del fichero ‘API.js’

Con esto, subimos tanto el programa como la web al ESP32, ejecutamos todo, y accedemos a la página web servida desde el ESP32. Si todo ha salido bien veremos aparecer los mensajes recibidos que se irán añadiendoa la página web servida.

En este ejemplo simplemente contiene el valor de Millis(). Lógicamente, en un proyecto real los datos en formato JSON contendrían más información. Esto lo veremos en la última entrada de la serie. Pero antes, en la próxima veremos cómo hacer esto mismo usando VueJS. ¡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
0 0 votes
Article Rating

Anuncio:

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Enviar Whatsapp
Hola 👋
¿En qué podemos ayudarte?