Grafana para Dashboards y Visualización IoT
Grafana es la herramienta de visualización de referencia para entornos IoT, permitiendo crear dashboards en tiempo real con datos de sensores procedentes de InfluxDB, TimescaleDB, MQTT y otras fuentes. Con Grafana puedes visualizar temperaturas, consumo eléctrico, humedad y cualquier métrica de dispositivos conectados, configurar alertas automáticas cuando se superan umbrales y compartir dashboards públicos con clientes o equipos. Esta guía cubre la instalación, la conexión a fuentes de datos IoT y la creación de dashboards efectivos.
Requisitos Previos
- Ubuntu 20.04/22.04 o CentOS/Rocky 8/9
- Mínimo 2 GB RAM y 2 vCPU
- Una base de datos de series temporales: InfluxDB 2.x o TimescaleDB (PostgreSQL)
- Datos de sensores disponibles (MQTT + Telegraf o ingesta directa)
- Puerto 3000 disponible
Instalación de Grafana
Ubuntu/Debian
# Añadir el repositorio oficial de Grafana
sudo apt-get install -y apt-transport-https software-properties-common wget
wget -q -O - https://apt.grafana.com/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/grafana.gpg
echo "deb [signed-by=/usr/share/keyrings/grafana.gpg] https://apt.grafana.com stable main" | \
sudo tee /etc/apt/sources.list.d/grafana.list
# Instalar Grafana Enterprise (incluye todas las funciones OSS)
sudo apt-get update
sudo apt-get install -y grafana
# Habilitar e iniciar Grafana
sudo systemctl enable grafana-server
sudo systemctl start grafana-server
# Verificar el estado del servicio
sudo systemctl status grafana-server
CentOS/Rocky Linux
# Añadir el repositorio de Grafana para RPM
sudo tee /etc/yum.repos.d/grafana.repo << 'EOF'
[grafana]
name=grafana
baseurl=https://rpm.grafana.com
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://rpm.grafana.com/gpg.key
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
EOF
sudo dnf install -y grafana
sudo systemctl enable --now grafana-server
Con Docker
# Ejecutar Grafana con Docker, montando volumen para persistencia
docker run -d \
--name grafana \
-p 3000:3000 \
-v grafana-data:/var/lib/grafana \
-e GF_SECURITY_ADMIN_PASSWORD=TuPasswordSeguro \
-e GF_USERS_ALLOW_SIGN_UP=false \
grafana/grafana:latest
# Verificar que está corriendo
docker logs grafana --tail=20
Configuración inicial
# Editar la configuración principal de Grafana
sudo tee /etc/grafana/grafana.ini << 'EOF'
[server]
# Dominio público de Grafana
domain = grafana.tudominio.com
root_url = https://grafana.tudominio.com/
[security]
# Cambiar siempre la contraseña por defecto en producción
admin_user = admin
admin_password = TuPasswordMuySeguro
secret_key = clave-secreta-aleatoria-de-al-menos-32-caracteres
[users]
# Deshabilitar el registro de nuevos usuarios
allow_sign_up = false
default_theme = dark
[auth.anonymous]
# Deshabilitar acceso anónimo (habilitarlo solo para dashboards públicos)
enabled = false
[smtp]
# Configurar SMTP para alertas por correo
enabled = true
host = smtp.tudominio.com:587
user = [email protected]
password = TuPasswordSMTP
from_address = [email protected]
from_name = Grafana IoT
EOF
sudo systemctl restart grafana-server
Configuración de Fuentes de Datos IoT
Accede a Grafana en http://tu-servidor:3000 (usuario: admin, contraseña: la configurada).
Conexión con InfluxDB
InfluxDB 2.x es la base de datos de series temporales más usada con Grafana para IoT:
# Primero, verificar que InfluxDB está accesible
curl -I http://localhost:8086/health
# Crear un token de API en InfluxDB para Grafana (si no tienes uno)
# Usando la CLI de InfluxDB
influx auth create \
--org mi-organizacion \
--description "Token para Grafana" \
--read-buckets \
--write-buckets
Configuración desde la interfaz de Grafana:
- Ve a Configuración → Data Sources → Add data source
- Selecciona InfluxDB
- Configura:
- Query Language: Flux
- URL:
http://localhost:8086 - Organization: tu organización en InfluxDB
- Token: el token de API generado
- Default Bucket: el bucket con los datos IoT
Ejemplo de query Flux para visualizar temperaturas:
// Query Flux: obtener lecturas de temperatura de las últimas 24 horas
from(bucket: "sensores-iot")
|> range(start: -24h)
|> filter(fn: (r) => r._measurement == "temperatura")
|> filter(fn: (r) => r._field == "valor")
|> filter(fn: (r) => r.ubicacion == "sala")
|> aggregateWindow(every: 5m, fn: mean, createEmpty: false)
|> yield(name: "media-5min")
Conexión con TimescaleDB
TimescaleDB extiende PostgreSQL con funciones de series temporales, ideal si ya usas PostgreSQL:
# Verificar la conexión a TimescaleDB
psql -h localhost -U grafana_user -d sensores_iot -c "\dt"
Configuración en Grafana:
- Data Sources → Add data source → PostgreSQL
- Configura:
- Host:
localhost:5432 - Database:
sensores_iot - User:
grafana_user(usuario de solo lectura) - Password: tu contraseña
- SSL Mode: require (recomendado)
- TimescaleDB: activar el toggle
- Host:
Ejemplo de query SQL para TimescaleDB:
-- Lecturas de temperatura con agregación por ventana de tiempo
SELECT
time_bucket('5 minutes', timestamp) AS time,
sensor_id,
AVG(valor) AS temperatura_media,
MIN(valor) AS temperatura_min,
MAX(valor) AS temperatura_max
FROM lecturas_sensores
WHERE
$__timeFilter(timestamp)
AND tipo_sensor = 'temperatura'
AND sensor_id = '$sensor'
GROUP BY time, sensor_id
ORDER BY time ASC
Visualización de Datos de Sensores
Panel de temperatura en tiempo real
Configuración recomendada para un panel de temperatura:
{
"type": "timeseries",
"title": "Temperatura en Tiempo Real",
"fieldConfig": {
"defaults": {
"unit": "celsius",
"min": -10,
"max": 50,
"thresholds": {
"mode": "absolute",
"steps": [
{"color": "blue", "value": null},
{"color": "green", "value": 18},
{"color": "yellow", "value": 28},
{"color": "red", "value": 35}
]
},
"custom": {
"lineWidth": 2,
"fillOpacity": 10,
"spanNulls": true
}
}
}
}
Panel de estado de dispositivos (Stat)
Para mostrar el estado actual de múltiples sensores:
// Query Flux: último valor de cada sensor
from(bucket: "sensores-iot")
|> range(start: -5m)
|> filter(fn: (r) => r._measurement == "estado_dispositivo")
|> filter(fn: (r) => r._field == "online")
|> last()
|> group(columns: ["sensor_id"])
Mapa de calor para distribución de valores
// Query para mapa de calor: distribución de temperatura por hora del día
from(bucket: "sensores-iot")
|> range(start: -30d)
|> filter(fn: (r) => r._measurement == "temperatura")
|> filter(fn: (r) => r._field == "valor")
|> aggregateWindow(every: 1h, fn: mean)
|> map(fn: (r) => ({
r with
hora: string(v: date.hour(t: r._time))
}))
Variables y Plantillas de Dashboard
Las variables hacen los dashboards interactivos, permitiendo filtrar por sensor, ubicación o período:
# Las variables se configuran en Dashboard Settings → Variables
# Variable tipo Query para seleccionar sensor dinámicamente
# En InfluxDB Flux:
import "influxdata/influxdb/schema"
schema.tagValues(
bucket: "sensores-iot",
tag: "sensor_id"
)
# Variable de intervalo personalizada
# Name: intervalo
# Type: Interval
# Values: 1m,5m,15m,30m,1h,6h,1d
# Default: 5m
Uso de variables en queries:
// Usar la variable $sensor en una query Flux
from(bucket: "sensores-iot")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r._measurement == "temperatura")
|> filter(fn: (r) => r.sensor_id == "${sensor}")
|> aggregateWindow(every: ${intervalo}, fn: mean, createEmpty: false)
Configuración de Alertas
Grafana Alerting permite notificar cuando los valores de sensores superan umbrales:
# Configurar un canal de notificaciones (webhook, email, Slack, etc.)
# API de Grafana para crear un canal de notificaciones
curl -X POST http://localhost:3000/api/v1/provisioning/contact-points \
-H "Content-Type: application/json" \
-u admin:TuPassword \
-d '{
"name": "Alertas IoT",
"type": "email",
"settings": {
"addresses": "[email protected]",
"singleEmail": false
}
}'
Configuración de una regla de alerta desde la UI:
- Ve al panel de temperatura → Edit → Alert tab
- Configura:
- Condition:
WHEN last() OF query(A, 5m, now) IS ABOVE 35 - Evaluate every:
1mfor5m - No data:
Alerting - Notifications: selecciona el canal configurado
- Condition:
Ejemplo de regla de alerta en formato provisionamiento YAML:
# /etc/grafana/provisioning/alerting/temperatura-alta.yaml
apiVersion: 1
groups:
- orgId: 1
name: "Alertas IoT"
folder: "IoT"
interval: 1m
rules:
- uid: temperatura-sala-alta
title: "Temperatura Sala Alta"
condition: C
data:
- refId: A
relativeTimeRange:
from: 300
to: 0
datasourceUid: influxdb-uid
model:
query: |
from(bucket: "sensores-iot")
|> range(start: -5m)
|> filter(fn: (r) => r._measurement == "temperatura")
|> filter(fn: (r) => r.ubicacion == "sala")
|> mean()
- refId: C
datasourceUid: __expr__
model:
type: threshold
conditions:
- evaluator:
params: [35]
type: gt
query:
params: [A]
noDataState: NoData
execErrState: Error
for: 5m
annotations:
summary: "Temperatura en sala supera 35°C"
description: "Temperatura actual: {{ $values.A.Value }}°C"
labels:
severity: warning
ubicacion: sala
Dashboards Públicos y Compartidos
# Habilitar dashboards públicos en grafana.ini
sudo tee -a /etc/grafana/grafana.ini << 'EOF'
[public_dashboards]
enabled = true
EOF
sudo systemctl restart grafana-server
Para compartir un dashboard:
- Abre el dashboard → icono de compartir → pestaña Public Dashboard
- Activa Enable public access
- Copia la URL pública generada
Para incrustar un panel en una web:
<!-- Código de inserción (embed) de un panel de Grafana -->
<iframe
src="https://grafana.tudominio.com/d-solo/abc123/mi-dashboard?orgId=1&panelId=2&from=now-1h&to=now&refresh=30s"
width="800"
height="400"
frameborder="0">
</iframe>
Solución de Problemas
No se cargan datos en el panel:
# Verificar la conexión con la fuente de datos
# En Grafana: Data Sources → tu fuente → Save & Test
# Comprobar que Grafana puede alcanzar InfluxDB
curl -v http://localhost:8086/health
# Ver los logs de Grafana
sudo journalctl -u grafana-server --no-pager -n 50
Las alertas no se envían:
# Probar el canal de notificaciones manualmente desde Grafana
# Alerting → Contact points → Test
# Verificar la configuración SMTP
sudo grep -A 10 "\[smtp\]" /etc/grafana/grafana.ini
# Ver logs de alertas
sudo journalctl -u grafana-server | grep -i alert
El dashboard es lento con muchos datos:
# Reducir la resolución de los datos con aggregateWindow en Flux
# O usar GROUP BY time($__interval) en SQL
# Configurar el tiempo de caché de queries
sudo tee -a /etc/grafana/grafana.ini << 'EOF'
[caching]
enabled = true
ttl = 30s
EOF
sudo systemctl restart grafana-server
Grafana no arranca tras actualización:
# Ver los errores de inicio
sudo journalctl -u grafana-server --no-pager -n 100
# Verificar la integridad de la base de datos de Grafana
sudo -u grafana grafana-cli admin data-migration
Conclusión
Grafana convierte los datos crudos de sensores IoT en dashboards accionables que permiten a los equipos de operaciones tomar decisiones en tiempo real. La integración nativa con InfluxDB y TimescaleDB, combinada con el sistema de alertas y las variables dinámicas, hace de Grafana la plataforma ideal para monitorizar cualquier infraestructura IoT, desde instalaciones industriales hasta smart buildings. Con los dashboards públicos habilitados, compartir el estado de tu infraestructura con clientes o equipos externos es tan sencillo como copiar una URL.


