From 83d567b55797f44387742e1f1b84455e1b953f80 Mon Sep 17 00:00:00 2001 From: Eric FELIXINE Date: Tue, 5 May 2026 00:39:43 -0400 Subject: [PATCH] Grafana: Fix dashboard provisioning (flatten nested dashboard objects) --- grafana_smart-city-overview.json | 349 ++++++++++++++++++++++++++++++- grafana_twin-overview.json | 84 ++++++++ 2 files changed, 432 insertions(+), 1 deletion(-) create mode 100644 grafana_twin-overview.json diff --git a/grafana_smart-city-overview.json b/grafana_smart-city-overview.json index 04c2eee1..0a379c00 100644 --- a/grafana_smart-city-overview.json +++ b/grafana_smart-city-overview.json @@ -1 +1,348 @@ -{"meta":{"type":"db","canSave":true,"canEdit":true,"canAdmin":true,"canStar":true,"canDelete":true,"slug":"smart-city-overview","url":"/d/e09bfbc3-6e4b-4134-963c-c98f9ffbb0f8/smart-city-overview","expires":"0001-01-01T00:00:00Z","created":"2026-05-04T15:26:52Z","updated":"2026-05-04T15:26:52Z","updatedBy":"admin","createdBy":"admin","version":1,"hasAcl":false,"isFolder":false,"folderId":0,"folderUid":"","folderTitle":"General","folderUrl":"","provisioned":false,"provisionedExternalId":"","annotationsPermissions":{"dashboard":{"canAdd":true,"canEdit":true,"canDelete":true},"organization":{"canAdd":true,"canEdit":true,"canDelete":true}}},"dashboard":{"id":4,"panels":[{"fieldConfig":{"defaults":{"color":{"mode":"thresholds"},"thresholds":{"mode":"absolute","steps":[{"color":"red","value":null},{"color":"yellow","value":10},{"color":"green","value":15}]},"unit":"short"}},"gridPos":{"h":4,"w":4,"x":0,"y":0},"id":1,"targets":[{"query":"from(bucket: \"iot_data\") |\u003e range(start: -1h) |\u003e filter(fn: (r) =\u003e r[\"_measurement\"] == \"sensors\") |\u003e distinct(column: \"device\") |\u003e count()"}],"title":"Active Sensors","type":"stat"},{"fieldConfig":{"defaults":{"color":{"mode":"thresholds"},"unit":"short"}},"gridPos":{"h":4,"w":4,"x":4,"y":0},"id":2,"targets":[{"query":"from(bucket: \"iot_data\") |\u003e range(start: -1h) |\u003e filter(fn: (r) =\u003e r[\"_measurement\"] == \"traffic\") |\u003e mean(column: \"vehicle_count\")"}],"title":"Average Traffic","type":"stat"},{"fieldConfig":{"defaults":{"color":{"mode":"thresholds"},"max":5,"min":1,"thresholds":{"steps":[{"color":"green","value":null},{"color":"yellow","value":2},{"color":"orange","value":3},{"color":"red","value":4}]},"unit":"short"}},"gridPos":{"h":4,"w":4,"x":8,"y":0},"id":3,"targets":[{"query":"from(bucket: \"iot_data\") |\u003e range(start: -1h) |\u003e filter(fn: (r) =\u003e r[\"_measurement\"] == \"airquality\") |\u003e mean(column: \"air_quality_index\")"}],"title":"Air Quality Index","type":"gauge"},{"fieldConfig":{"defaults":{"color":{"mode":"thresholds"},"unit":"short"}},"gridPos":{"h":4,"w":4,"x":12,"y":0},"id":4,"targets":[{"query":"from(bucket: \"iot_data\") |\u003e range(start: -1h) |\u003e filter(fn: (r) =\u003e r[\"_measurement\"] == \"parking\") |\u003e mean(column: \"available_spots\")"}],"title":"Parking Availability","type":"gauge"},{"fieldConfig":{"defaults":{"color":{"mode":"palette-classic"},"unit":"short"}},"gridPos":{"h":6,"w":12,"x":0,"y":4},"id":5,"targets":[{"query":"from(bucket: \"iot_data\") |\u003e range(start: -24h) |\u003e filter(fn: (r) =\u003e r[\"_measurement\"] == \"traffic\") |\u003e aggregateWindow(every: 5m, fn: mean)"}],"title":"Traffic Over Time","type":"timeseries"},{"gridPos":{"h":6,"w":12,"x":12,"y":4},"id":6,"options":{"layers":[{"config":{"location":{"mode":"coords"},"value":"pm25_ugm3"},"type":"markers"}],"view":{"lat":46.1667,"lon":-1.15,"zoom":12}},"targets":[{"query":"from(bucket: \"iot_data\") |\u003e range(start: -1h) |\u003e filter(fn: (r) =\u003e r[\"_measurement\"] == \"airquality\")"}],"title":"Air Quality Map","type":"geomap"},{"gridPos":{"h":3,"w":24,"x":0,"y":10},"id":7,"options":{"content":"## Current Weather\nTemperature: 18°C | Humidity: 65% | Wind: 15 km/h | UV Index: 3","mode":"markdown"},"title":"Weather Conditions","type":"text"}],"tags":["smart-city","digital-twin","overview"],"timezone":"browser","title":"Smart City Overview","uid":"e09bfbc3-6e4b-4134-963c-c98f9ffbb0f8","version":1}} \ No newline at end of file +{ + "timezone": "Americas/Martinique", + "timepicker": { + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d" + ], + "nowDelay": "5s" + }, + "title": "Smart City Digital Twin - Overview", + "tags": [ + "smart-city", + "digital-twin", + "overview" + ], + "schemaVersion": 16, + "version": 1, + "refresh": "5s", + "panels": [ + { + "id": 1, + "title": "Total Vehicles", + "type": "stat", + "gridPos": { + "x": 0, + "y": 0, + "w": 4, + "h": 4 + }, + "targets": [ + { + "query": "from(bucket: \"iot_data\") |> range(start: -24h) |> filter(fn: (r) => r[\"_measurement\"] == \"traffic\") |> group(columns: [\"sensor_id\"]) |> sum()" + } + ], + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "center", + "orientation": "auto" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 150 + }, + { + "color": "red", + "value": 300 + } + ] + } + } + } + }, + { + "id": 2, + "title": "Average Air Quality Index", + "type": "gauge", + "gridPos": { + "x": 4, + "y": 0, + "w": 4, + "h": 4 + }, + "targets": [ + { + "query": "from(bucket: \"iot_data\") |> range(start: -24h) |> filter(fn: (r) => r[\"_measurement\"] == \"airquality\") |> mean(column: \"air_quality_index\")" + } + ], + "options": { + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "fieldConfig": { + "defaults": { + "min": 1, + "max": 5, + "unit": "short", + "color": { + "mode": "thresholds" + }, + "thresholds": { + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 2 + }, + { + "color": "orange", + "value": 3 + }, + { + "color": "red", + "value": 4 + } + ] + } + } + } + }, + { + "id": 3, + "title": "Available Parking Spots", + "type": "stat", + "gridPos": { + "x": 8, + "y": 0, + "w": 4, + "h": 4 + }, + "targets": [ + { + "query": "from(bucket: \"iot_data\") |> range(start: -24h) |> filter(fn: (r) => r[\"_measurement\"] == \"parking\") |> sum(column: \"available_spots\")" + } + ], + "fieldConfig": { + "defaults": { + "unit": "short", + "color": { + "mode": "thresholds" + }, + "thresholds": { + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 50 + }, + { + "color": "green", + "value": 100 + } + ] + } + } + } + }, + { + "id": 4, + "title": "Average Noise Level", + "type": "gauge", + "gridPos": { + "x": 12, + "y": 0, + "w": 4, + "h": 4 + }, + "targets": [ + { + "query": "from(bucket: \"iot_data\") |> range(start: -24h) |> filter(fn: (r) => r[\"_measurement\"] == \"noise\") |> mean(column: \"noise_level_db\")" + } + ], + "options": { + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "fieldConfig": { + "defaults": { + "min": 30, + "max": 100, + "unit": "dB", + "color": { + "mode": "thresholds" + }, + "thresholds": { + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 60 + }, + { + "color": "orange", + "value": 75 + }, + { + "color": "red", + "value": 85 + } + ] + } + } + } + }, + { + "id": 5, + "title": "Traffic Over Time", + "type": "timeseries", + "gridPos": { + "x": 0, + "y": 4, + "w": 12, + "h": 6 + }, + "targets": [ + { + "query": "from(bucket: \"iot_data\") |> range(start: -24h) |> filter(fn: (r) => r[\"_measurement\"] == \"traffic\") |> aggregateWindow(every: 1m, fn: mean)" + } + ], + "options": { + "legend": { + "displayMode": "hidden" + }, + "tooltip": { + "mode": "single" + } + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "color": { + "mode": "palette-classic" + }, + "custom": { + "lineWidth": 2, + "fillOpacity": 10, + "gradientMode": "opacity" + } + } + } + }, + { + "id": 6, + "title": "Air Quality - PM2.5", + "type": "timeseries", + "gridPos": { + "x": 12, + "y": 4, + "w": 12, + "h": 6 + }, + "targets": [ + { + "query": "from(bucket: \"iot_data\") |> range(start: -24h) |> filter(fn: (r) => r[\"_measurement\"] == \"airquality\") |> aggregateWindow(every: 1m, fn: mean)" + } + ], + "options": { + "legend": { + "displayMode": "hidden" + }, + "tooltip": { + "mode": "single" + } + }, + "fieldConfig": { + "defaults": { + "unit": "\u03bcg/m\u00b3", + "color": { + "mode": "palette-classic" + } + } + } + }, + { + "id": 7, + "title": "Parking Availability", + "type": "piechart", + "gridPos": { + "x": 0, + "y": 10, + "w": 8, + "h": 6 + }, + "targets": [ + { + "query": "from(bucket: \"iot_data\") |> range(start: -24h) |> filter(fn: (r) => r[\"_measurement\"] == \"parking\") |> group(columns: [\"sensor_name\"]) |> sum()" + } + ], + "options": { + "pieType": "donut", + "displayLabels": "name", + "legend": { + "displayMode": "table", + "placement": "right", + "values": [ + "value" + ] + } + } + }, + { + "id": 8, + "title": "Weather Conditions", + "type": "timeseries", + "gridPos": { + "x": 8, + "y": 10, + "w": 16, + "h": 6 + }, + "targets": [ + { + "query": "from(bucket: \"iot_data\") |> range(start: -24h) |> filter(fn: (r) => r[\"_measurement\"] == \"weather\") |> aggregateWindow(every: 5m, fn: mean)" + } + ], + "options": { + "legend": { + "displayMode": "hidden" + }, + "tooltip": { + "mode": "single" + } + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "lineWidth": 2, + "fillOpacity": 5 + } + } + } + } + ], + "time": { + "from": "now-24h", + "to": "now" + } +} \ No newline at end of file diff --git a/grafana_twin-overview.json b/grafana_twin-overview.json new file mode 100644 index 00000000..0c30710b --- /dev/null +++ b/grafana_twin-overview.json @@ -0,0 +1,84 @@ +{ + "timezone": "Americas/Martinique", + "timepicker": { + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d" + ] + }, + "title": "TWIN Supply Chain - Overview", + "tags": [ + "twin", + "supply-chain" + ], + "panels": [ + { + "id": 1, + "title": "Active Shipments", + "type": "stat", + "gridPos": { + "x": 0, + "y": 0, + "w": 6, + "h": 4 + }, + "targets": [ + { + "query": "from(bucket: \"iot_data\") |> range(start: -1h) |> filter(fn: (r) => r[\"_measurement\"] == \"shipment\") |> count()" + } + ], + "fieldConfig": { + "defaults": { + "unit": "short" + } + } + }, + { + "id": 2, + "title": "Inventory Level", + "type": "stat", + "gridPos": { + "x": 6, + "y": 0, + "w": 6, + "h": 4 + }, + "targets": [ + { + "query": "from(bucket: \"iot_data\") |> range(start: -1h) |> filter(fn: (r) => r[\"_measurement\"] == \"inventory\") |> mean()" + } + ], + "fieldConfig": { + "defaults": { + "unit": "short" + } + } + }, + { + "id": 3, + "title": "Pending Orders", + "type": "stat", + "gridPos": { + "x": 12, + "y": 0, + "w": 6, + "h": 4 + }, + "targets": [ + { + "query": "from(bucket: \"iot_data\") |> range(start: -1h) |> filter(fn: (r) => r[\"_measurement\"] == \"order\") |> count()" + } + ], + "fieldConfig": { + "defaults": { + "unit": "short" + } + } + } + ] +} \ No newline at end of file