Tableaux de bord¶
Un tableau de bord IoT qui répond en 200 ms et affiche les bonnes métriques transforme un flux de données en outil de pilotage — la performance et la pertinence métier sont inséparables.
Grafana : l'écosystème de visualisation IoT¶
Grafana est devenu le standard de facto pour la visualisation des données IoT et DevOps. Sa force : un système de datasources qui permet d'interroger n'importe quelle source de données sans déplacer les données.
Datasources pertinentes pour l'IoT¶
| Datasource | Usage principal | Protocole |
|---|---|---|
| InfluxDB | Séries temporelles capteurs | Flux / InfluxQL |
| TimescaleDB | Séries temporelles + données relationnelles | PostgreSQL wire |
| Prometheus | Métriques infrastructure (broker, gateway) | PromQL |
| Loki | Logs centralisés (gateway, firmware) | LogQL |
| Elasticsearch | Recherche full-text sur événements | ES Query DSL |
| MQTT | Données temps réel (streaming panel) | MQTT |
| Eclipse Ditto | État des jumeaux numériques | REST/HTTP |
Architecture de déploiement Grafana¶
graph TB
subgraph "Sources de données"
INFLUX[(InfluxDB\nséries capteurs)]
TIMESCALE[(TimescaleDB\ndonnées enrichies)]
PROM[(Prometheus\nmétriques infra)]
LOKI[(Loki\nlogs système)]
end
subgraph "Grafana Stack"
GRAF[Grafana Server]
AGENT[Grafana Agent\ncollecteur unifié]
ALERT_MGR[Alertmanager]
ONCALL[Grafana OnCall]
end
subgraph "Utilisateurs"
OPS[Opérateurs terrain]
MGMT[Direction / Management]
MAINT[Maintenance]
end
INFLUX -->|Query| GRAF
TIMESCALE -->|Query| GRAF
PROM -->|PromQL| GRAF
LOKI -->|LogQL| GRAF
GRAF -->|Alertes| ALERT_MGR
ALERT_MGR --> ONCALL
ONCALL -->|SMS / Call| OPS
ONCALL -->|Email| MGMT
GRAF -->|Dashboard opérationnel| OPS
GRAF -->|Dashboard KPIs| MGMT
GRAF -->|Dashboard maintenance| MAINT
AGENT -->|Scrape metrics| PROM
AGENT -->|Collect logs| LOKI Deux types de tableaux de bord¶
Dashboard opérationnel¶
Destiné aux opérateurs de terrain et aux techniciens de supervision. Exigences :
- Rafraîchissement toutes les 5 à 30 secondes
- Visualisation de l'état actuel (gauges, stat panels)
- Alertes visuelles claires (rouge / orange / vert)
- Navigation rapide entre équipements (variables de dashboard)
- Pas plus de 20 panneaux par écran (lisibilité mur d'écrans)
Dashboard métier / KPIs¶
Destiné aux responsables de production et à la direction. Exigences :
- Horizons temporels plus longs (jour / semaine / mois)
- Agrégations métier (OEE, taux de disponibilité, consommation énergie/pièce)
- Données comparatives (vs objectif, vs période précédente)
- Export PDF planifié (rapport hebdomadaire automatique)
- Rafraîchissement toutes les 5 à 15 minutes
Comparaison des panneaux selon le type¶
| Type de panneau | Opérationnel | Métier |
|---|---|---|
| Gauge circulaire | État instantané température | Taux d'occupation global |
| Time series | Courbe brute 1h capteur | Tendance consommation 30j |
| Stat (valeur unique) | Dernière mesure | Production journalière |
| Bar chart | Alarmes par zone | Temps d'arrêt par ligne |
| Heatmap | Corrélation temp/pression | Répartition OEE mensuel |
| Table | Liste alarmes actives | Rapport d'incidents |
| Node graph | Topologie équipements | Flux entre ateliers |
Requêtes optimisées pour les time-series¶
La performance des dashboards Grafana dépend en grande partie de la qualité des requêtes. Quelques règles fondamentales :
Règle 1 — Utiliser les pré-agrégations¶
Ne jamais interroger les données brutes sur un horizon long.
// ❌ Mauvais : 30 jours de données brutes (200 millions de points)
from(bucket: "iot_raw")
|> range(start: -30d)
|> filter(fn: (r) => r.device_id == "sensor-042")
// ✅ Bon : utiliser le bucket pré-agrégé 1h (17 520 points)
from(bucket: "iot_1hour")
|> range(start: -30d)
|> filter(fn: (r) => r.device_id == "sensor-042")
Règle 2 — Aligner la résolution sur la période d'affichage¶
Grafana passe $__interval comme variable de résolution automatique.
from(bucket: "iot_1min")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r.device_id == "${device_id}")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
Équivalent TimescaleDB avec time_bucket_gapfill :
SELECT
time_bucket_gapfill('${__interval}', time) AS bucket,
device_id,
interpolate(avg(value)) AS avg_value
FROM temperature_1min
WHERE
time >= '${__from:date}' AND time < '${__to:date}'
AND device_id = '${device_id}'
GROUP BY bucket, device_id
ORDER BY bucket;
Règle 3 — Variables de dashboard pour éviter les requêtes en boucle¶
-- Variable $site : liste des sites disponibles
SELECT DISTINCT site FROM device_metadata ORDER BY site;
-- Variable $device_id : filtrée par $site
SELECT device_id FROM device_metadata
WHERE site = '${site}'
ORDER BY device_id;
Les variables permettent de réutiliser un même dashboard pour 500 équipements sans dupliquer les panneaux.
Alerting Grafana¶
Grafana Alerting (depuis v9) centralise la gestion des alertes avec des règles définies directement dans l'interface.
Architecture alerting¶
flowchart LR
subgraph "Évaluation"
DS[(TimescaleDB\nInfluxDB)]
RULE[Règle d'alerte\nEval every 1m\nFor 5m]
end
subgraph "Notification"
AM[Alertmanager\nGrouping / Silencing]
CP[Contact points\nEmail, PagerDuty\nSlack, Teams]
NP[Notification policy\nRacinement par tag]
end
DS -->|Requête| RULE
RULE -->|FIRING| AM
AM --> NP
NP --> CP Exemple de règle d'alerte¶
# Fichier de provisioning Grafana (infrastructure as code)
apiVersion: 1
groups:
- orgId: 1
name: IoT Critical Alerts
folder: IoT Production
interval: 1m
rules:
- uid: temp_high_bearing
title: "Température palier critique"
condition: C
data:
- refId: A
datasourceUid: influxdb_prod
model:
query: |
from(bucket: "iot_1min")
|> range(start: -5m)
|> filter(fn: (r) => r._measurement == "temperature"
and r.sensor_type == "bearing")
|> mean()
- refId: C
datasourceUid: "__expr__"
model:
type: threshold
conditions:
- evaluator:
type: gt
params: [85]
query:
params: [A]
for: 5m
labels:
severity: critical
team: maintenance
annotations:
summary: "Palier surchauffé — {{$labels.device_id}}"
description: "Température : {{$values.A.Text}}°C depuis 5 min"
runbook_url: "https://wiki.example.com/runbooks/bearing-overheat"
Optimisation avancée : materialized views et pré-calcul¶
Pour les dashboards métier avec des calculs complexes (OEE, MTBF, consommation spécifique), pré-calculer les agrégats est indispensable.
OEE (Overall Equipment Effectiveness) en TimescaleDB¶
-- Vue matérialisée : OEE horaire par ligne de production
CREATE MATERIALIZED VIEW oee_hourly
WITH (timescaledb.continuous) AS
SELECT
time_bucket('1 hour', time) AS hour,
production_line,
-- Disponibilité : temps de fonctionnement / temps planifié
SUM(CASE WHEN state = 'RUNNING' THEN 1 ELSE 0 END)::float
/ COUNT(*) AS availability,
-- Performance : cadence réelle / cadence nominale
AVG(actual_rate / nominal_rate) AS performance,
-- Qualité : pièces conformes / pièces produites
SUM(good_parts)::float / NULLIF(SUM(total_parts), 0) AS quality,
-- OEE = Disponibilité × Performance × Qualité
(SUM(CASE WHEN state = 'RUNNING' THEN 1 ELSE 0 END)::float / COUNT(*))
* AVG(actual_rate / nominal_rate)
* (SUM(good_parts)::float / NULLIF(SUM(total_parts), 0)) AS oee
FROM production_metrics
GROUP BY hour, production_line;
Ce qu'il faut retenir¶
- Séparer systématiquement les dashboards opérationnels (temps réel, opérateurs) des dashboards métier (tendances, KPIs, direction).
- Toujours pointer vers les buckets pré-agrégés sur les horizons > 24h : la performance de Grafana dépend du volume de données retourné.
- L'alerting Grafana unifié remplace avantageusement les alertes dispersées dans plusieurs outils.
Chapitre suivant : Intégration SI — connecter le pipeline IoT aux systèmes d'information de l'entreprise (ERP, MES, SCADA, datawarehouse).