Skip to content

Commit debfc0c

Browse files
committed
feat(grafana): add Trip Cost and Cost/100km panels to Drive Details
Add two new stat panels to the Drive Details internal dashboard that estimate the cost of a trip based on recent charging price data: - Trip Cost (est.): total estimated cost for the drive - Ø Cost / 100 <unit>: estimated cost per 100 km or 100 mi Cost/kWh is determined by a 3-tier lookup: 1. Average cost/kWh across all charging sessions that ended within the 24 hours before the drive started (the most relevant window) 2. Fallback: cost/kWh of the single most recent charge before the drive, if no sessions exist in the 24h window 3. N/A if no prior charge has cost data at all Both panels are placed at y=28 alongside the existing Distance driven and Elevation Summary panels (all resized to w=3 to fit on one row).
1 parent e9ddcab commit debfc0c

1 file changed

Lines changed: 187 additions & 3 deletions

File tree

grafana/dashboards/internal/drive-details.json

Lines changed: 187 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1816,7 +1816,7 @@
18161816
},
18171817
"gridPos": {
18181818
"h": 3,
1819-
"w": 6,
1819+
"w": 3,
18201820
"x": 0,
18211821
"y": 28
18221822
},
@@ -1898,8 +1898,8 @@
18981898
},
18991899
"gridPos": {
19001900
"h": 3,
1901-
"w": 6,
1902-
"x": 6,
1901+
"w": 3,
1902+
"x": 3,
19031903
"y": 28
19041904
},
19051905
"id": 20,
@@ -2389,6 +2389,190 @@
23892389
],
23902390
"title": "Ø Speed",
23912391
"type": "stat"
2392+
},
2393+
{
2394+
"datasource": {
2395+
"type": "grafana-postgresql-datasource",
2396+
"uid": "TeslaMate"
2397+
},
2398+
"description": "Estimated trip cost. Cost/kWh uses the average of charges that ended within 24 h before this drive; if none have cost data, falls back to the single most recent charge before the trip.",
2399+
"fieldConfig": {
2400+
"defaults": {
2401+
"decimals": 2,
2402+
"mappings": [
2403+
{
2404+
"options": {
2405+
"match": "null",
2406+
"result": {
2407+
"text": "N/A"
2408+
}
2409+
},
2410+
"type": "special"
2411+
}
2412+
],
2413+
"thresholds": {
2414+
"mode": "absolute",
2415+
"steps": [
2416+
{
2417+
"color": "super-light-blue",
2418+
"value": 0
2419+
}
2420+
]
2421+
},
2422+
"unit": "none"
2423+
},
2424+
"overrides": []
2425+
},
2426+
"gridPos": {
2427+
"h": 3,
2428+
"w": 3,
2429+
"x": 6,
2430+
"y": 28
2431+
},
2432+
"id": 41,
2433+
"maxDataPoints": 100,
2434+
"options": {
2435+
"colorMode": "value",
2436+
"graphMode": "none",
2437+
"justifyMode": "center",
2438+
"orientation": "auto",
2439+
"percentChangeColorMode": "standard",
2440+
"reduceOptions": {
2441+
"calcs": [
2442+
"lastNotNull"
2443+
],
2444+
"fields": "/.*/",
2445+
"values": false
2446+
},
2447+
"showPercentChange": false,
2448+
"textMode": "auto",
2449+
"wideLayout": true
2450+
},
2451+
"pluginVersion": "12.4.0",
2452+
"targets": [
2453+
{
2454+
"datasource": {
2455+
"type": "grafana-postgresql-datasource",
2456+
"uid": "TeslaMate"
2457+
},
2458+
"editorMode": "code",
2459+
"format": "table",
2460+
"rawQuery": true,
2461+
"rawSql": "WITH drive AS (\n SELECT\n d.start_date,\n (start_${preferred_range}_range_km - end_${preferred_range}_range_km) * car.efficiency AS energy_kwh\n FROM drives d\n JOIN cars car ON car.id = d.car_id\n WHERE d.id = $drive_id\n),\nrecent_cost AS (\n SELECT sum(cp.cost) / NULLIF(sum(cp.charge_energy_added), 0) AS cost_per_kwh\n FROM charging_processes cp\n CROSS JOIN drive\n WHERE cp.car_id = $car_id\n AND cp.cost IS NOT NULL AND cp.charge_energy_added > 0\n AND cp.end_date <= drive.start_date\n AND cp.end_date >= drive.start_date - INTERVAL '24 hours'\n),\nlast_charge_cost AS (\n SELECT cp.cost / NULLIF(cp.charge_energy_added, 0) AS cost_per_kwh\n FROM charging_processes cp\n CROSS JOIN drive\n WHERE cp.car_id = $car_id\n AND cp.cost IS NOT NULL AND cp.charge_energy_added > 0\n AND cp.end_date <= drive.start_date\n ORDER BY cp.end_date DESC\n LIMIT 1\n),\neffective_cost AS (\n SELECT COALESCE(recent_cost.cost_per_kwh, last_charge_cost.cost_per_kwh) AS cost_per_kwh\n FROM last_charge_cost LEFT JOIN recent_cost ON true\n)\nSELECT ROUND((drive.energy_kwh * effective_cost.cost_per_kwh)::numeric, 2) AS \"Trip Cost\"\nFROM drive CROSS JOIN effective_cost",
2462+
"refId": "A",
2463+
"sql": {
2464+
"columns": [
2465+
{
2466+
"parameters": [],
2467+
"type": "function"
2468+
}
2469+
],
2470+
"groupBy": [
2471+
{
2472+
"property": {
2473+
"type": "string"
2474+
},
2475+
"type": "groupBy"
2476+
}
2477+
],
2478+
"limit": 50
2479+
}
2480+
}
2481+
],
2482+
"title": "Trip Cost (est.)",
2483+
"type": "stat"
2484+
},
2485+
{
2486+
"datasource": {
2487+
"type": "grafana-postgresql-datasource",
2488+
"uid": "TeslaMate"
2489+
},
2490+
"description": "Estimated cost per 100 km/mi. Cost/kWh uses the average of charges that ended within 24 h before this drive; if none have cost data, falls back to the single most recent charge before the trip.",
2491+
"fieldConfig": {
2492+
"defaults": {
2493+
"decimals": 2,
2494+
"mappings": [
2495+
{
2496+
"options": {
2497+
"match": "null",
2498+
"result": {
2499+
"text": "N/A"
2500+
}
2501+
},
2502+
"type": "special"
2503+
}
2504+
],
2505+
"thresholds": {
2506+
"mode": "absolute",
2507+
"steps": [
2508+
{
2509+
"color": "super-light-blue",
2510+
"value": 0
2511+
}
2512+
]
2513+
},
2514+
"unit": "none"
2515+
},
2516+
"overrides": []
2517+
},
2518+
"gridPos": {
2519+
"h": 3,
2520+
"w": 3,
2521+
"x": 9,
2522+
"y": 28
2523+
},
2524+
"id": 42,
2525+
"maxDataPoints": 100,
2526+
"options": {
2527+
"colorMode": "value",
2528+
"graphMode": "none",
2529+
"justifyMode": "center",
2530+
"orientation": "auto",
2531+
"percentChangeColorMode": "standard",
2532+
"reduceOptions": {
2533+
"calcs": [
2534+
"lastNotNull"
2535+
],
2536+
"fields": "/.*/",
2537+
"values": false
2538+
},
2539+
"showPercentChange": false,
2540+
"textMode": "auto",
2541+
"wideLayout": true
2542+
},
2543+
"pluginVersion": "12.4.0",
2544+
"targets": [
2545+
{
2546+
"datasource": {
2547+
"type": "grafana-postgresql-datasource",
2548+
"uid": "TeslaMate"
2549+
},
2550+
"editorMode": "code",
2551+
"format": "table",
2552+
"rawQuery": true,
2553+
"rawSql": "WITH drive AS (\n SELECT\n d.start_date,\n (start_${preferred_range}_range_km - end_${preferred_range}_range_km) * car.efficiency AS energy_kwh,\n convert_km(d.distance::numeric, '$length_unit') AS dist\n FROM drives d\n JOIN cars car ON car.id = d.car_id\n WHERE d.id = $drive_id\n),\nrecent_cost AS (\n SELECT sum(cp.cost) / NULLIF(sum(cp.charge_energy_added), 0) AS cost_per_kwh\n FROM charging_processes cp\n CROSS JOIN drive\n WHERE cp.car_id = $car_id\n AND cp.cost IS NOT NULL AND cp.charge_energy_added > 0\n AND cp.end_date <= drive.start_date\n AND cp.end_date >= drive.start_date - INTERVAL '24 hours'\n),\nlast_charge_cost AS (\n SELECT cp.cost / NULLIF(cp.charge_energy_added, 0) AS cost_per_kwh\n FROM charging_processes cp\n CROSS JOIN drive\n WHERE cp.car_id = $car_id\n AND cp.cost IS NOT NULL AND cp.charge_energy_added > 0\n AND cp.end_date <= drive.start_date\n ORDER BY cp.end_date DESC\n LIMIT 1\n),\neffective_cost AS (\n SELECT COALESCE(recent_cost.cost_per_kwh, last_charge_cost.cost_per_kwh) AS cost_per_kwh\n FROM last_charge_cost LEFT JOIN recent_cost ON true\n)\nSELECT ROUND((drive.energy_kwh / NULLIF(drive.dist, 0) * 100 * effective_cost.cost_per_kwh)::numeric, 2) AS \"Ø Cost / 100 $length_unit\"\nFROM drive CROSS JOIN effective_cost",
2554+
"refId": "A",
2555+
"sql": {
2556+
"columns": [
2557+
{
2558+
"parameters": [],
2559+
"type": "function"
2560+
}
2561+
],
2562+
"groupBy": [
2563+
{
2564+
"property": {
2565+
"type": "string"
2566+
},
2567+
"type": "groupBy"
2568+
}
2569+
],
2570+
"limit": 50
2571+
}
2572+
}
2573+
],
2574+
"title": "Ø Cost / 100 $length_unit",
2575+
"type": "stat"
23922576
}
23932577
],
23942578
"preload": false,

0 commit comments

Comments
 (0)