Live dashboard: show what the car sends, compute pack energy

The car publishes no battery, cabin or outside temperature and no pack
energy (checked against the fields that reached InfluxDB). Instead of
panels that stay empty:

- Battery temperature tile -> Climate setpoint.
- Outside temperature tile -> Last update ("2 minutes ago").
- Energy in pack = SOC x usable capacity, from the hidden dashboard
  constant usableKwh = 50.8 (51 kWh battery).
- Temperatures chart -> Battery voltage and current.

Checked with a simulated drive carrying exactly the car's fields: all
11 panels return data, energy matches 61 % x 50.8 kWh. SPECS.md lists
the missing signals and why.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
This commit is contained in:
2026-10-17 22:17:41 +02:00
co-authored by Claude Opus 5.5
parent f3de272c69
commit 582c084b35
2 changed files with 61 additions and 15 deletions
+42 -15
View File
@@ -33,6 +33,14 @@
"current": {},
"hide": 0,
"sort": 1
},
{
"name": "usableKwh",
"label": "Usable battery capacity (kWh)",
"type": "constant",
"query": "50.8",
"hide": 2,
"description": "MG4 51 kWh battery: 50.8 kWh usable."
}
]
},
@@ -187,7 +195,7 @@
{
"id": 4,
"type": "stat",
"title": "Battery temperature",
"title": "Climate setpoint",
"datasource": {
"type": "influxdb",
"uid": "mg4-influxdb"
@@ -205,7 +213,7 @@
"type": "influxdb",
"uid": "mg4-influxdb"
},
"query": "from(bucket: \"mg4\")\n |> range(start: -30d)\n |> filter(fn: (r) => r._measurement == \"telemetry\" and r.installationId == \"${installationId}\" and r._field == \"batt_temp\")\n |> last()"
"query": "from(bucket: \"mg4\")\n |> range(start: -30d)\n |> filter(fn: (r) => r._measurement == \"telemetry\" and r.installationId == \"${installationId}\" and r._field == \"hvac_setpoint\")\n |> last()"
}
],
"fieldConfig": {
@@ -235,7 +243,7 @@
{
"id": 5,
"type": "stat",
"title": "Outside temperature",
"title": "Last update",
"datasource": {
"type": "influxdb",
"uid": "mg4-influxdb"
@@ -253,17 +261,16 @@
"type": "influxdb",
"uid": "mg4-influxdb"
},
"query": "from(bucket: \"mg4\")\n |> range(start: -30d)\n |> filter(fn: (r) => r._measurement == \"telemetry\" and r.installationId == \"${installationId}\" and r._field == \"ext_temp\")\n |> last()"
"query": "from(bucket: \"mg4\")\n |> range(start: -30d)\n |> filter(fn: (r) => r._measurement == \"telemetry\" and r.installationId == \"${installationId}\" and r._field == \"soc\")\n |> last()\n |> map(fn: (r) => ({_value: int(v: r._time) / 1000000}))"
}
],
"fieldConfig": {
"defaults": {
"unit": "celsius",
"unit": "dateTimeFromNow",
"color": {
"mode": "fixed",
"fixedColor": "#E0424C"
},
"decimals": 0
}
},
"overrides": []
},
@@ -278,7 +285,8 @@
"colorMode": "value",
"graphMode": "none",
"textMode": "value"
}
},
"description": "When the car last reported."
},
{
"id": 6,
@@ -301,7 +309,7 @@
"type": "influxdb",
"uid": "mg4-influxdb"
},
"query": "from(bucket: \"mg4\")\n |> range(start: -30d)\n |> filter(fn: (r) => r._measurement == \"telemetry\" and r.installationId == \"${installationId}\" and r._field == \"soe\")\n |> last()"
"query": "from(bucket: \"mg4\")\n |> range(start: -30d)\n |> filter(fn: (r) => r._measurement == \"telemetry\" and r.installationId == \"${installationId}\" and r._field == \"soc\")\n |> last()\n |> map(fn: (r) => ({_value: r._value / 100.0 * float(v: \"${usableKwh}\")}))"
}
],
"fieldConfig": {
@@ -326,7 +334,8 @@
"colorMode": "value",
"graphMode": "none",
"textMode": "value"
}
},
"description": "Computed: state of charge × usable capacity (dashboard constant usableKwh, 50.8 kWh for the 51 kWh battery). The car publishes no pack energy itself."
},
{
"id": 7,
@@ -527,7 +536,7 @@
{
"id": 10,
"type": "timeseries",
"title": "Temperatures",
"title": "Battery voltage and current",
"datasource": {
"type": "influxdb",
"uid": "mg4-influxdb"
@@ -545,12 +554,12 @@
"type": "influxdb",
"uid": "mg4-influxdb"
},
"query": "from(bucket: \"mg4\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"telemetry\" and r.installationId == \"${installationId}\" and (r._field == \"batt_temp\" or r._field == \"cabin_temp\" or r._field == \"ext_temp\" or r._field == \"hvac_setpoint\"))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> keep(columns: [\"_time\", \"_field\", \"_value\"])"
"query": "from(bucket: \"mg4\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"telemetry\" and r.installationId == \"${installationId}\" and (r._field == \"voltage\" or r._field == \"current\"))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> keep(columns: [\"_time\", \"_field\", \"_value\"])"
}
],
"fieldConfig": {
"defaults": {
"unit": "celsius",
"unit": "volt",
"custom": {
"lineWidth": 2,
"fillOpacity": 8,
@@ -558,7 +567,24 @@
"showPoints": "never"
}
},
"overrides": []
"overrides": [
{
"matcher": {
"id": "byRegexp",
"options": ".*current.*"
},
"properties": [
{
"id": "unit",
"value": "amp"
},
{
"id": "custom.axisPlacement",
"value": "right"
}
]
}
]
},
"options": {
"legend": {
@@ -568,7 +594,8 @@
"tooltip": {
"mode": "multi"
}
}
},
"description": "Traction battery. Current is negative while charging or regenerating."
},
{
"id": 11,