Está en la página 1de 10

CÓMO COMUNICAR UN

ESP32 CON UNA PÁGINA


WEB A TRAVÉS DE
MQTT

30 DICIEMBRE, 2021

     

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 <WiFi.h>

#include <SPIFFS.h>

#include <ESPAsyncWebServer.h>

#include <AsyncMqttClient.h>

#include <ArduinoJson.h>

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

<!doctype html>

<html lang="">

<head>

<title>ESP32 MQTT</title>

<meta charset="utf-8">

<meta http-equiv="x-ua-compatible" content="ie=edge">

<title></title>

<meta name="description" content="">

<meta name="viewport" content="width=device-width, initial-scale=1">

</head>

<body>

<div id="app">

</div>

<script type="text/javascript" src="./vendor/nativeWs.min.js"></script>

<script type="text/javascript" src="./vendor/mqttws31.min.js" ></script>

<script type="text/javascript" src="./js/API.js"></script>

<script type="text/javascript" src="./js/app.js"></script>


</body>

</html>
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

Anuncio:

También podría gustarte