fix: Stabilisation complète Smart City Digital Twin Martinique

- Correction simulateur: nettoyage code FIWARE (erreurs syntaxe)
- Grafana: dashboard complet 10 panneaux sur grafana.digitribe.fr
- InfluxDB: datasource corrigée (bucket smartcity, org digitribe)
- Nettoyage: suppression services FIWARE (Orion-LD, Stellio, QuantumLeap)
- Pipeline validé: Simulator → 3 MQTT brokers → Telegraf → InfluxDB → Grafana
- Dashboard URL: https://grafana.digitribe.fr/d/smartcity-martinique-complete/

Architecture simplifiée:
- 3 MQTT brokers (EMQX, Mosquitto, BunkerM)
- Telegraf pour agrégation
- InfluxDB pour stockage time-series
- Grafana pour visualisation (Traefik: grafana.digitribe.fr)
This commit is contained in:
Eric FELIXINE
2026-05-08 01:10:30 -04:00
parent 552dba20d6
commit dfaa240d5a
6 changed files with 905 additions and 322 deletions

View File

@@ -0,0 +1,257 @@
#!/usr/bin/env python3
import json
import requests
# UID de la datasource correcte
DS_UID = "dd1bfc24-de9d-4c23-8a3c-151d153f8169"
dashboard = {
"annotations": {"list": []},
"editable": True,
"fiscalYearStartMonth": 0,
"graphTooltip": 1,
"id": None,
"links": [],
"panels": [
# ===== AIR QUALITY =====
{
"title": "Air Quality - PM2.5 (µg/m³)",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 0},
"datasource": {"type": "influxdb", "uid": DS_UID},
"targets": [
{
"query": 'from(bucket:"smartcity")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "airquality")\n |> filter(fn: (r) => r["_field"] == "pm25_ugm3")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: "PM2.5")',
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "µg/m³",
"thresholds": {
"mode": "absolute",
"steps": [
{"color": "green", "value": None},
{"color": "yellow", "value": 25},
{"color": "orange", "value": 50},
{"color": "red", "value": 100}
]
}
}
}
},
{
"title": "Air Quality - CO (mg/m³)",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 0},
"datasource": {"type": "influxdb", "uid": DS_UID},
"targets": [
{
"query": 'from(bucket:"smartcity")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "airquality")\n |> filter(fn: (r) => r["_field"] == "co_mgm3")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: "CO")',
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "mg/m³",
"thresholds": {
"mode": "absolute",
"steps": [
{"color": "green", "value": None},
{"color": "yellow", "value": 5},
{"color": "red", "value": 15}
]
}
}
}
},
# ===== TRAFFIC =====
{
"title": "Traffic - Average Speed (km/h)",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 16},
"datasource": {"type": "influxdb", "uid": DS_UID},
"targets": [
{
"query": 'from(bucket:"smartcity")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "traffic")\n |> filter(fn: (r) => r["_field"] == "average_speed_kmh")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: "Speed")',
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "km/h",
"thresholds": {
"mode": "absolute",
"steps": [
{"color": "red", "value": None},
{"color": "yellow", "value": 20},
{"color": "green", "value": 40}
]
}
}
}
},
{
"title": "Traffic - Congestion Level",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 16},
"datasource": {"type": "influxdb", "uid": DS_UID},
"targets": [
{
"query": 'from(bucket:"smartcity")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "traffic")\n |> filter(fn: (r) => r["_field"] == "congestion_level")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: "Congestion")',
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "",
"min": 0,
"max": 1,
"thresholds": {
"mode": "absolute",
"steps": [
{"color": "green", "value": None},
{"color": "yellow", "value": 0.5},
{"color": "red", "value": 0.8}
]
}
}
}
},
# ===== PARKING =====
{
"title": "Parking - Available Spots",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 32},
"datasource": {"type": "influxdb", "uid": DS_UID},
"targets": [
{
"query": 'from(bucket:"smartcity")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "parking")\n |> filter(fn: (r) => r["_field"] == "available_spots")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: "Available")',
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "spots"
}
}
},
{
"title": "Parking - Occupancy (%)",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 32},
"datasource": {"type": "influxdb", "uid": DS_UID},
"targets": [
{
"query": 'from(bucket:"smartcity")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "parking")\n |> filter(fn: (r) => r["_field"] == "occupancy_percent")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: "Occupancy")',
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "percent",
"min": 0,
"max": 100
}
}
},
# ===== NOISE =====
{
"title": "Noise Level (dB)",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 48},
"datasource": {"type": "influxdb", "uid": DS_UID},
"targets": [
{
"query": 'from(bucket:"smartcity")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "noise")\n |> filter(fn: (r) => r["_field"] == "noise_level_db")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: "Noise")',
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "dB",
"thresholds": {
"mode": "absolute",
"steps": [
{"color": "green", "value": None},
{"color": "yellow", "value": 65},
{"color": "orange", "value": 80},
{"color": "red", "value": 95}
]
}
}
}
},
# ===== WEATHER =====
{
"title": "Weather - Temperature (°C)",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 48},
"datasource": {"type": "influxdb", "uid": DS_UID},
"targets": [
{
"query": 'from(bucket:"smartcity")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "weather")\n |> filter(fn: (r) => r["_field"] == "temperature_celsius")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: "Temperature")',
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "°C"
}
}
},
# ===== LIGHT =====
{
"title": "Light - Brightness (lux)",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 64},
"datasource": {"type": "influxdb", "uid": DS_UID},
"targets": [
{
"query": 'from(bucket:"smartcity")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "light")\n |> filter(fn: (r) => r["_field"] == "brightness_lux")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: "Brightness")',
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "lux"
}
}
},
{
"title": "Light - Power Consumption (W)",
"type": "timeseries",
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 64},
"datasource": {"type": "influxdb", "uid": DS_UID},
"targets": [
{
"query": 'from(bucket:"smartcity")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r["_measurement"] == "light")\n |> filter(fn: (r) => r["_field"] == "power_consumption_w")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: "Power")',
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "W"
}
}
}
],
"schemaVersion": 38,
"style": "dark",
"tags": ["smart-city", "martinique", "iot", "complete"],
"templating": {"list": []},
"time": {"from": "now-1h", "to": "now"},
"title": "Smart City Digital Twin - Martinique (COMPLET)",
"uid": "smartcity-martinique-complete",
"version": 1
}
# Sauvegarder localement
with open('/home/eric/smart-city-digital-twin-martinique/grafana-dashboard-complete.json', 'w') as f:
json.dump(dashboard, f, indent=2)
print("✅ Dashboard complet généré")
print(f" Fichier: grafana-dashboard-complete.json")
print(f" UID: {dashboard['uid']}")
print(f" Panneaux: {len(dashboard['panels'])}")
print(f" Datasource: {DS_UID}")