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:
257
create_dashboard_complete.py
Normal file
257
create_dashboard_complete.py
Normal 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}")
|
||||
Reference in New Issue
Block a user