IOT Discovery
Este documento describe la funcionalidad IOT de de PandoraFMS, compuesta por un servidor broker MQTT y un plugin de discovery.
- Introducción
- Elementos de la integración IOT
- Instalación manual
- Prerrequisitos
- Parámetros servidor MQTT
- Configurando el servidor MQTT
- Parámetros del plugin de Discovery
- Configurando el plugin de Discovery
- Configurando el filtrado de mensajes
- Ejecución manual
- Agentes y módulos generados por el plugin
Introducción
La integración Pandora IOT tiene como finalidad supervisar mensajes que se reciben de un servidor broker de mqtt.
Para ello, la integración hace uso de un servidor broker MQTT, que abre la posibilidad de suscribirse a un topic para recibir mensajes y un plugin de Discovery, que permite configurar un filtrado de estos mensajes y visualizar el postprocesado de estos en la consola de PandoraFMS mediante agentes y módulos que se envían vía XML al servidor de pandora.
El monitoreo de dispositivos IoT (Internet de las Cosas) permite supervisar en tiempo real el estado de equipos y sensores conectados, facilitando la toma de decisiones rápidas y eficaces. Al integrar estos dispositivos en sistemas de monitoreo, las empresas pueden detectar problemas de manera anticipada, optimizar sus operaciones y reducir tiempos de inactividad.
¿Porque es útil monitorizar dispositivos IoT?
Imagina que tienes sensores de temperatura en una planta industrial y el servidor MQTT recibe mensajes con valores de temperatura cada minuto, la integración puede filtrar aquellos valores que estén fuera del rango aceptable (por ejemplo, > 80°C) y generar un módulo de alerta en PandoraFMS, lo que puede ayudar a prevenir problemas y protegernos ante posibles incidencias.
Elementos de la integración IOT
La integración IOT se compone principalmente de dos elementos clave, un servidor broker MQTT que se encargara de recibir los mensajes y almacenarlos en base de datos y un plugin de discovery que se encargara de filtrar estos mensajes previamente almacenados en base de datos y procesar estos para una visualización según sea requerida de estos que facilitara la automatización de alarmas o lo que sea necesario realizar con estos datos.
-
Servidor MQTT
Este servicio se encarga de conectarse a un servidor MQTT, recibir mensajes de un tema específico y almacenarlos en una base de datos. También registra logs en archivos y en la consola, limpia periódicamente los datos antiguos y maneja correctamente el cierre del programa para evitar pérdidas de información.
-
Plugin discovery
Este script se encarga de conectarse a la base de datos en los que se han almacenado los mensajes previamente con el receptor, realizar un filtrado de mensajes en base a una configuración previamente realizada por el usuario y crea agentes y módulos en base a los mensajes que pasan los filtros.
Instalación manual
Puedes realizar una instalación manual del servidor MQTT de la siguiente manera:
el8
Debes instalar el fichero .rpm llamado pandora_iot_server-1.0-1.el8.x86_64.rpm
sudo dnf install ./pandora_iot_server-1.0-1.el8.x86_64.rpm
el9
Debes instalar el fichero .rpm llamado pandora_iot_server-1.0-1.el9.x86_64.rpm
sudo dnf install ./pandora_iot_server-1.0-1.el9.x86_64.rpm
ubuntu
Debes instalar el fichero .deb llamado pandora_iot_server_1.0-1.deb
sudo dpkg -i pandora_iot_server_1.0-1.deb
Una vez ejecutado el comando, nos pedirá confirmación, para instalar el server.
Después de aceptar, se instalará el servidor y podremos empezar a configurar la escucha de mensajes.
Prerrequisitos
- El servidor MQTT debe estar instalado en el entorno en el que se pretende realizar la escucha de mensajes.
- El plugin de discovery, debe estar previamente cargado en PandoraFMS para poder configurar las tareas.
- Se requiere conectividad al servidor MQTT
- Se requiere conectividad hacia la base de datos que almacenara los mensajes.
Parámetros servidor MQTT
Parámetros
-c,--conf_file | Ruta al archivo de configuración |
-v,--verbosity | Activar modo debug |
Archivo de configuración (--conf)
[DEFAULT]
;;topic
topic = < Topic al que se suscribirse para recibir mensajes. >
;; connection
host = < Host del servidor en el que se escucharan los mensajes >
port = < Puerto del servidor en el que se escucharan los mensajes >
;; protocol supports: tcp, websockets, unix
; protocol = < Tipo de protocolo. Aceptados : tcp, websockets, unix
; user = < Usuario >
; password = < Contraseña >
; ssl = 0 < Activar cifrado ssl >
; trust_ssl = < Verificacion de certificado >
;; Database
; dblocation = < Localización del fichero de base de datos >
; dbname = < Nombre del fichero de base de datos >
; data_cleaning_interval = 300 < Periodo de restablecimiento de los datos >
; data_cleaning_period = < Periodo de antigüedad de los datos a restablecer>
;; Logs
;; log_name = < Nombre del fichero de logs >
; log_location = < Ruta del fichero de logs >
; log_level = < Nivel del log >
; max_log_bytes = < Tamaño máximo de log >
; log_rotation_count = < Número de ficheros de log que se almacenan despus de rotar, por defecto: 3 >
Ejemplo
[DEFAULT]
;;topic
topic = testtopic/#
;; connection
host = test.mosquitto.org
port = 1883
;; protocol supports: tcp, websockets, unix
; protocol = websockets
; user = ro
; password = readonly
; ssl = 0
; trust_ssl = 1
;; Database
dblocation = /opt/pandora/pandora_iot_server/db
dbname = pandora_iot.db
; data_cleaning_interval = 300
; data_cleaning_period = 86400
;; Logs
log_name = pandora_iot.log
log_location = /var/log/pandora/
; log_level = debug
; max_log_bytes = 50_000_000
; log_rotation_count = 3
Configurando el servidor MQTT
Este script permite suscribirse a un tópico MQTT, recibir mensajes y almacenarlos en una base de datos SQLite. A continuación se describen los pasos para configurarlo y ejecutarlo correctamente.
1.Configuración del archivo de configuración
Antes de ejecutar el script, se debe crear un archivo de configuración en formato .ini. Este archivo contiene los parámetros necesarios para la conexión al broker MQTT, la base de datos y la configuración de logs. Un ejemplo de archivo de configuración es el siguiente:
[DEFAULT]
;;topic
topic = testtopic/#
;; connection
host = test.mosquitto.org
port = 1883
;; protocol supports: tcp, websockets, unix
; protocol = websockets
; user = ro
; password = readonly
; ssl = 0
; trust_ssl = 1
;; Database
dblocation = /opt/pandora/pandora_iot_server/db
dbname = pandora_iot.db
; data_cleaning_interval = 300
; data_cleaning_period = 86400
;; Logs
log_name = pandora_iot.log
log_location = /var/log/pandora/
; log_level = debug
; max_log_bytes = 50_000_000
; log_rotation_count = 3
Parámetros clave:
topic
: Define el tópico MQTT al que se suscribirá el script (por ejemplo,testtopic/#
).host
: Especifican la dirección del broker MQTT.port
: Especifican el puerto del broker MQTT.protocol
: El protocolo a usar para la conexión MQTT (por ejemplo,tcp
owebsockets
).ssl
: Habilita o deshabilita la conexión SSL. (0 para deshabilitar, 1 para habilitar).trust_ssl
: Controla si se debe confiar en los certificados SSL del broker.dblocation
: Directorio donde se almacenará la base de datos SQLite.dbname
: Nombre de la base de datos SQLite.- data_cleaning_interval: Intervalo de tiempo (en segundos) entre cada ejecución del proceso de limpieza de datos.
- data_cleaning_period: Tiempo (en segundos) para eliminar datos antiguos de la base de datos.
- log_name: Nombre del archivo donde se almacenarán los logs.
log_location
: Directorio donde se almacenarán los archivos de log.log_level
: Nivel de detalle de los logs (por ejemplo,debug
).- max_log_bytes: Tamaño máximo (en bytes) que puede alcanzar un archivo de log antes de rotarse.
- log_rotation_count: Número máximo de archivos de log que se conservarán antes de eliminar los más antiguos.
2. Arrancar el servicio.
Se podrá lanzar el servicio con el siguiente comando :
systemctl start pandora_iot_server
Para dejar de recibir y almacenar mensajes se puede pausar el servicio con :
systemctl stop pandora_iot_server
Se debe reiniciar el servicio con cada cambio de configuración para que haga efecto:
systemctl restart pandora_iot_server
Parámetros del plugin de Discovery
Parámetros
--conf | Ruta al archivo de configuración |
--filter_conf | Ruta al achivo de filtros para los mensajes |
--verbosity | Sirve para activar el modo debug |
Archivo de configuración (--conf)
db_path = Ruta a la base de datos sql lite
threads = < Número máximo de threads utilizados >
timestamp_filter = < Timestamp en segundos desde el que se filtraran los mensajes >
agents_group_name = < Nombre de grupo para los agentes creados >
interval = < Intervalo en segundos para los agentes >
tentacle_ip = < IP de la máquina destino para los agentes creados >
tentacle_port = < Puerto de tentacle, por defecto : 41121 >
Ejemplo
db_path = /opt/pandora/pandora_iot_server/db/pandora_iot.db
threads = 4
timestamp_filter = 1738000000
agents_group_name = Unknown
interval = 300
tentacle_ip = 127.0.0.1
tentacle_port = 41121
Archivo para filtrar los mensajes (--filter_conf)
#=======================================================================
#Configuración de filtros
#=======================================================================
filter_begin: < Marca el inicio de una configuración de filtro. Todo lo que esté hasta filter_end pertenece al mismo filtro. Obligatorio. >
filter_module_name: < Nombre asignado al módulo que genera el filtro. Obligatorio. >
filter_module_type: < Tipo de módulo que genera el filtro. Obligatorio. >
filter_topic: < Expresión regular o texto exacto que debe coincidir con el tema del mensaje para que se aplique el filtro. Opcional. Por defecto, coincide con cualquier tema. >
filter_topic_exact_match: < Define si filter_topic se trata como una expresión regular (0) o como texto exacto (1). Opcional. Por defecto es 0. >
filter_message: < Expresión regular o texto exacto que debe coincidir con el contenido del mensaje para que se aplique el filtro. Opcional. Por defecto, coincide con cualquier mensaje. >
filter_message_exact_match: < Define si filter_message se trata como una expresión regular (0) o como texto exacto (1). Opcional. Por defecto es 0. >
filter_message_capture_regex: < Expresión regular con grupos de captura para extraer valores del mensaje. >
< Los valores capturados se almacenarán en macros '__regexN__', donde N es el índice del grupo de captura. >
filter_message_capture_json: < Lista de rutas JSON (separadas por '|') para extraer valores, utilizando el mismo formato que jq. >
< Los valores capturados se almacenarán en macros '__jsonN__', donde N es el índice de la ruta. >
filter_module_value: < Valor asignado al módulo que genera el filtro. Obligatorio. >
filter_end: < Marca el final de una configuración de filtro. Todo lo que esté desde filter_begin pertenece al mismo filtro. Obligatorio. >
#Macros disponibles para su uso en filter_module_name y filter_module_value:
__topic__: < Se reemplaza con el tema exacto del mensaje procesado. >
__regexN__: < Se reemplaza con el valor correspondiente capturado por filter_message_capture_regex. >
__jsonN__: < Se reemplaza con el valor correspondiente capturado por filter_message_capture_json. >
Ejemplo
filter_begin
filter_module_name pressure
filter_module_type generic_data_string
filter_topic sensor/humidity
filter_topic_exact_match 1
filter_message Value:
filter_message_exact_match 1
filter_message_capture_regex (\b\w{6}\b).*?(\b\w{7}\b).*?(\d{3})\s(\w)-
filter_message_capture_json
filter_module_value 1__regex1__ __regex2__ __topic__
filter_end
filter_begin
filter_module_name humidity
filter_module_type generic_data_string
filter_topic sensor/pressure
filter_topic_exact_match 1
filter_message
filter_message_exact_match 1
filter_message_capture_regex
filter_message_capture_json $.extra_info[0].value|$.extra_info[1].value
filter_module_value 2 __json1__ __json2__
filter_end
Configurando el plugin de Discovery
Este plugin puede integrarse con el Discovery de Pandora FMS.
Para ello se debe cargar el paquete ".disco" que puede descargar desde la librería de Pandora FMS:
https://pandorafms.com/library/
Una vez cargado, se podrá recibir y supervisar mensajes de un broker, creando tareas de Discovery desde la sección Management > Discovery > App
Para cada tarea se solicitarán los siguientes datos mínimos:
- DB path: Ruta del fichero de base de datos. Por defecto : /opt/pandora/pandora_iot_server/db/pandora_iot.db
- Time window: Es la ventana de tiempo desde el punto que se ejecuta hasta x en el pasado en el que se aplicaran los filtros. Se especifica en segundos en formato timestamp.
- Tentacle IP: IP del servidor de Tentacle al que enviar los datos de los agentes. Normalmente este parámetro no se modificará.
- Tentacle port: Puerto del servidor de Tentacle al que enviar los datos. Normalmente este parámetro no se modificará.
- Tentacle extra options: Opciones extra de Tentacle.
También se podrá ajustar la configuración de los filtros para personalizar la monitorización deseada:
- Max threads: Número de hilos a utilizar.
- FIlter message modules: Opciones de configuración de filtros para los módulos. Mas detalle sobre las opciones y etiquetas posibles a utilizar en este apartado en la seccion " parámetros" de este manual.
Las tareas completadas con éxito tendrán un resumen de ejecución con la siguiente información:
- Total agents : Número total de agentes generados por la tarea.
- Total messages: Numero total de mensajes que han pasado los filtros.
Configurando el filtrado de mensajes
El plugin hace uso de distintos filtros en los que apoyarse para la filtración de mensajes.
Filtrado de topic
Para el filtrado de topic, se hace uso de las etiquetas Filter_topic y Filter_topic_exact_match
-
Filter_topic
Expresión regular o texto exacto que deba coincidir con el topic del mensaje para cumplirse el filtro. Es opcional. Por defecto haría match con cualquier topic.
-
Filter_topic_exact_match
Indica si lo indicado en filter_topic se tratará como una expresión regular (0) o como un texto exacto (1). Es opcional. Por defecto su valor es 0.
Ejemplos
Haciendo uso de los filtros Filter_topic y Filter_topic_exact_match podremos elegir el topic al que suscribirse.
Podemos indicar directamente el nombre del topic o buscar un patron de regex en este.
Supongamos que tienes un topic MQTT llamado:
sensors/temperature/livingroom
EJEMPLO 1 filter_topic_exact_match 1 (Texto exacto)
Podríamos configurar filter_topic especifando el nombre del topic.
filter_topic sensors/temperature/livingroom
y configurar filter_topic_exact_match a 1, para que busque solo ese topic.
filter_topic_exact_match 1
Si en vez de especificar el nombre del topic completo, especificamos solo una parte de este :
filter_topic sensors/temperature/
También coincidiría.
EJEMPLO 2 filter_topic_exact_match 0 (Expresión regular)
Podríamos configurar filter_topic especifando una expresión regular que haga match con el nombre del topic al que se pretende suscribir. Por ejemplo, la siguiente, que miraría que empiecen por "sensors" y terminen en "livingroom"
filter_topic ^sensors/.*?/livingroom$
y configurar filter_topic_exact_match a 0, para que filtre por expresión regular, en vez de texto exacto.
filter_topic_exact_match 0
Filtrado de mensajes
Para el filtrado de topic, se hace uso de las etiquetas Filter_topic y Filter_topic_exact_match
-
Filter_message
Expresión regular o texto exacto que deba coincidir con el mensaje para cumplirse el filtro. Es opcional. Por defecto haría match con cualquier mensaje.
-
FIlter_message_exact_match
Indica si lo indicado en filter_message se tratará como una expresión regular (0) o como un texto exacto (1). Es opcional. Por defecto su valor es 0.
Ejemplos
Haciendo uso de los filtros Filter_messagey Filter_message_exact_match podremos filtrar los mensajes que se van a recibir.
Podemos indicar directamente contenido del mensaje o buscar un patron de regex en este.
Supongamos que tienes un mensaje como este:
{"message":"Move up right",
"status":"active",
"datetime":"2025-02-11T14:30:54.260Z",
"data":{"yaw_rate":0.11466979980468749,
"pitch_rate":0.6159210205078126,
"yaw_direction":"right",
"pitch_direction":"up"}}
EJEMPLO 1 filter_message_exact_match 1 (Texto exacto)
Podríamos configurar filter_message especifando el texto del mensaje.
filter_message Move up right
y configurar filter_topic_exact_match a 1, para que busque solo ese topic.
filter_message_exact_match 1
Si en vez de especificar el nombre del topic completo, especificamos solo una parte de este :
filter_message Move up
También coincidiría.
EJEMPLO 2 filter_message_exact_match 0 (Expresión Regular)
Podríamos configurar filter_message especifando una expresión regular que haga match con los mensajes que se pretenden filtrar. Por ejemplo, la siguiente, buscaría un mensaje que contenga las palabras "move" y "right"
filter_message Move.*right|right.*Move
y configurar filter_message_exact_match a 0, para que filtre por expresión regular, en vez de texto exacto.
filter_message_exact_match 0
Generación y uso de macros
Ejemplos
Imagina que tenemos el siguiente mensaje:
{
"message": "Move up right",
"status": "active",
"datetime": "2025-02-11T14:30:54.260Z",
"data": {
"yaw_rate": 0.11466979980468749,
"pitch_rate": 0.6159210205078126,
"yaw_direction": "right",
"pitch_direction": "up"
}
}
Y queremos capturar algunas partes del mensaje, por ejemplo :
yaw_direction
(dirección del giro), que es"right"
.pitch_direction
(dirección de inclinación), que es"up"
.message
, que contiene"Move up right"
.
Además, también queremos capturar el topic
al que pertenece el mensaje en una macro para incluirlo en el valor.
Para ello deberíamos seguir los siguientes pasos, pudiendo hacerlo con Filter_message_capture_regex y FIlter_message_capture_json:
-
FIlter_message_capture_regex
Con Filter_message_capture_regex se espera una expresión regular con grupos de captura para obtener valores del mensaje. Aquello que haga match con los grupos de captura se almacenará en macros “__regexN__”, siendo N la posición del grupo de captura de la regex. Los pasos para configurar las macros a capturar serían los siguientes:
1. Configurar filter_message_capture_regex para capturar las partes necesarias:
Usamos una expresión regular para capturar "yaw_direction", "pitch_direction" y el contenido de "message".
filter_message_capture_regex \"yaw_direction\":\\s?\"(\\w+)\".*\"pitch_direction\":\\s?\"(\\w+)\".*\"message\":\\s?\"([^\"]+)\"
2. Configurar filter_module_value para incluir las macros que contienen los valores capturados y el topic.
filter_module_value __topic__ | Yaw Direction: __regex1__ | Pitch Direction: __regex2__ | Message: __regex3__
Ejemplo de configuración completa
filter_begin
filter_module_name __topic__ get right
filter_module_type generic_data_string
filter_topic testtopic/rgb/test/action/
filter_topic_exact_match 1
filter_message Move up right
filter_message_exact_match 1
filter_message_capture_regex \"yaw_direction\":\\s?\"(\\w+)\".*\"pitch_direction\":\\s?\"(\\w+)\".*\"message\":\\s?\"([^\"]+)\"
filter_message_capture_json
filter_module_value __topic__ | Yaw Direction: __regex1__ | Pitch Direction: __regex2__ | Message: __regex3__
filter_end
Entonces, con el mensaje y la configuración mostradas de ejemplos previamente, se crearía el siguiente agente:
Y el siguiente módulo de mensaje:
-
Filter_message_capture_json
Con Filter_message_capture_json se espera una lista de rutas dentro de un JSON (separadas por”|”) de las cuales capturar sus valores. Usando el mismo formato que el comando jq. Aquello que se capture por cada path se almacenará en macros “__jsonN__”, siendo N la posición del path dentro de la lista. . Los pasos para configurar las macros a capturar serían los siguientes:
1. Configurar filter_message_capture_json para capturar las partes necesarias del JSON.
filter_message_capture_json $.data.yaw_direction|$.data.pitch_direction|$.message
Las rutas JSONPath deben comenzar con $ porque representa la raíz del documento JSON.
2. Configurar filter_module_value para incluir las macros que contienen los valores capturados y el topic.
filter_module_value __topic__ | Yaw Direction: __json1__ | Pitch Direction: __json2__ | Message: __json3__
Ejemplo de configuración completa
filter_begin
filter_module_name __topic__ get right
filter_module_type generic_data_string
filter_topic testtopic/rgb/test/action/
filter_topic_exact_match 1
filter_message Move up right
filter_message_exact_match 1
filter_message_capture_regex
filter_message_capture_json $.data.yaw_direction|$.data.pitch_direction|$.message
filter_module_value __topic__ | Yaw Direction: __json1__ | Pitch Direction: __json2__ | Message: __json3__
filter_end
Entonces, con el mensaje y la configuración mostradas de ejemplos previamente, se crearía el siguiente agente:
Y el siguiente módulo de mensaje:
Ejecución manual
El formato de la ejecución del plugin es el siguiente:
./proccess_messages --conf < ruta al fichero de configuración > --filter_conf < ruta al fichero con los filtros para los mensajes >
Por ejemplo:
./proccess_messages --conf /var/spool/pandora/data_in/discovery/pandorafms.iot/file.conf --filter_conf /var/spool/pandora/data_in/discovery/pandorafms.iot/file_filters.conf
La ejecución devolverá una salida en formato JSON con información sobre la ejecución, y generará un fichero XML para cada agente (topic) y cada mensaje que haya pasado los filtros, que enviará al servidor de Pandora FMS por el método de transferencia indicado en la configuración.
Por ejemplo:
{"summary": {"Total agents": 2, "Total messages": 141}}
{"summary": {"Total agents": 2, "Total messages": 2}}
Agentes y módulos generados por el plugin
- Se creara un agente por cada topic que contenga mensajes que hayan pasado los filtros
- Se creará un módulo por cada mensaje que haya pasado los filtros.
Recuerda que no puede haber mas de un modulo con el mismo nombre en el mismo agente.