MQTT con ESP32 y Mongoose-OS

Mongoose-OS incorpora un cliente MQTT y un simple intérprete mJS (una versión reducida de JavaScript). Con ellos podemos rápida y fácilmente conectarnos a un broker MQTT y realizar pruebas de concepto de aplicaciones más complejas.

Configuración

Configuramos el ESP32 con Mongoose-OS para tener un cliente MQTT y conectarse como cliente a una red WiFi. Dado que debemos conectarnos a un servidor, ésta nos resulta la forma tal vez más rápida y simple de realizar las pruebas y explicar la operación. La configuración puede realizarse manualmente mediante RPC, en un archivo de configuración JSON; o definirla en el archivo YAML que describe el proyecto. Para las pruebas elegimos esta última opción.

libs:
  - origin: https://github.com/mongoose-os-libs/mqtt  # incorpora el cliente MQTT
config_schema:
  - ["mqtt.enable", true]            # Habilita el cliente MQTT
  - ["mqtt.server", "address:port"]  # Dirección IP del broker a utilizar

El puerto comúnmente utilizado es 1883. El broker puede además solicitar que utilicemos nombre de usuario y password, los detalles de la configuración completa los podemos encontrar en la página de Mongoose-OS.

Operación

Antes de compilar y ejecutar, es conveniente tener un cliente conectado al broker para poder observar el mensaje enviado al momento de conexión. Hemos utilizado un broker instalado en nuestro lab:

$ mosquitto_sub -h mqtt.lab -p 1883 -t "#" -v

También (si el tráfico habitual lo permite) es posible usar el broker abierto de Eclipse , en cuyo caso deberemos limitar un poco el tópico a suscribirnos a fin de intentar recibir sólo nuestros mensajes

$ mosquitto_sub -h mqtt.eclipseprojects.io -p 1883 -t "/this/#" -v

Luego de compilado el código (mos build) y grabado el microcontrolador (mos flash) mediante mos tool, observaremos en el log si todo funciona como debe, o los errores que se hayan producido. Recordemos que debemos configurar las credenciales para conectarnos por WiFi a nuestra red (SSID y clave) y la dirección y port del broker MQTT que vayamos a utilizar.

[Feb 11 15:19:42.353] mgos_mqtt_conn.c:435    MQTT0 connecting to mqtt.sensors.lab:1883
[Feb 11 15:19:42.370] mgos_mqtt_conn.c:188    MQTT0 TCP connect ok (0)
[Feb 11 15:19:42.380] mgos_mqtt_conn.c:235    MQTT0 CONNACK 0
[Feb 11 15:19:42.385] mgos_mqtt_conn.c:168    MQTT0 sub /this/sub @ 1
[Feb 11 15:19:42.393] init.js:38              MQTT connected
[Feb 11 15:19:42.407] init.js:26              Published:OK topic:/this/pub/esp32_807A98 msg:CONNECTED!

En este momento observaremos el mensaje en nuestro cliente:

$ mosquitto_sub -h mqtt.lab -p 1883 -t "#" -v
/this/pub/esp32_807A98 CONNECTED!

A continuación, enviamos un mensaje a nuestro dispositivo publicando uno en el tópico al que éste se halla suscripto:

$ mosquitto_pub -t /this/sub -h mqtt.lab -m "This message"

En este momento observaremos el mensaje en nuestro cliente

$ mosquitto_sub -h mqtt.lab -p 1883 -t "#" -v
/this/pub/esp32_807A98 CONNECTED!
/this/sub This message

y en el log de nuestro dispositivo

[Feb 11 15:20:02.647] init.js:32              Got a msg: This message

Finalmente, apagamos nuestro ESP32 y al cabo de unos minutos el broker detectará la desconexión; en ese momento observaremos el mensaje “de última voluntad” en nuestro cliente

$ mosquitto_sub -h mqtt.lab -p 1883 -t "#" -v
/this/pub/esp32_807A98 CONNECTED!
/this/sub This message
/this/test lost

El código mJS

Cuando queremos publicar algo, invocamos el método MQTT.pub(). No debemos esperar ni hacer handshakes, sólo llamarlo y observar el resultado. Internamente el mensaje es puesto en una cola, de donde saldrá cuando sea posible. El valor devuelto indica que ha sido posible encolar el mensaje, no que éste ha llegado a destino. En el código que acompaña a este artículo creamos una función como ejemplo de uso:

let publish = function (topic, msg) {
    let ok = MQTT.pub(topic, msg, 1, false); // QoS = 1, do not retain
    Log.print(Log.INFO, 'Published:' + (ok ? 'OK' : 'FAIL') + ' topic:' + topic + ' msg:' +  msg);
    return ok;
};

let device_id = Cfg.get('device.id');
publish('/this/pub/'+device_id,'CONNECTED!');

Si queremos que el mensaje sea retenido, el cuarto parámetro de MQTT.pub() debe ser verdadero.

Para recibir mensajes, nos suscribimos al tópico deseado usando el método MQTT.sub(). El segundo parámetro es un handler a una función callback que se ejecutará cuando recibamos un mensaje. En el código que acompaña a este artículo mostramos un ejemplo de uso:

MQTT.sub('/this/sub', function(conn, topic, msg) {
    Log.print(Log.INFO, 'Got a msg: ' + msg);
}, null);

Last will, mensajes “de última voluntad”

Si deseamos configurar una “última voluntad”, es decir, un mensaje que el broker publicará por nosotros ante la detección de una desconexión, podemos hacerlo como se ve a continuación:

  - ["mqtt.will_topic", "/this/test"]
  - ["mqtt.will_message", "lost"]

En algunas aplicaciones es necesario que este mensaje sea retenido por el broker, de modo que otros clientes que se conecten luego de nuestra desconexión y antes de nuestra reconexión puedan recibir dicho mensaje, que por lo general tiene la misión de indicar que no estamos disponibles.

  - ["mqtt.will_retain", true]

Retain, persistencia

La retención de mensajes (sean “de última voluntad” o mensajes corrientes con el flag retain seteado) requiere de un broker MQTT con capacidad de persistencia (persistence), es decir, con una base de datos que almacene los últimos mensajes marcados como persistentes y los retransmita a quien se suscribe al tópico correspondiente al momento de iniciar la suscripción.

En nuestro caso hemos utilizado como broker Eclipse Mosquitto, pero hay otras opciones.

En el caso de Mosquitto, para configurar la persistencia debemos agregar

persistence true

en el archivo de configuración (si lo buscamos lo encontramos). También es posible que además debamos agregar el nombre y ubicación de la base de datos de persistencia (paths en formato ambiente GNU/Linux):

persistence_file mosquitto.db
persistence_location /var/lib/mosquitto/

pero eso depende de la distribución que utilicemos, por lo que puede que ya esté hecho por defecto. El usuario bajo el cual se ejecuta el proceso debe tener permisos de escritura a esta base de datos.

Ejemplo

El código de ejemplo se encuentra en Github.

Want to share this ?

Leave a Reply

Your email address will not be published. Required fields are marked *

Enter Captcha Here : *

Reload Image