¿Qué aprenderá?
¿Qué hará?
¿Cuáles son los prerrequisitos?
Grafana es una tecnología web que ayuda a crear tableros (dashboards) de monitoreo de diversos sistemas. La tecnología es compatible con una alta variedad de fuentes de datos, entre esas están bases de datos relacionales, de series de tiempo y documentales. Grafana es de código abierto, aunque también existen licencias de pago para acceso a la nube de Grafana.
En el sistema que ha desplegado en los tutoriales pasados estaba haciendo uso de HighCharts para graficar los datos; sin embargo, en este tutorial usamos Grafana debido a sus ventajas con respecto a Highcharts, las cuales pueden verse en la tabla comparativa que sigue:
Criterio | Highcharts | Grafana |
Tipo de tecnología | Librería | Plataforma web completa |
Modo de integración | Se importa en una aplicación web e implica tocar varios elementos de dicha aplicación. | Se integra con el resto de capas del sistema IoT a través de las fuentes de datos. No es necesario modificar los componentes del sistema que ya se tienen. |
Esfuerzo del desarrollador | El programador tiene que tocar varios elementos. Primero, debe crear una consulta que extraiga los datos de las fuentes y luego crear un nuevo endpoint dentro del API del servicio de visualización para acceder a dichos datos. Finalmente, debe editar el código de la plantilla de Django para definir: 1) cómo alimentar la gráfica con los datos extraídos; 2) cómo ubicar la gráfica en la pantalla; y 3) cómo pintarla en cuanto a color, fuente, tipo, etc. | El programador debe simplemente escoger las visualizaciones que desea, entre un gran abanico de gráficas predeterminadas (plugins), o crear las suyas propias. Una vez escoge el tipo de gráfica, debe definir la consulta de los datos y el look-and-feel de la gráfica utilizando el editor de Grafana. |
Tabla 1. Comparación de características y ventajas de Highcharts vs. Grafana
Para integrar Grafana con las capas que se han desarrollado en los tutoriales hemos agregado una nueva máquina virtual al despliegue del sistema (ver Figura 1). Como puede observar en el diagrama de despliegue, la nueva máquina que ejecuta Grafana está conectada únicamente con la base de datos y es alcanzada desde el navegador del usuario final. A lo largo del tutorial, Grafana se conectará a dos bases de datos diferentes: una llamada "iot_data_demo" y otra "iot_data". La base de datos "Iot_data_demo" contiene un conjunto de datos de base para que se vea más claramente el propósito de cada gráfica del tablero. Por su parte, "iot_data" se utilizará para ver la actualización de las gráficas en tiempo cercano al real cuando se conecten el resto de capas del sistemas IoT.
Figura 1. Diagrama de despliegue de la arquitectura de microservicios, incluyendo el servicio de visualización de Grafana
Para más información sobre tecnología, puede visitar el sitio web de Grafana.
El tutorial empieza por desplegar la infraestructura que se requiere para ejecutar el tablero Grafana del ejemplo REMA y verlo en acción. Esto se hará con ayuda de un script de IaC (Infrastructure as Code) en CloudFormation. Posteriormente, usted deberá integrar Grafana con una fuente de datos de prueba a través de algunas configuraciones. En este punto es importante que siga teniendo desplegada la infraestructura realizada en el anterior tutorial ("Capa de aplicación: lógica"). Luego, usted explorará el tablero, con su respectivo código y configuraciones. Seguidamente, se conectará Grafana a las capas que se vienen trabajando en tutoriales anteriores para ver la actualización de las gráficas en tiempo cercano al real. Para finalizar, se crea una nueva gráfica en el tablero y se cierra con algunas reflexiones.
Figura 2. Gráficas del tablero REMA
La Figura 2 muestra el tablero Grafana del ejemplo REMA. Recordemos que los usuarios finales y tomadores de decisión son los miembros de una comunidad académica. Los datos que se explotan son los de temperatura y humedad colectados en una cierta ubicación geográfica. Las decisiones que estos miembros pueden tomar van desde decisiones sencillas del día a día (como ventilar su vivienda para mejorar la calidad del aire) hasta decisiones de responsabilidad social (como interponer acciones de la mano de colectivos medioambientales de la ciudad si la temperatura/humedad está por fuera de los rangos de referencia). Para soportar estas decisiones hemos diseñado un tablero con tres partes principales:
Para ver el tablero REMA en acción siga las instrucciones a continuación.
En esta sección se despliega la máquina virtual de AWS que corre Grafana, por medio de un script de CloudFormation. En el script se especifica la creación de la VPC (Red Privada Virtual), los permisos de seguridad y la creación de la máquina EC2. Adicionalmente, para la máquina se especifican los comandos que instalan el ambiente de ejecución requerido para que se ejecute Grafana correctamente. Para desplegar la máquina virtual siga los pasos a continuación:
Figura 3. Interfaz de inicio del laboratorio
~$ wget -O template https://raw.githubusercontent.com/SELF-Software-Evolution-Lab/Realtime-Monitoring-webApp/main/tutoriales/Capa%20de%20Aplicaci%C3%B3n%20Visualizaci%C3%B3n/IOT-Grafana.template.json
~$ aws cloudformation create-stack --stack-name iot-grafana --template-body file://template --capabilities "CAPABILITY_IAM"
En la terminal se debe mostrar el ID del stack creado.
Figura 4. Inicio de la consola de AWS
En la sección "CloudFormation" podrá ver el estado del stack, a saber: creación en proceso, fallo o creación completada. Para continuar asegúrese de que al menos existen los stacks iot-system
e iot-grafana
.
Figura 5. Stacks creados en CloudFormation
Espere a que el estado del stack iot-grafana
sea "CREATE_COMPLETE".
IOT-Grafana/Grafana
. Si eliminó las máquinas, debe realizar de nuevo el tutorial de capa de aplicación lógica.Figura 6. Listado de máquinas aprovisionadas para el tutorial
Para esta sección es necesario que usted aún tenga desplegada la infraestructura del tutorial "Capa de aplicación - lógica"; es decir, las cinco máquinas que componen las capas de sesión, datos y aplicación. Si aún tiene la infraestructura, teniendo en cuenta que la sesión de AWS Academy se cierra, las máquinas virtuales pierden las direcciones IPs que tenían vinculadas y los servicios se detienen. Al momento de iniciar de nuevo el laboratorio se asignan nuevas direcciones. En el tutorial "Capa de aplicación - lógica" se le pedía cambiar las IPs en la configuración de los distintos servicios y debe efectuar dichos pasos para reconfigurar el sistema que ya había desplegado. Siga estos pasos para reconfigurar el sistema:
IoT Viewer App
). Las direcciones IP las puede encontrar en la sección "EC2" (https://us-east-1.console.aws.amazon.com/ec2/v2/home).settings.py
de la carpeta IOTMonitoringServer
, y haga clic en el botón "Edit this file".Figura 7. Edición de un archivo en GitHub
ALLOWED_HOSTS
: cambie "ip.maquina.visualizador" o la dirección IP presente en esa línea por la nueva dirección del servicio de visualización (IoT Viewer App
).HOST
: cambie "ip.maquina.db" o la dirección IP presente en esa línea por la nueva dirección de la base de datos (Timescale DB
).MQTT_HOST
: cambie "ip.maquina.mqtt" o la dirección IP presente en esa línea por la nueva dirección del bróker MQTT (MQTT Broker
).Nota: recuerde que las direcciones deben ir entre comillas. Por ejemplo, MQTT_HOST = "ip.maquina.mqtt"
cambia a MQTT_HOST = "127.0.0.1"
.
Figura 8. Botón para guardar los cambios efectuados en un archivo en GitHub
IoT Viewer App
, IoT Receiver App
y IoT Alert App
). Se deben actualizar los cambios de las IPs e iniciar los servicios. Estas son las instrucciones que se deben realizar en la terminal cuando se accede a cada máquina.IOTMonitoringServer
, usando el comando:~$ cd IOTMonitoringServer
~$ git pull
~$ nohup sudo python3 manage.py runserver 0.0.0.0:80 &
~$ nohup python3 manage.py start_control &
~$ nohup python3 manage.py start_mqtt &
En esta sección usted poblará la base de datos "iot_data_demo" con datos de prueba para visualizar el tablero de Grafana en acción. Siga estos pasos:
~$ wget -O demo.sql https://github.com/SELF-Software-Evolution-Lab/Realtime-Monitoring-webApp/raw/main/tutoriales/Capa%20de%20Aplicaci%C3%B3n%20Visualizaci%C3%B3n/demo.sql
~$ psql postgresql://dbadmin:uniandesIOT1234*@localhost:5432/postgres -c "create database iot_data_demo;"
~$ psql postgresql://dbadmin:uniandesIOT1234*@localhost:5432/iot_data_demo < demo.sql
Luego de haber desplegado Grafana y reconfigurado el sistema IoT se necesita parametrizar la nueva tecnología. Para esto, Grafana se conectará a la fuente de datos que se quiere consultar, en este caso "iot_data_demo". Y luego se cargará el código que genera las gráficas. Para conectar una nueva fuente de datos siga estas instrucciones:
Figura 9. Página de inicio de sesión de Grafana
Inicie sesión en la página con las credenciales:
Usuario: admin
Contraseña: admin
Si es la primera vez que inicia sesión, Grafana le pedirá cambiar la contraseña, pero no es necesario. Si la cambia, asegúrese de recordarla para su uso futuro. Para no cambiarla puede oprimir "Skip".
Figura 10. Página de cambio de contraseña de Grafana
Figura 11. Interfaz de inicio de Grafana
Figura 12. Interfaz de configuración de fuentes de datos de Grafana
Figura 13. Interfaz de selección de tipo de fuente de datos en Grafana
Name
a "Demo". Host
ingrese la dirección IP de la base de datos con ":5432" al final. Ej., 12.34.130.23:5432.Database
ingrese el nombre de la base de datos, "iot_data_demo".User
y Password
ingrese las credenciales de la base de datos; esto es, nombre de usuario ("dbadmin") y contraseña ("uniandesIOT1234*").TLS/SSL Mode
. Esto se hace porque no se han generado los certificados para el servidor que alberga la base de datos.TimescaleDB
dejando encendido el interruptor como se muestra en la Figura 14.Figura 14. Interfaz de configuración de fuente de datos en Grafana
Ahora usted cargará un dashboard previamente configurado por el equipo docente para visualizar algunos datos de la fuente que acaba de parametrizar. Proceda con los siguientes pasos.
Figura 15. Menú de importación de Grafana
Figura 16. Interfaz de selección de archivo importado en Grafana
Figura 17. Interfaz de importación de archivo en Grafana
Figura 18.Gráfica de línea en el tiempo de las variables humedad y temperatura en un periodo
Figura 19. Gráfica de gauge con los últimos valores de humedad y temperatura
Figura 20. Mapa de calor que discrimina datos agregados de humedad y temperatura
Figura 21. Botones de control en el tablero de Grafana
Figura 22. Selección de fuente de datos del tablero de control de Grafana
La creación y configuración de las visualizaciones de Grafana puede exportarse a un script. En este link de Github podrá encontrar el script creado para el ejemplo REMA. Descargue el archivo para que lo examine a fondo.
Al abrirlo en el ambiente de desarrollo de su preferencia puede observar que es un archivo JSON con varios atributos. A continuación se explican algunos: en la línea 23 se encuentra el título ("title"), en la línea 17 está el rango de tiempo ("time") que sirve para filtrar los resultados de las gráficas según un rango de tiempo, y en la línea 11 se ubican los paneles ("panels"). Exploraremos los paneles en detalle a continuación.
1 {
2 "annotations": {...},
3 "description": "",
4 "editable": true,
5 "fiscalYearStartMonth": 0,
6 "graphTooltip": 0,
7 "id": 5,
8 "iteration": 1654104132398,
9 "links": [],
10 "liveNow": false,
11 "panels": [...],
12 "refresh": "1s",
13 "schemaVersion": 36,
14 "style": "dark",
15 "tags": [],
16 "templating": {...},
17 "time": {
18 "from": "now-1h",
19 "to": "now"
20 },
21 "timepicker": {...},
22 "timezone": "",
23 "title": "Tablero REMA",
24 "uid": "dashboard1",
25 "version": 9,
26 "weekStart": ""
27 }
Dentro de los paneles está la descripción de cada uno y en especial las consultas SQL que se usan para extraer información de las fuentes. A continuación, se especifica el código JSON estándar de cada panel y las consultas SQL particulares. Hay un panel por cada una de las gráficas descritas al inicio del tutorial, esto es, gráficas de líneas, gráficas de gauge y mapas de calor.
1 {
2 "datasource": {
3 "type": "postgres",
4 "uid": "${Database}"
5 },
6 "fieldConfig": { ... },
7 "gridPos": { ... },
8 "id": 15,
9 "options": { ... },
10 "targets": [ ... ],
11 "title": "Temperatura y humedad",
12 "transformations": [],
13 "type": "timeseries"
14 }
Note que la especificación de cada panel posee atributos como datasource
, fieldConfig
, gridPos
, id
, options
, targets
, title
, transformation
, type
, que se explican a continuación:
datasource
hace referencia a la fuente de datos de donde la gráfica extraerá la información, esta fuente se establece como se explica en la sección "Configurar Grafana". fieldConfig
permite configurar el estilo de la gráfica (por ej., colores de las líneas) y rango de datos. id
es el campo que indica la referencia única de la gráfica dentro de Grafana. options
permite realizar configuraciones adicionales a la gráfica como el uso de leyendas e información adicional de los datos graficados. targets
contiene todas las consultas requeridas para crear la gráfica, es decir que acá encontrará las consultas SQL que se realizan a la base de datos. title
guarda el nombre del panel que ve el usuario final. transformations
estarían ubicados los post-procesamientos de los datos que Grafana es capaz de realizar, por ejemplo, obtener un nombre de ciudad legible y no un nombre de ciudad como los que están en los tópicos de MQTT (recuerde que esos nombres están en minúscula e incluyen caracteres especiales). type
especifica el tipo de la gráfica, ya sea una serie de tiempo, un histograma, una torta, un mapa geográfico, etc.Este apartado describe las consultas SQL que se diseñaron para extraer los datos que cada gráfica utiliza.
Las gráficas de línea y gauge usan la misma consulta de base. La implementación de dicha consulta se basa en las decisiones de diseño que se tomaron en el tutorial anterior de capa de datos. Recuerde que las muestras de temperatura y humedad se almacenaron en la entidad "Data
" (ver Figura 23) siguiendo el patrón blob. Vale la pena recordar que en este patrón cada fila almacena un conjunto de muestras tomadas en una ventana de tiempo, para esto se cuenta con los siguientes atributos: 1) base_time
, que indica la fecha y tiempo de inicio de la ventana de tiempo; 2) times
, que es una lista ordenada que guarda los desfases de tiempo con respecto a base_time
; y 3) values
, que es una lista ordenada que guarda los valores de una variable (ya sea temperatura o humedad) correspondientes para cada uno de los tiempos almacenados en el arreglo times
.
Figura 23. Entidad "Data" del tutorial de capa de datos
Dado que las muestras están almacenadas de forma agregada, es necesario extraer los datos de los arreglos y convertirlos a una representación compatible con las gráficas a mostrar. Como resultado se obtiene el código SQL que sigue para extraer los valores de una variable en el tiempo:
1 WITH
2 constantes (temperatura, humedad) AS (values(1, 2)),
3 time_p AS (SELECT d.time,
4 t.idx as
index,
5 t.time + cast(extract(epoch from d.base_time) as
integer) as tiempo
6 FROM receiver_data as d, constantes as c
7 LEFT JOIN UNNEST(d.times) WITH ORDINALITY AS t(time, idx) ON TRUE
8 WHERE d.measurement_id = c.humedad),
9 value_p AS (SELECT d.time,
10 v.idx as
index,
11 v.value as valor
12 FROM receiver_data as d, constantes as c
13 LEFT JOIN UNNEST(d.values) WITH ORDINALITY AS v(value, idx) ON TRUE
14 WHERE d.measurement_id = c.humedad)
15 SELECT t.tiempo as
time,
16 v.valor as humedad
17 FROM time_p t LEFT JOIN value_p v on (t.time = v.time AND t.index = v.index);
Aunque el código puede parecer complejo de leer a primera vista, la consulta es sencilla:
times
y se suman al tiempo de base_time
de cada fila para una variable específica.values
de cada fila para una variable específica.El resultado de esta consulta será una matriz de "n" filas y dos columnas, una representa el tiempo y la otra el valor medido correspondiente. Ver la Figura 24 a manera de ilustración:
Figura 24. Resultado de la consulta de los valores de la variable temperatura en el tiempo
Como se comentó previamente, esta consulta sirve para las gráficas de línea y las de gauge. La diferencia es que mientras las gráficas de línea usan todos los datos de la matriz, las gráficas de gauge usan el último valor que aparezca en la matriz. En otras palabras, si la matriz tiene los valores de temperatura 2, 3, 4, 8, 3, 10, 4, la gráfica gauge mostrará el último valor (4). Las siguientes figuras ilustran el tipo de gráficas que se obtienen a partir de la consulta.
Figura 25. Gráficas de línea de humedad y temperatura en el tiempo
Figura 26. Gráficas gauge del último valor de humedad y temperatura medido
La consulta de los mapas de calor cambia considerablemente con respecto a la consulta previamente descrita. La consulta de mapas indaga sobre la latitud, la longitud, el promedio de las mediciones y la cantidad de estaciones de una cierta ubicación. Como todos estos datos se encuentran en diferentes tablas de la base de datos, se requiere ejecutar varias operaciones JOIN
y GROUP BY
. La consulta para temperatura sigue:
1 WITH
2 data
AS (
3 SELECT station_id, AVG(avg_value) AS
value
FROM processor_data
4 WHERE measurement_id = 1
GROUP BY station_id
5 ),
6 estaciones
AS (
7 SELECT station.location_id, COUNT(*) AS quantity, AVG(data.value) AS
value
8 FROM
data
data
9 RIGHT JOIN processor_station station ON (data.station_id = station.id)
10 GROUP BY station.location_id
11 )
12 SELECT sta.location_id,
13 sta.quantity,
14 sta.value,
15 location.lat AS latitude,
16 location.lng AS longitude
17 FROM estaciones sta
18 RIGHT JOIN processor_location location
19 ON (sta.location_id = location.id);
En esta consulta se realizan los siguiente pasos:
station_id
).location_id
); en este paso también se cuentan las estaciones que hay en cada ubicación.La Figura 27 muestra el tipo de mapas que se generen a partir de la consulta anterior parametrizada tanto para humedad como para temperatura. Se puede observar que cada mapa tiene distintos círculos, uno por ciudad desde donde se reportan mediciones. El color específico de cada círculo varía según el promedio de las mediciones de las estaciones de cada ciudad. Por ejemplo, si el promedio de temperaturas reportadas en una cierta ciudad es mayor a 5°C y menor que 32°C se mostrará un círculo de color verde. Estos rangos y colores también se pueden configurar en Grafana.
Figura 27. Ejemplo de resultado de las gráficas de mapa de calor
Grafana es una tecnología de tipo "pull". Esto quiere decir que siempre que se necesite información actualizada, la tecnología se encarga de conseguirla ya sea a través de una consulta SQL o del consumo de un API. Entonces, para lograr que un tablero de Grafana muestre la evolución de los datos en tiempo cercano al real es necesario hacer unas configuraciones adicionales. Para esto, es necesario establecer intervalos de tiempo los más pequeños posibles. Por ej., el tablero que usted importó está configurado para que recargue la información cada segundo, esto compagina bien con los intervalos de medición de los dispositivos IoT. Si quiere cambiar la frecuencia con la que se hace la actualización de los datos, basta con seleccionar un intervalo diferente en la opción "Refresh", ubicada en la parte superior del tablero como se muestra a continuación.
Figura 28. Botones de control en el tablero de Grafana
Para probar que las gráficas se están actualizando en tiempo cercano al real siga los pasos a continuación:
Name,
que debe quedar con un nombre diferente al de la fuente "iot_data_demo".En esta sección se explican los pasos para implementar una visualización en Grafana desde cero. Recordemos que en un tablero IoT se pueden mostrar tanto datos del ambiente (por ej., temperatura, aceleración, etc.) como datos de los elementos del sistema (por ej., consumo de recursos, métricas de calidad). Las gráficas previamente presentadas son sobre datos del ambiente. Mientras que la gráfica que crearemos a continuación es sobre datos de disponibilidad de los dispositivos de capa física. Se trata de una torta (pie chart) en donde se visualizarán los porcentajes de estaciones (dispositivos) activas/inactivas en la última hora. A continuación listamos los pasos para la creación de dicha gráfica.
Figura 29. Menú "Dashboard en Grafana
Figura 30. Dashboards recientes en Grafana
Figura 31. Botón de creación de panel en Grafana
Figura 32. Selección de tipo de panel en Grafana
Figura 33. Interfaz de visualización, configuración y creación de consulta en Grafana
Figura 34. Lista de tipos de gráfica en Grafana
Figura 35. Tipos de gráfica en Grafana
SELECT
count(*) FILTER(WHERE last_activity >= NOW() - '1 hour'::INTERVAL) as activos,
count(*) FILTER(WHERE last_activity < NOW() - '1 hour'::INTERVAL) as inactivos
FROM receiver_station
Esta consulta cuenta las estaciones y las clasifica como activas si el atributo last_activity
de la entidad "Station
", que es una fecha y hora, está dentro del rango de tiempo de la última hora. En contraparte, si el atributo last_activity
de una cierta estación está por fuera del rango entonces se cuenta como inactiva.
Ahora bien, Grafana ofrece dos opciones para crear consultas con fuentes de datos SQL. La primera opción es el constructor de consultas ("Query Builder") y la segunda es un editor de SQL. El Query Builder facilita la creación de consultas por medio de botones y opciones preestablecidas, pero restringe al diseñador de expresar consultas que se salen de dichas opciones. Por su parte, el editor de SQL permite especificar la consulta como el diseñador desee, pero se requiere más conocimiento de SQL para evitar errores. Dado que la consulta que nos atañe necesita algunas operaciones avanzadas usaremos el editor de SQL para especificarla. A continuación listamos los pasos para esto.
Figura 36. Editor de consulta Query Builder en Grafana
Figura 37. Editor de consulta SQL en Grafana
Figura 38. Formato de respuesta de la consulta en Grafana
Figura 39. Configuración de panel en Grafana
Figura 40. Gráfica tipo "pie" que muestra el porcentaje de estaciones activas e inactivas
Las siguientes preguntas lo invitan a reflexionar sobre lo que observó en el desarrollo de los pasos inmediatamente anteriores:
Para responder las preguntas considere lo visto a lo largo del tutorial y los videos conceptuales de la semana. ¡Traiga sus reflexiones a las sesiones sincrónicas!
Después de haber realizado este tutorial, usted adquirió diversos elementos para diseñar un tablero Web Grafana y conectarlo con el resto de capas de un sistema IoT.
Juan Avelino, Kelly Garcés | Autores |
Rocío Héndez, Andrés Bayona | Revisores |