539 lines
24 KiB
Python
539 lines
24 KiB
Python
"""
|
|
Create a comprehensive Smart Intersection dashboard in Grafana with proper Flux queries
|
|
"""
|
|
import requests
|
|
import json
|
|
import time
|
|
from datetime import datetime
|
|
|
|
# Configuration
|
|
GRAFANA_URL = "http://localhost:3000"
|
|
GRAFANA_USER = "admin"
|
|
GRAFANA_PASSWORD = "admin" # Default password, change if you've modified it
|
|
INFLUX_BUCKET = "traffic_monitoring"
|
|
INFLUX_ORG = "smart-intersection-org"
|
|
|
|
def get_datasource_id():
|
|
"""Get the InfluxDB datasource ID"""
|
|
try:
|
|
response = requests.get(
|
|
f"{GRAFANA_URL}/api/datasources",
|
|
auth=(GRAFANA_USER, GRAFANA_PASSWORD)
|
|
)
|
|
|
|
if response.status_code != 200:
|
|
print(f"❌ Failed to get datasources: {response.status_code}")
|
|
return None
|
|
|
|
datasources = response.json()
|
|
|
|
for ds in datasources:
|
|
if "influx" in ds["type"].lower():
|
|
print(f"✅ Found InfluxDB datasource: {ds['name']} (ID: {ds['id']})")
|
|
return ds
|
|
|
|
print("❌ No InfluxDB datasource found")
|
|
return None
|
|
except Exception as e:
|
|
print(f"❌ Error getting datasource ID: {e}")
|
|
return None
|
|
|
|
def create_smart_intersection_dashboard(datasource):
|
|
"""Create a comprehensive dashboard for the Smart Intersection application"""
|
|
if not datasource:
|
|
print("❌ No datasource provided, cannot create dashboard")
|
|
return False
|
|
|
|
print(f"Creating Smart Intersection Dashboard with datasource: {datasource['name']}")
|
|
|
|
dashboard = {
|
|
"dashboard": {
|
|
"id": None,
|
|
"uid": "smart-intersection-monitoring",
|
|
"title": "Smart Intersection Monitoring",
|
|
"description": "Real-time monitoring dashboard for smart intersection metrics",
|
|
"tags": ["smart-intersection", "monitoring", "traffic"],
|
|
"timezone": "browser",
|
|
"refresh": "5s",
|
|
"time": {
|
|
"from": "now-15m",
|
|
"to": "now"
|
|
},
|
|
"panels": [
|
|
# Performance Overview Row
|
|
{
|
|
"id": 1,
|
|
"title": "Row - Performance Metrics",
|
|
"type": "row",
|
|
"collapsed": False,
|
|
"gridPos": {"h": 1, "w": 24, "x": 0, "y": 0}
|
|
},
|
|
# FPS Gauge
|
|
{
|
|
"id": 2,
|
|
"title": "FPS",
|
|
"type": "gauge",
|
|
"gridPos": {"h": 8, "w": 8, "x": 0, "y": 1},
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"options": {
|
|
"orientation": "auto",
|
|
"showThresholdLabels": False,
|
|
"showThresholdMarkers": True
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {"mode": "thresholds"},
|
|
"decimals": 1,
|
|
"mappings": [],
|
|
"max": 30,
|
|
"min": 0,
|
|
"thresholds": {
|
|
"mode": "absolute",
|
|
"steps": [
|
|
{"color": "red", "value": None},
|
|
{"color": "orange", "value": 15},
|
|
{"color": "green", "value": 24}
|
|
]
|
|
},
|
|
"unit": "fps"
|
|
},
|
|
"overrides": []
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"query": f'from(bucket: "{INFLUX_BUCKET}")\n |> range(start: -1m)\n |> filter(fn: (r) => r._measurement == "performance")\n |> filter(fn: (r) => r._field == "fps")\n |> last()'
|
|
}
|
|
]
|
|
},
|
|
# Processing Time
|
|
{
|
|
"id": 3,
|
|
"title": "Processing Time",
|
|
"type": "gauge",
|
|
"gridPos": {"h": 8, "w": 8, "x": 8, "y": 1},
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"options": {
|
|
"orientation": "auto",
|
|
"showThresholdLabels": False,
|
|
"showThresholdMarkers": True
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {"mode": "thresholds"},
|
|
"decimals": 1,
|
|
"mappings": [],
|
|
"max": 200,
|
|
"min": 0,
|
|
"thresholds": {
|
|
"mode": "absolute",
|
|
"steps": [
|
|
{"color": "green", "value": None},
|
|
{"color": "orange", "value": 80},
|
|
{"color": "red", "value": 150}
|
|
]
|
|
},
|
|
"unit": "ms"
|
|
},
|
|
"overrides": []
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"query": f'from(bucket: "{INFLUX_BUCKET}")\n |> range(start: -1m)\n |> filter(fn: (r) => r._measurement == "performance")\n |> filter(fn: (r) => r._field == "processing_time_ms")\n |> last()'
|
|
}
|
|
]
|
|
},
|
|
# Device Info
|
|
{
|
|
"id": 4,
|
|
"title": "Device Info",
|
|
"type": "stat",
|
|
"gridPos": {"h": 8, "w": 8, "x": 16, "y": 1},
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"options": {
|
|
"colorMode": "value",
|
|
"graphMode": "none",
|
|
"justifyMode": "auto",
|
|
"orientation": "auto",
|
|
"reduceOptions": {
|
|
"calcs": ["lastNotNull"],
|
|
"fields": "",
|
|
"values": False
|
|
},
|
|
"textMode": "auto"
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {"mode": "thresholds"},
|
|
"mappings": [
|
|
{
|
|
"type": "value",
|
|
"options": {
|
|
"online": {"color": "green", "index": 0, "text": "🟢 Online"},
|
|
"offline": {"color": "red", "index": 1, "text": "🔴 Offline"}
|
|
}
|
|
}
|
|
],
|
|
"thresholds": {
|
|
"mode": "absolute",
|
|
"steps": [
|
|
{"color": "green", "value": None}
|
|
]
|
|
}
|
|
},
|
|
"overrides": []
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"query": f'from(bucket: "{INFLUX_BUCKET}")\n |> range(start: -5m)\n |> filter(fn: (r) => r._measurement == "device_info")\n |> filter(fn: (r) => r._field == "status")\n |> last()\n |> yield(name: "device_status")'
|
|
},
|
|
{
|
|
"refId": "B",
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"query": f'from(bucket: "{INFLUX_BUCKET}")\n |> range(start: -5m)\n |> filter(fn: (r) => r._measurement == "device_info")\n |> filter(fn: (r) => r._field == "location")\n |> last()\n |> yield(name: "location")'
|
|
}
|
|
]
|
|
},
|
|
# Performance History
|
|
{
|
|
"id": 5,
|
|
"title": "Performance History",
|
|
"type": "timeseries",
|
|
"gridPos": {"h": 9, "w": 24, "x": 0, "y": 9},
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"options": {
|
|
"tooltip": {"mode": "multi", "sort": "none"},
|
|
"legend": {"showLegend": True},
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {"mode": "palette-classic"},
|
|
"custom": {
|
|
"lineInterpolation": "smooth",
|
|
"fillOpacity": 10,
|
|
"spanNulls": False,
|
|
},
|
|
"unit": "fps"
|
|
},
|
|
"overrides": [
|
|
{
|
|
"matcher": {"id": "byName", "options": "processing_time_ms"},
|
|
"properties": [
|
|
{"id": "unit", "value": "ms"},
|
|
{"id": "color", "value": {"mode": "fixed", "fixedColor": "orange"}}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"query": f'from(bucket: "{INFLUX_BUCKET}")\n |> range(start: -15m)\n |> filter(fn: (r) => r._measurement == "performance")\n |> filter(fn: (r) => r._field == "fps")\n |> aggregateWindow(every: 2s, fn: mean, createEmpty: false)\n |> yield(name: "fps")'
|
|
},
|
|
{
|
|
"refId": "B",
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"query": f'from(bucket: "{INFLUX_BUCKET}")\n |> range(start: -15m)\n |> filter(fn: (r) => r._measurement == "performance")\n |> filter(fn: (r) => r._field == "processing_time_ms")\n |> aggregateWindow(every: 2s, fn: mean, createEmpty: false)\n |> yield(name: "processing_time_ms")'
|
|
}
|
|
]
|
|
},
|
|
# Detection Row
|
|
{
|
|
"id": 6,
|
|
"title": "Row - Object Detection",
|
|
"type": "row",
|
|
"collapsed": False,
|
|
"gridPos": {"h": 1, "w": 24, "x": 0, "y": 18}
|
|
},
|
|
# Vehicle Count
|
|
{
|
|
"id": 7,
|
|
"title": "Vehicle Count",
|
|
"type": "stat",
|
|
"gridPos": {"h": 8, "w": 8, "x": 0, "y": 19},
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"options": {
|
|
"colorMode": "value",
|
|
"graphMode": "area",
|
|
"justifyMode": "auto",
|
|
"orientation": "auto",
|
|
"reduceOptions": {
|
|
"calcs": ["lastNotNull"],
|
|
"fields": "",
|
|
"values": False
|
|
}
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {"mode": "thresholds"},
|
|
"mappings": [],
|
|
"thresholds": {
|
|
"mode": "absolute",
|
|
"steps": [
|
|
{"color": "blue", "value": None}
|
|
]
|
|
},
|
|
"unit": "none"
|
|
},
|
|
"overrides": []
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"query": f'from(bucket: "{INFLUX_BUCKET}")\n |> range(start: -1m)\n |> filter(fn: (r) => r._measurement == "detection_events")\n |> filter(fn: (r) => r._field == "vehicle_count")\n |> last()'
|
|
}
|
|
]
|
|
},
|
|
# Red Light Violations
|
|
{
|
|
"id": 8,
|
|
"title": "Red Light Violations",
|
|
"type": "stat",
|
|
"gridPos": {"h": 8, "w": 8, "x": 8, "y": 19},
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"options": {
|
|
"colorMode": "value",
|
|
"graphMode": "area",
|
|
"justifyMode": "auto",
|
|
"orientation": "auto",
|
|
"reduceOptions": {
|
|
"calcs": ["lastNotNull"],
|
|
"fields": "",
|
|
"values": False
|
|
}
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {"mode": "thresholds"},
|
|
"mappings": [],
|
|
"thresholds": {
|
|
"mode": "absolute",
|
|
"steps": [
|
|
{"color": "green", "value": None},
|
|
{"color": "red", "value": 1}
|
|
]
|
|
},
|
|
"unit": "none"
|
|
},
|
|
"overrides": []
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"query": f'from(bucket: "{INFLUX_BUCKET}")\n |> range(start: -1h)\n |> filter(fn: (r) => r._measurement == "violation_events")\n |> filter(fn: (r) => r.violation_type == "red_light_violation")\n |> count()\n |> yield(name: "violations")'
|
|
}
|
|
]
|
|
},
|
|
# Traffic Light Status
|
|
{
|
|
"id": 9,
|
|
"title": "Traffic Light Status",
|
|
"type": "stat",
|
|
"gridPos": {"h": 8, "w": 8, "x": 16, "y": 19},
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"options": {
|
|
"colorMode": "value",
|
|
"graphMode": "none",
|
|
"justifyMode": "auto",
|
|
"orientation": "auto",
|
|
"reduceOptions": {
|
|
"calcs": ["lastNotNull"],
|
|
"fields": "",
|
|
"values": False
|
|
},
|
|
"textMode": "auto"
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {"mode": "thresholds"},
|
|
"mappings": [
|
|
{
|
|
"type": "value",
|
|
"options": {
|
|
"RED": {"color": "red", "index": 0, "text": "🔴 RED"},
|
|
"YELLOW": {"color": "yellow", "index": 1, "text": "🟡 YELLOW"},
|
|
"GREEN": {"color": "green", "index": 2, "text": "🟢 GREEN"},
|
|
"UNKNOWN": {"color": "gray", "index": 3, "text": "❓ UNKNOWN"}
|
|
}
|
|
}
|
|
],
|
|
"thresholds": {
|
|
"mode": "absolute",
|
|
"steps": [
|
|
{"color": "red", "value": None}
|
|
]
|
|
}
|
|
},
|
|
"overrides": []
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"query": f'from(bucket: "{INFLUX_BUCKET}")\n |> range(start: -5m)\n |> filter(fn: (r) => r._measurement == "traffic_light_status")\n |> filter(fn: (r) => r._field == "color_numeric")\n |> last()\n |> map(fn: (r) => ({{ r with _value: if r._value == 1.0 then "RED" else if r._value == 2.0 then "YELLOW" else if r._value == 3.0 then "GREEN" else "UNKNOWN" }}))'
|
|
}
|
|
]
|
|
},
|
|
# Detection History
|
|
{
|
|
"id": 10,
|
|
"title": "Detection History",
|
|
"type": "timeseries",
|
|
"gridPos": {"h": 9, "w": 24, "x": 0, "y": 27},
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"options": {
|
|
"tooltip": {"mode": "multi", "sort": "none"},
|
|
"legend": {"showLegend": True}
|
|
},
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
"color": {"mode": "palette-classic"},
|
|
"custom": {
|
|
"lineInterpolation": "linear",
|
|
"fillOpacity": 10,
|
|
"spanNulls": False,
|
|
},
|
|
"unit": "none"
|
|
},
|
|
"overrides": []
|
|
},
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"query": f'from(bucket: "{INFLUX_BUCKET}")\n |> range(start: -15m)\n |> filter(fn: (r) => r._measurement == "detection_events")\n |> filter(fn: (r) => r._field == "vehicle_count")\n |> aggregateWindow(every: 5s, fn: mean, createEmpty: false)'
|
|
},
|
|
{
|
|
"refId": "B",
|
|
"datasource": {
|
|
"type": datasource["type"],
|
|
"uid": datasource["uid"]
|
|
},
|
|
"query": f'from(bucket: "{INFLUX_BUCKET}")\n |> range(start: -15m)\n |> filter(fn: (r) => r._measurement == "violation_events")\n |> filter(fn: (r) => r._field == "count")\n |> aggregateWindow(every: 5s, fn: sum, createEmpty: false)'
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"overwrite": True,
|
|
"message": "Created Smart Intersection Monitoring Dashboard"
|
|
}
|
|
|
|
try:
|
|
response = requests.post(
|
|
f"{GRAFANA_URL}/api/dashboards/db",
|
|
auth=(GRAFANA_USER, GRAFANA_PASSWORD),
|
|
headers={"Content-Type": "application/json"},
|
|
data=json.dumps(dashboard)
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
result = response.json()
|
|
dashboard_url = f"{GRAFANA_URL}/d/{result['uid']}"
|
|
print(f"✅ Dashboard created successfully: {dashboard_url}")
|
|
print(f"👉 Please open this URL in your browser: {dashboard_url}")
|
|
return True
|
|
else:
|
|
print(f"❌ Failed to create dashboard: {response.status_code}")
|
|
print(f"Response: {response.text}")
|
|
return False
|
|
except Exception as e:
|
|
print(f"❌ Error creating dashboard: {e}")
|
|
return False
|
|
|
|
def main():
|
|
print("===== CREATING SMART INTERSECTION DASHBOARD =====")
|
|
print("This will create a comprehensive dashboard for your Smart Intersection application")
|
|
|
|
# Get the InfluxDB datasource
|
|
datasource = get_datasource_id()
|
|
if not datasource:
|
|
print("❌ Failed to get InfluxDB datasource, cannot proceed")
|
|
return
|
|
|
|
# Create the dashboard
|
|
success = create_smart_intersection_dashboard(datasource)
|
|
|
|
if success:
|
|
print("\n✅ Smart Intersection Dashboard created successfully!")
|
|
print("The dashboard includes:")
|
|
print(" - Real-time FPS and processing time gauges")
|
|
print(" - Device information panel")
|
|
print(" - Performance history graph")
|
|
print(" - Vehicle count statistics")
|
|
print(" - Red light violation tracking")
|
|
print(" - Traffic light status indicator")
|
|
print(" - Detection history graph")
|
|
print("\nEnsure your application is writing the following measurements to InfluxDB:")
|
|
print(" - 'performance' with fields 'fps' and 'processing_time_ms'")
|
|
print(" - 'detection_events' with field 'vehicle_count'")
|
|
print(" - 'violation_events' with field 'count' and tag 'violation_type'")
|
|
print(" - 'traffic_light' with field 'status'")
|
|
else:
|
|
print("\n❌ Failed to create Smart Intersection Dashboard")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|