Introduction
En 2026, Grafana reste l'outil incontournable pour visualiser les données IoT en temps réel, grâce à sa flexibilité et ses plugins avancés. Ce tutoriel avancé vous guide pour déployer une stack complète : broker MQTT (Mosquitto), collecteur Telegraf vers InfluxDB, et Grafana avec provisioning automatique. Imaginez monitorer des capteurs industriels – température, humidité, vibrations – avec des dashboards interactifs, alertes unifiées et scaling horizontal.
Pourquoi c'est crucial ? Les flottes IoT génèrent des téraoctets de données ; une mauvaise visualisation mène à des downtimes coûteux. Nous couvrons du déploiement Docker à l'optimisation des queries Flux, en passant par des simulations de données réelles. À la fin, vous aurez une architecture production-ready, scalable pour 1000+ devices. Prêt à transformer vos métriques IoT en insights actionnables ? (128 mots)
Prérequis
- Docker et Docker Compose 20+ installés
- Connaissances avancées en YAML, TOML et Flux (langage query InfluxDB 2.x)
- Python 3.10+ pour scripts simulateurs
- Port 3000 (Grafana), 8086 (InfluxDB), 1883 (MQTT) libres
- 4 Go RAM minimum pour la stack locale
Déployer la stack Docker Compose
version: '3.8'
services:
mosquitto:
image: eclipse-mosquitto:2.0
ports:
- '1883:1883'
volumes:
- ./mosquitto.conf:/mosquitto/config/mosquitto.conf
influxdb:
image: influxdb:2.7
ports:
- '8086:8086'
environment:
DOCKER_INFLUXDB_INIT_MODE: setup
DOCKER_INFLUXDB_INIT_USERNAME: admin
DOCKER_INFLUXDB_INIT_PASSWORD: adminpass
DOCKER_INFLUXDB_INIT_ORG: iot-org
DOCKER_INFLUXDB_INIT_BUCKET: iot-bucket
DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: token123
volumes:
- influxdb_data:/var/lib/influxdb2
telegraf:
image: telegraf:1.28
depends_on:
- influxdb
- mosquitto
volumes:
- ./telegraf.conf:/etc/telegraf/telegraf.conf:ro
environment:
INFLUX_TOKEN: token123
grafana:
image: grafana/grafana:10.4.0
ports:
- '3000:3000'
depends_on:
- influxdb
volumes:
- grafana_data:/var/lib/grafana
- ./provisioning:/etc/grafana/provisioning
volumes:
influxdb_data:
grafana_data:Ce docker-compose.yml orchestre les 4 services essentiels : Mosquitto pour MQTT, InfluxDB 2.x pour stockage, Telegraf pour ingestion, Grafana pour viz. Les volumes persistent les données ; l'ordre des depends_on assure un démarrage séquentiel. Piège : sans :ro sur configs, les conteneurs écrasent vos fichiers locaux.
Configurer le broker MQTT
Mosquitto agit comme hub central pour vos topics IoT (ex: sensors/temp/room1). Créez le fichier de config pour activer persistence et auth basique – scalable pour 10k+ connexions.
Configuration Mosquitto
persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
listener 1883
allow_anonymous true
max_queued_messages 10000
message_size_limit 0
max_inflight_messages 100
max_queued_bytes 0Active la persistence pour retenir les messages QoS1/2 après redémarrage. Limites élevées pour bursts IoT ; allow_anonymous pour dev, passez à ACL+users en prod. Piège : sans max_queued, un publisher floode la RAM.
Ingestion via Telegraf
Telegraf lit MQTT et écrit en InfluxDB via Flux. Configurez inputs/outputs pour batching optimisé – réduit la latence de 50% sur high-throughput.
Configuration Telegraf
[[outputs.influxdb_v2]]
urls = ["http://influxdb:8086"]
token = "token123"
organization = "iot-org"
bucket = "iot-bucket"
[[inputs.mqtt_consumer]]
servers = ["tcp://mosquitto:1883"]
topics = [
"sensors/+/temp",
"sensors/+/humidity"
]
data_format = "value"
data_type = "float"
[[inputs.mqtt_consumer.tags]]
device_id = "${topic:sensors/}"
[[processors.enum]]
[[processors.enum.mapping]]
field = "topic"
[processors.enum.mapping.value_mappings]
"sensors/room1/temp" = "temperature"
"sensors/room1/humidity" = "humidity"Inputs MQTT avec wildcards capture tous sensors/* ; outputs vers bucket dédié. Processors ajoutent tags/metadata pour queries Grafana. Piège : sans data_type=float, Influx infère mal, cassant les graphs.
Provisioning Grafana
Automatisez datasources et dashboards via YAML/JSON – zéro config manuelle, idéal CI/CD. Créez dossiers provisioning/.
Datasource InfluxDB provisioning
apiVersion: 1
providers:
- name: 'iot-influxdb'
orgId: 1
type: influxdb
url: http://influxdb:8086
access: proxy
jsonData:
version: Flux
organization: 'iot-org'
defaultBucket: 'iot-bucket'
tlsSkipVerify: true
secureJsonData:
token: 'token123'YAML provisionne datasource Flux-ready. Proxy mode pour queries serveur-side. Piège : tlsSkipVerify=true en dev seulement ; en prod, certs + secureJsonData via secrets.
Dashboard IoT JSON
{
"__inputs": [],
"dashboard": {
"id": null,
"title": "IoT Sensors Dashboard",
"tags": ["iot"],
"panels": [
{
"id": 1,
"title": "Températures par Device",
"type": "timeseries",
"targets": [{
"query": "from(bucket: "iot-bucket")
|> range(start: v.timeRangeStart)
|> filter(fn: (r) => r._measurement == "temp")
|> aggregateWindow(every: v.windowPeriod, fn: mean)",
"refId": "A",
"datasource": "-- Grafana --",
"model": {"dataSource":{"type":"-- Grafana --","uid":"${datasource}"}},
"format": "time_series"
}],
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 0},
"options": {"legend":{"displayMode":"table","placement":"bottom"},"tooltip":{"mode":"multi"}}
},
{
"id": 2,
"title": "Humidité Moyenne",
"type": "stat",
"targets": [{
"query": "from(bucket: "iot-bucket")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r._measurement == "humidity")
|> mean()",
"refId": "A",
"datasource": "-- Grafana --"
}],
"fieldConfig": {"defaults":{"color":{"mode":"thresholds"},"thresholds":{"steps":[{"color":"green","value":null},{"color":"yellow","value":60},{"color":"red","value":80}]},
"unit": "percent (0-100)"}},
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 0}
}
],
"time": {"from":"now-6h","to":"now"},
"timezone":"browser",
"refresh":"5s",
"schemaVersion": 39,
"version": 1
},
"overwrite": true
}Dashboard JSON provisionné avec panels timeseries/stat pour temp/humidity. Queries Flux agrégées ; refresh 5s pour near-RT. Piège : ${datasource} UID doit matcher provisioning ; testez avec API Grafana.
Simuler des données IoT
Lancez un publisher Python pour injecter données réalistes – simule 10 sensors avec noise gaussienne.
Script publisher MQTT
import paho.mqtt.client as mqtt
import time
import random
import json
from threading import Thread
client = mqtt.Client()
client.connect("localhost", 1883, 60)
sensors = ["room1", "room2", "factory1"]
def publish_sensor(sensor):
while True:
temp = 22 + random.gauss(0, 2)
hum = 50 + random.gauss(0, 10)
payload = json.dumps({"temp": temp, "humidity": hum, "timestamp": time.time()})
client.publish(f"sensors/{sensor}/temp", temp)
client.publish(f"sensors/{sensor}/humidity", hum)
time.sleep(5)
threads = []
for s in sensors:
t = Thread(target=publish_sensor, args=(s,))
t.start()
threads.append(t)
for t in threads:
t.join()
client.loop_forever()Paho MQTT publie float values sur topics wildcards-ready. Threads par sensor pour parallélisme ; gauss pour réalisme. Piège : sans connect() retry, reconnexion échoue ; ajoutez client.reconnect_delay_set() en prod.
Démarrer et tester
Démarrez : docker compose up -d && python iot_publisher.py. Accédez Grafana:3000 (admin/admin). Dashboard auto-chargé. Queries Flux live sur 5s refresh.
Script de démarrage
#!/bin/bash
docker compose up -d
python3 iot_publisher.py &
grafana-cli plugins install grafana-clock-panel
grafana-cli plugins install vertamedia-clickhouse-datasource
echo "Stack démarrée. Grafana: http://localhost:3000"Bash one-liner pour stack + publisher background. Plugins optionnels pour extensions. Piège : sans & , publisher bloque ; utilisez nohup pour detach.
Bonnes pratiques
- Provisioning everywhere : YAML/JSON pour GitOps, évitez UI manuelle.
- Queries Flux optimisées : Utilisez aggregateWindow(every: 10s) pour downsampling, <1% CPU.
- Sécurité : MQTT ACL, Influx RBAC, Grafana OAuth ; secrets via Docker Swarm.
- Scaling : Influx IOx cluster, Telegraf agents distribués, Grafana HA.
- Alerting : Règles unifiées sur anomalies (ex: temp>30°C), notify Slack/Teams.
Erreurs courantes à éviter
- Wildcard MQTT mal parsé : "+/+" au lieu de "sensors/+/temp" perd tags ; testez avec mosquitto_sub.
- Influx token expired : Regénèrez via UI, pas hardcoded.
- Dashboard non provisionné : Vérifiez logs Grafana (
docker logs grafana) pour path errors. - High cardinality : Trop de tags unique (device_id par ms) explose stockage ; bucketing + downsample.
Pour aller plus loin
- Docs officielles : Grafana IoT docs
- Plugins avancés : Grafana MQTT plugin
- Scaling prod : Kubernetes avec Helm charts Grafana.