NodeRED III: nodo función

En la entrada anterior, NodeRED II: nodos principales, presente el funcionamiento de unos nodos mediante ejemplos. En la presente entrada, NodeRED III: nodo función, me centraré en el nodo función con el cual podremos definir una función definida en código Java Script empleando el nodo Function.

La descripción funcional del conjunto de flujos de trabajo definidos en la entrada son los siguientes:

  • Ejemplo 1: función básica.- Definición de un flujo de trabajo con una función básica.
  • Ejemplo 2: función y sentencias condicionales.- Definición de un flujo de trabajo con una función en donde se emplean sentencias condicionales.
  • Ejemplo 3: función y salidas múltiples.- Definición de un flujo de trabajo con una función de salida múltiple.
  • Ejemplo 4: función y bucles.- Definición de un flujo de trabajo con una función en donde se aplican bucles.
  • Ejemplo 5: función variables de entorno y trazas.- Definición de un flujo de trabajo con una función en donde se trabaja variables de contexto y trazas.
  • Ejemplo 6: función variables de entorno.- Definición de un flujo de trabajo con una función en donde se trabaja con variables de contexto.

Ejemplo 1: función básica.

En el flujo de trabajo del ejemplo 1, se define un nodo inyección en donde se inicia el arranque del flujo; se define un nodo función; y, por último, se define un nodo debug para mostrar por consola el resultado y la trazabilidad.

La función del nodo función flujo define una funcionalidad en el evento «On Message», la funcionalidad definida en este evento es muy sencilla: definición de una variable xyx, definición de una variable newMsg, la cual almacena la longitud del string pasado en el objeto msg, y el retorno de la variable msg. La función realiza la escritura de dos trazas en la consola de log: la primera de tipo warning y la segunda de tipo log.

Desde un punto de vista gráfico, el ejemplo con el código de la función y una ejecución en la consola de NodeRed queda representada en la siguiente imagen de la captura de pantalla del interfaz visual:

Figura 1: definición del flujo y código del ejemplo 1.

Ejemplo 2: función y sentencias condicionales.

En el flujo de trabajo del ejemplo 2, se define un nodo inyección en donde se inicia el arranque del flujo; se define un nodo función; dos nodos template para procesar la salida; y, por último, dos nodos debug para mostrar por consola el resultado y la trazabilidad de la ejecución.

La funcionalidad del nodo función define una funcionalidad en el evento «On Message», la funcionalidad definida en este evento es la siguiente: definición de una variable de tipo lista; una sentencia condicional la cual asigna un valor para cada condición; dos nodos template para parsear la salida; y, por último, los nodos debug para mostrar por consola el resultado.

Desde un punto de vista gráfico, el ejemplo con el código de la función y una ejecución en la consola de NodeRed queda representada en la siguiente imagen de la captura de pantalla del interfaz visual:

Figura 2: definición del flujo y código del ejemplo 2.

Ejemplo 3: función y salidas múltiples.

En el flujo de trabajo del ejemplo 3, se define un nodo inyección en donde se inicia el arranque del flujo; se define un nodo función; dos nodos template para procesar la salida; y, por último, dos nodos debug para mostrar por consola el resultado y la trazabilidad de la ejecución.

La funcionalidad del nodo función define una funcionalidad en el evento «On Message», la funcionalidad definida en este evento es la siguiente: definición de cuatro variables de tipo diccionario y, como salida, retorno una estructura de tipo lista con las variables definidas.

Desde un punto de vista gráfico, el ejemplo con el código de la función y una ejecución en la consola de NodeRed queda representada en la siguiente imagen de la captura de pantalla del interfaz visual:

Figura 3: definición del flujo y código del ejemplo 3.

Ejemplo 4: función y bucles.

En el flujo de trabajo del ejemplo 4, se define un nodo inyección en donde se inicia el arranque del flujo; se define un nodo función; un nodo template para procesar la salida; y, por último, dos nodos debug para mostrar por consola el resultado y la trazabilidad de la ejecución.

La funcionalidad del nodo función define una funcionalidad en el evento «On Message», la funcionalidad definida en este evento es la siguiente: definición de un variable de tipo lista, definición de una variable lista con el contenido del string pasado por parámetro, un bucle que recorre las palabras string y, como salida, retorna la estructura con las palabras.

Desde un punto de vista gráfico, el ejemplo con el código de la función y una ejecución en la consola de NodeRed queda representada en la siguiente imagen de la captura de pantalla del interfaz visual:

Figura 4: definición de flujo y código del ejemplo 4

Ejemplo 5: función variables de entorno y trazas.

En el flujo de trabajo del ejemplo 5, se define un nodo inyección en donde se inicia el arranque del flujo; se define un nodo función; un nodo template para procesar la salida; y, por último, dos nodos debug para mostrar por consola el resultado y la trazabilidad de la ejecución.

La funcionalidad del nodo función define una funcionalidad en el evento «On Message», la funcionalidad definida en este evento es la siguiente: definición de un variable de tipo lista, definición de una variable lista con el contenido del string pasado por parámetro, un bucle que recorre las palabras string y, como salida, retorna la estructura con las palabras. Además, se muestra por consola el valor de la variable de contexto «counter» y se crea una variable global con nombre «varGlobal» la cual se emplea en el flujo del ejemplo 6. En el evento «On Start», se define la variable de contexto «counter» utilizada en la funcionalidad «On Message».

Desde un punto de vista gráfico, el ejemplo con el código de la función y una ejecución en la consola de NodeRed queda representada en la siguiente imagen de la captura de pantalla del interfaz visual:

Figura: definición del evento On Start
Figura 5: definición del flujo y código del ejemplo 5.

Ejemplo 6: función variables de entorno.

En el flujo de trabajo del ejemplo 6, se define un nodo inyección en donde se inicia el arranque del flujo; se define un par de nodos función; un nodo template para procesar la salida; y, por último, un nodo debug para mostrar por consola el resultado y la trazabilidad de la ejecución.

El primer nodo función es prácticamente igual que el nodo del ejemplo 5 salvo que se muestra la variable de contexto «counter», se definen variables múltiples con nombre values y se define la variable «varFlow». En el segundo nodo función, se muestra por consola las trazas de nivel warning, las variables de contexto y de flujo. Por último, el nodo template aplica una plantilla para retornos al siguiente nodo unstring con el valor del atributo payload del objeto msg y la variable varFlow definida en el flujo.

Desde un punto de vista gráfico, el ejemplo con el código de la función y una ejecución en la consola de NodeRed queda representada en la siguiente imagen de la captura de pantalla del interfaz visual:

Figura 6: definición del flujo y el código de la función 6-1.
Figura 7: definición del flujo y el código de la función 6-2.

Los ejemplos mostrados en la entrada permiten mostrar cómo usar nodos función, algunas características básicas del lenguaje Java Script para la definición de funcionalidad en los nodos función y, además, cómo trabajar con diferentes tipos de entrada y salida con nodos tipo función.

En la siguientes entrada, NodeRED IV: mensajes y secuencias, me centraré en la utilización de mensajes y secuencias de mensajes.

NodeRED I: Instalación y ejemplo base

En la presente entrada, NodeRED I: Instalación, realizaré una descripción de la herramienta NodeRed y explicaré los primeros pasos para utilizar NodeRED mediante la definición de un programa básico representado en un flujo NodeRED.

Node-RED es aquella herramienta de programación que permite la conexión de dispositivos hardware, API y servicios online.

El editor de Node-RED está basado en una herramienta gráfica que se accede desde el navegador web La estructura de la interfaz gráfica está compuesta en la parte central por un panel de trabajo; en la parte izquierda, se muestra los diferentes nodos funcionales categorizados por funcionalidades; y, en la parte derecha, un conjunto de pantallas en donde se puede visualizar diferentes paneles de información.

Un programa de NodeRED es aquella estructura visual de un flujo de operaciones compuesta por la unión de nodos la cual realiza una funcionalidad determinada a partir de los datos de entrada definidos en los nodos para tal fin y, como salida, un resultado determinado en los nodos de salida.

Instalación en Docker

NodeRED puede ser instalado en varias plataformas: en una máquina local, en un contenedor docker, en un dispositivo como puede ser una placa Raspberry o bien en un servicio en la nube como AWS o Azure. En el caso que presento, describiré los pasos que he seguido para utilizar NodeRED en un contenedor Docker.

Para realizar la descarga de la imagen de Docker con la instalación de NodeRED, ejecuté el siguiente comando:

docker pull nodered/node-red

Para realizar el arranque de NodeRED con la imagen descargada, ejecutaré el siguiente comando desde la línea de comandos:

docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red

Una segunda forma para arrancar NodeRED en Docker es identificando el volumen externo del contenedor con una carpeta del sistema de ficheros de la máquina en donde levanta. Para realizar este arranque, identificamos el path de la carpeta de la siguiente forma:

docker run -it -p 1880:1880 -v /path/to/folder:/data --name mynodered nodered/node-red

La descripción de los parámetros del comando anterior son las siguientes:

  • -it.- Modo de arranque del contenedor.
  • -p 1880:1880.- Acceso al interfaz gráfico del contenedor por el puerto 1880.
  • -v node_red_data:/data.- Creación de un volumen de datos a la carpeta de configuración de datos de NodeRED con el nombre /data.
  • –name mynodered.- Asignación del nombre del contenedor con nombre mynodered.
  • nodered/node-red.- Nombre de la imagen docker que se emplea en el contenedor.

Para verificar si el contenedor se ha levantado correctamente, se ejecuta el siguiente comando desde la línea de comandos:

docker container ps -a

Para acceder a la interfaz gráfica del editor de NodeRED una vez arrancado el contenedor, se abre una ventana de un navegador y se utiliza la siguiente URL: localhost:1880. El aspecto visual del editor queda representado en la siguiente imagen:

Figura1: NodeRED interfaz
Figura1: NodeRED interfaz

Ejemplo básico

Para definir un programa en NodeRED, se realiza la definición de un flujo de nodos en el panel de trabajo central con los nodos existentes en la paleta de nodos existentes en la parte izquierda del interfaz. El proceso se realiza seleccionando y arrastrando los nodos y enlazando dichos nodos.

Las categorías de los nodos en NodeRED son las siguientes:

  • Categoría common.- Nodos en donde definen funcionalidades comunes como; por ejemplo: inyección de un valor, operación de debug.
  • Categoría function.- Nodos en donde definen funciones de usuario, funciones de control de flujo,…
  • Categoría network.- Nodos en donde se definen operaciones de red; por ejemplo: peticiones MQTT o bien HTTP, entre otras.
  • Categoría sequences.- Nodos en donde se definen operaciones sobre secuencias de flujo.
  • Categoría parser.- Nodos en donde se definen operaciones de parseo de tipos de datos.
  • Categoría storage.- Nodos en donde se definen operaciones de almacenamiento.

Para desplegar y verificar el correcta definición, es necesario pulsar al botón «Deploy» ubicado en la parte superior derecha.

Un ejemplo básico tipo «Hola Mundo» consiste en inyectar un dato, como por ejemplo, el valor de una fecha determinada; procesar dicho valor en una función y, por último, mostrarlo por la consola debug.

El flujo se compondrá por los siguiente nodos: el primero, un nodo de tipo common de tipo inject el cual inyecta un valor; el segundo, un nodo tipo función el cual, el valor que recibe como parámetro de entrada, lo procesará y retornará para el siguiente nodo; y, por último, un nodo de tipo debug el cual realiza la escritura del valor inyectado.

Nodo inyector

El nodo inyector es aquel nodo que está compuesto por un objeto msg compuesto de dos atributos: payload, con el valor timestamp que se inyecta; y, topic, con el mensaje adicional a inyectar. El aspecto visual del componente es el siguiente:

Figura2: nodo inyector

Nodo Function

El nodo función es aquel nodo el cual gestiona distintos eventos los cuáles pueden ser: evento On Start, funcionalidad que se realiza al inicio del nodo; evento On Message, funcionalidad que se ejecuta al recibir un mensaje; y, evento On Stop, fncionalidad que se realiza al parar el nodo. Todo la funcionalidad se define en Java Script.

En nuestro ejemplo, se define la funcionalidad de evento al recibir un mensaje la cual realiza el tratamiento del valor timestamp recibido y su transformación en tipo String. El aspecto visual del componente es el siguiente:

Figura3: nodo function

Nodo Debug

El nodo debug es aquel que escribe en la consola el campo del mensaje especificado. El aspecto visual del componente es el siguiente:

Figura 4: nodo debug.

Para ejecutar el flujo de trabajo es necesario pulsar en el cuadro izquierdo ubicado en el nodo inject. El aspecto de la salida en la consola del ejemplo descrito es el siguiente:

Figura 5: nodo debug con resultado.

Obtención de la configuración y flujos de trabajo.

La definición de los flujos de trabajo que se definen de forma visual, representados en el fichero flows.json, así como la configuración de NodeRED, representado en el fichero settings.js, se encuentra en la carpeta data del contenedor y en el volumen de Docker. Una forma sencilla para realizar una copia de la carpeta data, es utilizando el comando docker de copiado. Así, para realizar una copia de la carpeta data del contenedor utilizado mynodered a una carpeta determinada, se puede emplear el siguiente comando:

docker cp  mynodered:/data  /your/backup/directory

En las siguiente entrada, NodeRED II: nodos principales, iré profundizando en la definición de flujos y usos de NodeRED.

Broker Mosquitto con MQTTS

Hace un tiempo publiqué una entrada cuyo tema principal era el protocolo MQTT mediante el broker Eclipse Mosquitto. En la entrada de hoy, Broker Mosquitto con MQTTS, describiré cómo utilizar el protocolo MQTT de forma segura, es decir, cómo utilizar el protocolo MQTTS.

El protocolo MQTT es un protocolo muy utilizado en los sistemas IoT y, para conseguir un nivel de seguridad adecuado, es necesario utilizar el protocolo con comunicaciones seguras.

1.-Componentes de seguridad

Para la creación de los certificados, claves privadas y los certificados de solicitud de firma utilizaremos OpenSSL. En los siguientes apartados, realizaré la descripción de los elementos necesarios para nuestro ejemplo de prueba.

Para facilitar la comprensión de los elementos a crear y la configuración del broker, utilizaré una carpeta, con nombre certs, en la cual se ubicarán las siguientes carpetas: carpeta ca, carpeta para almacenar los componentes de seguridad de la autoridad certificadora; carpeta broker, carpeta para almacenar los componentes de seguridad para el broker MQTT; y, por último, la carpeta client, carpeta para almacenar los componentes de seguridad para los clientes, en nuestro caso, los agentes con funcionalidad de publicadores y suscriptores.

La herramienta a utilizar para la creación de los diferentes componentes es OpenSSL la cual se encuentra instalada al menos en los sistemas Linux o Mac de forma predeterminada. Para utilizarla simplemente invocamos el comando openssl desde una consola de comandos.

1.1.- Creación de certificados

La creación de la autoridad de certificados la realizamos con el comando openssl y, para ello, nos ubicamos en la carpeta ~/certs2/ca en una consola de comandos. El comando a utilizar es el siguiente:

openssl req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt

El comando anterior realiza la creación de un certificado definido en el fichero ca.crt y realiza la creación de una clave privada en el fichero ca.key. La validez del certificado es de un año (365 días) desde la fecha de creación. El comando requiere la introducción de unos campos necesarios como son, entre otros: password del certificado, país, ciudad, nombre de la compañía,…

1.2.- Creación de clave privada y certificados para el broker

La creación de las claves y certificados necesarios para el broker la realizamos con el comando openssl y, como en el casa anterior, nos ubicamos en la carpeta creada para ello, carpeta ~/certs2/broker. En este caso, debemos de realizar más operaciones las cuáles son:

  • Generación de una clave privada.

Para la creación de una clave privada RSA para el broker ejecutamos el siguiente comando:

openssl genrsa -out broker.key 2048

El comando anterior realiza la creación de una clave RSA en el fichero broker.key

  • Generación del fichero de solicitud de firmas csr.

Para la creación del fichero para realizar la solicitud de firmas para los certificados se emplea el siguiente comando openssl el cual utiliza la clave privada creada previamente, el comando es el siguiente:

openssl req -out broker.csr -key broker.key -new

La ejecución del comando anterior requiere de la inserción de un conjunto de datos como son, entre otros: país, ciudad y otros datos de identificación; de todos ellos, requiere una especial atención el campo CN Command Name el cual identifica el nombre del dominio en donde se ejecuta el broker, en nuestro caso, el campo CN tiene el valor ‘localhost’.

  • Generación del fichero certificado.

Por último, realizamos la creación del certificado con todos los elementos creados previamente. El comando es el siguiente:

openssl x509 -req -in broker.csr -CA ../ca/ca.crt -CAkey ../ca/ca.key -CAcreateserial -out broker.crt -days 100

El comando anterior realiza un certificado en el fichero broker.crt con una validez de 100 días utilizando el fichero de solicitud de firmas broker.csr y los ficheros de la autoridad certificadora ca.crt y ca.key.

1.3.- Creación de clave privada y certificados para los clientes

La creación de las claves y certificados necesarios para el broker lo realizamos con el comando openssl y, como en el casa anterior, nos ubicamos en la carpeta creada para ello, carpeta ~/certs2/client. En este caso, debemos de realizar más operaciones las cuáles son:

  • Generación de una clave privada.

Para la creación de una clave privada RSA para el cliente ejecutamos el siguiente comando:

openssl genrsa -out client.key 2048

El comando anterior realiza la creación de una clave RSA en el fichero client.key

  • Generación del fichero de solicitud de firmas csr.

Para la creación del fichero para realizar la solicitud de firmas para los certificados se emplea el siguiente comando openssl el cual utiliza la clave privada creada previamente, el comando es el siguiente:

openssl req -out client.csr -key client.key -new

La ejecución del comando anterior requiere de la inserción de un conjunto de datos como son, entre otros: país, ciudad y otros datos de identificación; de todos ellos, requiere una especial atención el campo CN Command Name el cual identifica el nombre del dominio en donde se ejecuta el broker, en nuestro caso, el campo CN tiene el valor ‘localhost’.

  • Generación del fichero certificado.

Por último, realizamos la creación del certificado con todos los elementos creados previamente. El comando es el siguiente:

openssl x509 -req -in client.csr -CA ../ca/ca.crt -CAkey ../ca/ca.key -CAcreateserial -out client.crt -days 100

El comando anterior realiza un certificado en el fichero client.crt con una validez de 100 días utilizando el fichero de solicitud de firmas client.csr y los ficheros de la autoridad certificadora ca.crt y ca.key.

2.- Configuración del broker Mosquitto

La configuración del broker Mosquitto se realiza en el fichero mosquitto.conf ubicado en la carpeta de instalación del mismo. Para poder operar con el broker es necesario que la configuración sea como mínimo la siguiente:

  listener 8883
  certfile /Users/usuario/mosquitto/certs2/broker/broker.crt
  keyfile /Users/usuario/mosquitto/certs2/broker/broker.key
  require_certificate true
  cafile /Users/usuario/mosquitto/certs2/ca/ca.crt
  use_identity_as_username true

3.- Ejemplo de uso

3.1.- Arranque del broker

Para arrancar Mosquitto con la configuración, en un entorno Linux/Mac, el comando a ejecutar es el siguiente:

/usr/local/opt/mosquitto/sbin/mosquitto -c /usr/local/etc/mosquitto/mosquitto.conf

La salida por consola del broker es la siguiente:

Consola del broker Mosquitto

3.2.- Arranque del suscriptor.

Pare simular la recepción de un mensaje utilizaremos la herramienta mosquitto_sub el cual simula la suscripción de un elemento. El comando a utilizar para ejecutar un suscriptor desde línea de comando es el siguiente:

mosquitto_sub -h localhost -t "casa/habitaciones/hab1/luz" --cafile "/Users/E050690/mosquitto/certs2/ca/ca.crt"  --cert "/Users/E050690/mosquitto/certs2/client/client.crt" --key "/Users/E050690/mosquitto/certs2/client/client.key" -p 8883

Los parámetros del comando anterior tienen la siguiente descripción:

  • -h.- Nombre del host donde está funcionando Mosquitto. Es el mismo nombre que el campo CN de los certificados.
  • -t.- Topic del broker donde se conecta el suscriptor.
  • –cafile.- Localización del certificado de la entidad certificadora.
  • –cert.- Localización del certificado del cliente, en nuestro caso, el componente suscriptor.
  • –key.- Localización de la clave privada del cliente, en nuestro caso, el componente suscriptor.
  • -p.- Puerto del protocolo MQTTS.

La consola del suscriptor queda vacía a la espera de los mensajes que realice el publicador/productor.

3.3.- Arranque del publicador.

Para simular el envío de un mensaje utilizaremos la herramienta mosquitto_pub el cual realiza la producción de mensajes a un topic del broker. El comando a utilizar para ejecutar una publicación de un mensaje desde la línea de comandos el el siguiente:

mosquitto_pub -h localhost -t "casa/habitaciones/hab1/luz" --cafile "/Users/E050690/mosquitto/certs2/ca/ca.crt"  --cert "/Users/E050690/mosquitto/certs2/client/client.crt" --key "/Users/E050690/mosquitto/certs2/client/client.key" -p 8883  -m "ON1"

Los parámetros del comando anterior tienen la siguiente descripción:

  • -h.- Nombre del host donde está funcionando Mosquitto. Es el mismo nombre que el campo CN de los certificados.
  • -t.- Topic del broker donde se publica el mensaje.
  • –cafile.- Localización del certificado de la entidad certificadora.
  • –cert.- Localización del certificado del cliente, en nuestro caso, el componente publicador.
  • –key.- Localización de la clave privada del productor, en nuestro caso, el componente publicador.
  • -p.- Puerto del protocolo MQTTS.
  • -m.- Mensaje que se publica en el topic -t

La salida de la consola del broker Mosquitto es la siguiente:

Consola del broker Mosquitto

La salida de la consola del simulador de del suscriptor es la siguiente:

4.- Conclusiones

La complejidad del ejercicio planteado es la creación de los certificados, claves privadas y certificados de petición de firma ya que la configuración y uso del suscriptor, publicador y broker, si se sabe su uso sin certificados, es relativamente sencilla. Un detalle importante es el valor asignado al campo Command Name (CN) de los certificados de firma ya que un valor erróneo puede originar errores de protocolo en las pruebas.

Cliente Mosquitto: Paho-mqtt

En la anterior entrada con título «Mosquitto», realicé la descripción del broker Mosquitto, explicando las tareas de instalación, estructuras de carpetas y uso del Broker desde la consola del sistema. En esta entrada, «Cliente Mosquitto: Paho-mqtt», me centraré en cómo los dispositivos se pueden conectar al broker Mosquitto utilizando la librería Paho-mqtt.

Paho-mqtt es aquella librería cliente en lenguaje Python la cual implementa la versión 3.1 y 3.1.1 del protocolo MQTT.

Creación del proyecto

Para la realización de los ejemplos con el cliente Paho-mqtt, reallizaré la creación de un proyecto Python con el cliente Paho-mqtt. El proceso de creación consistirá en lo siguiente:

  1.  Creación de un proyecto Python en el IDE.
  2. Desde la carpeta del proyecto y en la consola del sistema, creación del entorno virtual del proyecto ejecutando el siguiente comando:
     python3 -m venv venv
  3. Desde la carpeta del proyecto y en la consola del sistema, instalación del cliente Paho-mqtt ejecutando el siguiente comando:
     pip install paho-mqtt

Una vez realizado los pasos anteriores, tenemos creado un proyecto Python con el cliente Paho-mqtt para desarrollar los publicadores y subscriptores del broker Mosquitto.

Broker Mosquitto

Para realizar las pruebas, necesitamos arrancar el broker Mosquitto, un publicador y un subscriptor para realizar las pruebas. Los pasos a seguir y la estructura de topics serán los mismos que en la entrada anterior. Los comandos a ejecutar son los siguientes:

  • Para el arranque del broker Mosquitto en el puerto por defecto en la línea de comandos, se realiza con el siguiente comando:
sudo /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf
  • Para el arranque de un publicador en la línea de comandos, se realiza con el siguiente comando:
mosquitto_pub -t "casa/habitaciones/hab1/luz" -m "ON"
  • Para el arranque de un subscriptor en la línea de comandos, se realiza con el siguiente comando:
mosquitto_sub -t "casa/habitaciones/hab1/luz" -v

Una vez realizados estos pasos, tenemos el broker levantado, las consolas del publicador y subscriptor abiertas para ver la actividad existente.

Publicadores

En el presente apartado, me centraré en presentar tres ejemplos de publicación de mensajes en un topic del broker Mosquitto. El publicador es aquel elemento que genera mensajes que son enviados al broker Mosquitto.

Ejemplo básico

El primer ejemplo, lo realizamos en un fichero Python con nombre publicador_ejem1.py, es aquel ejemplo básico de creación de un cliente, conexión al broker y publicación del mensaje «Ejemplo desde Python» en el topic del broker Mosquitto.

El snippet del código es el siguiente:

 import paho.mqtt.client as mqtt

 broker_address = "localhost"
 client = mqtt.Client('Publicador_ejem1') # Creación del cliente
 client.connect(broker_address)
 topic = "casa/habitaciones/hab1/luz"

 client.publish(topic, "Ejemplo desde Python")

Tras la ejecución de publicador_ejem1.py, la salida en la consola del subscriptor Mosquitto, abierta conforme lo descrito en el apartado anterior, es la siguiente:

casa/habitaciones/hab1/luz Ejemplo desde Python

Ejemplo publicador de un mensaje

El segundo ejemplo, lo realizamos en un fichero Python con nombre publicador_ejem2.py, es aquel ejemplo de creación de un publicador, definición del topic al cual informar, y envío del mensaje «Ejemplo de publicador simple desde Python» al broker Mosquitto mediante la función single del publicador. El snippet del código es el siguiente:

 import paho.mqtt.publish as publish

 broker_address = "localhost"
 topic = "casa/habitaciones/hab1/luz"
 publish.single(topic, "Ejemplo de publicador simple desde Python", hostname=broker_address,
 client_id='publicador_ejem2.py')

Tras la ejecución de publicador_ejem2.py, la salida en la consola del subscriptor Mosquitto, abierta conforme lo descrito en el apartado anterior, es la siguiente:

casa/habitaciones/hab1/luz Ejemplo de publicador simple desde Python

Ejemplo publicador de mensaje múltiple

El tercer ejemplo, lo realizamos en un fichero Python con nombre publicador_ejem3.py, es aquel que utiliza un publicador, se definen tres mensajes (mensaje1, mensaje2 y mensaje3) para ser enviados al broker Mosquitto mediante la función multiple del publicador. El snippet del código es el siguiente:

 import paho.mqtt.publish as publish

 broker_address = "localhost"
 topic = "casa/habitaciones/hab1/luz"
 mensaje1 = "Mensaje 1 de un envío multiple"
 mensaje2 = "Mensaje 2 de un envío multiple"
 mensaje3 = "Mensaje 3 de un envío multiple"

 msgs = [{'topic': topic, 'payload': mensaje1},
 (topic, mensaje2, 0, False),
 (topic, mensaje3, 0, False)]

 publish.multiple(msgs, hostname=broker_address)

Tras la ejecución de publicador_ejem3.py, la salida en la consola del subscriptor Mosquitto, abierta conforme lo descrito en el apartado anterior, es la siguiente:

casa/habitaciones/hab1/luz Mensaje 3 de un envío multiple
casa/habitaciones/hab1/luz Mensaje 2 de un envío multiple
casa/habitaciones/hab1/luz Mensaje 1 de un envío multiple

Subscriptores

En el presente apartado, me centraré en presentar tres ejemplos de subscriptores de mensajes en un topic del broker Mosquitto. El subscriptor es aquel elemento que recibe mensajes de un topic del broker Mosquitto originados en un publicador determinado.

Ejemplo básico de subscriptor

El primer ejemplo, lo realizamos en el fichero subscriptor_ejem1.py, es aquel que utiliza un cliente MQTT con las siguientes tareas: definición de un callback para la recepción de mensajes del topic en la función on_message; conexión al broker con la función connect;y, la subscripción al topic del broker de Mosquitto, mediante la función subscribe. El presente ejemplo realiza solo una iteración por las funciones loop_start() y loop_stop. El snippet del código es el siguiente:

import time
import paho.mqtt.client as mqtt # import the client1

broker_address = "localhost"
broker_port = 1883
topic = "casa/habitaciones/hab1/luz"

def on_message(client, userdata, message):
 print("Mensaje recibido=", str(message.payload.decode("utf-8")))
 print("Topic=", message.topic)
 print("Nivel de calidad [0|1|2]=", message.qos)
 print("Flag de retención o nuevo?=", message.retain)

client = mqtt.Client("Subscriptor_ejem1")
client.on_message = on_message 
client.connect(broker_address) 
client.loop_start() # Inicio del bucle
client.subscribe(topic)
time.sleep(10) # Paramos el hilo para recibir mensajes.
client.loop_stop() # Fin del bucle

Tras la ejecución del subscriptor_ejem1.py y tras la publicación de un mensaje en la consola Mosquitto, conforme a lo descrito en el apartado anterior, la salida es la siguiente:

Mensaje recibido= PRUEBA
Topic= casa/habitaciones/hab1/luz
Nivel de calidad [0|1|2]= 0
Flag de retención o nuevo?= 0

Ejemplo de subscriptor de N mensajes

El segundo ejemplo, lo realizamos en el fichero subscriptor_ejem2.py, es aquel ejemplo que espera infinitos mensajes de un topic del broker Mosquitto. Las operaciones son casi las mismas al apartado anterior, estando las diferencias en la definición de un bucle infinito con la función loop_forever(). El snippet del código es el siguiente:

import paho.mqtt.client as mqtt

broker_address = "localhost"
broker_port = 1883
topic = "casa/habitaciones/hab1/luz"

def on_message(client, userdata, message):
 print("Mensaje recibido=", str(message.payload.decode("utf-8")))
 print("Topic=", message.topic)
 print("Nivel de calidad [0|1|2]=", message.qos)
 print("Flag de retención =", message.retain)

client = mqtt.Client('Cliente1') 
client.on_message = on_message 
client.connect(broker_address, broker_port, 60) 
client.subscribe(topic) # Subscripción al topic
client.loop_forever()

Tras la ejecución del subscriptor_ejem2.py y tras la publicación de dos mensajes en el consola Mosquitto, conforme a lo descrito en el apartado anterior, la salida es la siguiente:

Mensaje recibido= PRUEBA1
Topic= casa/habitaciones/hab1/luz
Nivel de calidad [0|1|2]= 0
Flag de retención = 0
Mensaje recibido= PRUEBA2
Topic= casa/habitaciones/hab1/luz
Nivel de calidad [0|1|2]= 0
Flag de retención = 0

Ejemplo con control de conexión al topic

El tercer ejemplo, lo realizamos en el fichero subscriptor_ejem3.py, es aquel ejemplo que espera infinitos mensaje de un topic del broker Mosquitto pero se define un callback para realizar la conexión definida en la función on_connect; este callback, si se pierde la conexión, realiza la reconexión al topic. El snippet del código es el siguiente:

import paho.mqtt.client as mqtt
broker_address = "localhost"
broker_port = 1883
topic = "casa/habitaciones/hab1/luz"

def on_connect(client, userdata, flags, rc):
 print("Connected with result code " + str(rc))
 print("UserData= " + str(userdata))
 print("flags= " + str(flags))
 print("")
 client.subscribe(topic)

def on_message(client, userdata, message):
 print("Mensaje recibido=", str(message.payload.decode("utf-8")))
 print("Topic=", message.topic)
 print("Nivel de calidad [0|1|2]=", message.qos)
 print("Flag de retención=", message.retain)
 print("---------------------------------------------")
 print("")

client = mqtt.Client('Cliente1', userdata="UsuarioDePrueba") 
client.on_connect = on_connect 
client.on_message = on_message 
client.connect(broker_address, broker_port, 60) 
client.loop_forever()

Tras la ejecución del subscriptor_ejem3.py y tras la publicación de un mensaje en el consola Mosquitto, conforme a lo descrito en el apartado anterior, la salida es la siguiente:

Connected with result code 0
UserData= UsuarioDePrueba
flags= {'session present': 0}

Mensaje recibido= PRUEBA
Topic= casa/habitaciones/hab1/luz
Nivel de calidad [0|1|2]= 0
Flag de retención= 0
---------------------------------------------

La definición de componentes software con la librería Paho-mqtt para la comunicación con el broker Mosquitto, es una tarea sencilla teniendo claro el modelo productor/consumidor. En los ejemplos descritos, se centran en la comunicación con el broker faltando el desarrollo de captura de datos de los sensores o componentes los cuales han sido simulados desde la consola de Mosquitto.

Mosquitto

Mosquitto es un broker de mensajería Open Source(licencia EPL/EDL) que implementa el protocolo MQTT para las versiones 3.1 y 3.1.1. Mosquitto es parte de Eclipse foundation y es un proyecto de Eclipse. Mosquitto es ligero y es adecuado para todos los dispositivos, desde computadoras de baja potencia hasta servidores complejos.

El protocolo MQTT (MQ Telemetry Transport or Message Queuing Telemetry Transport) es un estándar ISO basado en un método sencillo para realizar intercambio de mensajes conforme el modelo productor-consumidor en sistemas de Internet de las cosas ( IoT – Internet of the Thinks). Los dispositivos que se conectan pueden ser sensores, dispositivos móviles, microcontroladores o sistemas embebidos.

El sketchnote de la entrada es el definido en la siguiente imagen:

Instalación

La descripción del proceso de instalación está basada en plataformas Linux; pero, para el resto de plataformas (Windows, Mac,…), el proceso de instalación es el típico para dichas plataformas. La información de instalación para cada plataforma, se encuentra en el apartado Download de la documentación oficial.

Los comandos a ejecutar para la instalación de Mosquitto son los siguientes:

sudo apt-add-repository ppa:mosquitto-dev/mosquitto-ppa
sudo apt-get update
sudo apt-get install python-software-properties
sudo apt-get install mosquitto

Estructura de carpetas

El proceso de instalación nos creará una estructura de directorios como la siguiente:

  • /etc/mosquitto.- Carpeta con los ficheros de configuración del broker. El contenido del directorio es el siguiente:

-> directorio ca_certificates.-Directorio de certificados

-> certs.- Directorio de certificados

-> conf.d .- Directorio de configuración

-> mosquitto.conf .- Fichero de configuración

  • /usr/sbin .- En esta carpeta se localiza el fichero de arranque mosquitto.sh
  • /var/log/mosquitto .- Directorio en el que se encuentra el fichero mosquitto.log

Inicio del broker

Para iniciar el broker de mensajería Mosquitto es necesario la ejecución del comando mosquitto identificando la ubicación del fichero de configuración. El comando de ejecución del broker es el siguiente:

sudo /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf

El flag -c indica al comando mosquitto la ubicación del fichero de configuración mosquitto.conf. Si se desea conocer la información del comando, es decir, la ayuda del comando, se puede ejecutar el comando:

/usr/sbin/mosquitto -h

El resultado de la ejecución del comando, será que el broker Mosquitto está ejecutándose en la máquina en el puerto por defecto 1883.

Cliente del Broker

Una vez instalado e iniciado el broker es necesario definir el mecanismo por el cual poder conectarse y realizar una comunicación. Para realizar dichas operaciones, es necesario la instalación de un cliente específico MQTT; dicho cliente, servirá para la realización de simulaciones de dispositivos MQTT. El nombre del dispositivo es mosquitto-clients y, el comando de instalación en la plataforma Linux, es el siguiente:

sudo apt-get install mosquitto-clients

El cliente instalado es aquel cliente que permite simular el funcionamiento de los productores, entidades que generan información MQTT; y, consumidores, entidades que reciben los datos suministrados por los productores.

Para el broker Mosquitto, los productores de datos se denominan publicadores y, los que consumen los datos, subscriptores.

Topic

Llegado a este punto, disponemos del broker MQTT instalado y ejecutándose; tenemos instalado el cliente para definir los publicadores y los subscriptores; pero, no tenemos definido el mecanismos de interconexión entre los clientes. El mecanismo en cuestión son los topics. Los topics son aquellos buzones en los cuales los publicadores dejan sus mensajes. Así, un publicador dejan en un topic aquel mensaje que quiere transmitir al subscritor; y, el subscriptor, en el instante de la publicación de un mensaje, recibe dicho mensaje.

Como he comentado antes, los dispositivos que se pueden conectar son múltiples: sensores, sistemas embedidos, dispositivos móviles; con lo cual, es necesario una organización de todos los elememtos. Así, para el supuesto de un sistema IoT de los sensores de una casa, podemos definir los dispositivos en una estructura jerárquica de la siguiente forma:

casa

habitaciones

hab1

luz: sensor de luz

temperatura: sensor de temperatura

hab2

luz: sensor de luz

temperatura: sensor de temperatura

trastero

luz: sensor de luz

temperatura: sensor de temperatura

humedad: sensor de humedad

Dada la estructura anterior, definimos los siguientes topic como ejemplos en el broker de la siguiente manera:

  • casa/habitaciones/hab1/luz.- Topic del sensor de luz de la habitación 1
  • casa/habitaciones/hab2/luz.- Topic del sensor de luz de la habitación 2
  • casa/trastero/humedad.- Topic del sensor de humedad del Trastero.

Ejemplos

Los clientes del broker MQTT Mosquitto pueden ser: subscriptores, entidades que reciben datos de sensores; y, publicadores, los sensores que envían datos al broker. Para realizar la simulación desde consola, utilizamos los comandos siguientes comandos: mosquitto_sub, comando para la simulación de subscriptores; y, mosquitto_pub, comando para la simulación de sensores.

En los siguientes apartados, describiré la ejecución de cada uno de los comados.

Subscriptor

El comando para la simulación de subscriptores es el comando mosquitto_sub. Un ejemplo básico de subscripción en el topic «casa/habitaciones/hab1/luz» es el siguiente:

mosquitto_sub -t "casa/habitaciones/hab1/luz" -v

El flag -t identifica el topic de subscripción y, el flag -v, indica que sea verboso. Para visualizar la ayuda del comando se ejecuta el comando con los flag –help.

Publicador

El comando para la simulación de publicadores de mensajes es el comando mosquitto_pub. En ejemplo básico de publicación del mensaje «ON» en el topic «casa/habitaciones/hab1/luz» es el siguiente:

mosquitto_pub -t "casa/habitaciones/hab1/luz" -m "ON"

El flag -t identifica el topic de subscripción y, el flag -m, identifica el mensaje a enviar al broker.Para visualizar la ayuda del comando se ejecuta el comando con los flag –help.

La publicación del mensaje «ON» produce la salida por consola de subscriptor. Así, la salida de la consola del subscriptor es la siguiente:

casa/habitaciones/hab1/luz ON

Conclusiones

El broker MQTT Mosquitto es un broker ligero y sencillo de utilizar. En la presente entrada, me he centrado en la instalación y casos de uso básicos, no he tratado en esta entrada los aspectos orientados a la seguridad los cuáles en los sistemas IoT son importantes.

Desde un punto de vista genérico, el funcionamiento de Mosquitto es el típico de un broker que implementa un modelo productor/consumidor.

En la siguiente entrada, me centraré en la utilización del broker Mosquitto desde una aplicación en Python con el cliente paho-mqtt.