Provider: show the electric range with the climate control on

MyToyota reports two range figures for an EV, and only one of them was
reaching the readings: evRangeWithAc was listed as a fallback alias for
evRange, so on a car that reports both — every bZ4X — the first key won
and the second was never shown. It is its own reading now. The gap
between the two is the useful part: it is what running the A/C costs you.

Both are labelled for the pair, "Electric range (A/C off)" beside
"Electric range (A/C on)", so neither figure is left ambiguous now that
they sit next to each other.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tajniak81
2026-08-17 20:58:07 +02:00
co-authored by Claude Opus 5
parent bc798dae49
commit 2b6da642ad
5 changed files with 22 additions and 5 deletions
+6 -1
View File
@@ -642,7 +642,12 @@ func headlineMetrics(trees []any) []providerMetric {
{key: "fuelLevel", keys: []string{"fuelLevel", "fuelPercentage", "fuelRemainingPercent"}, unit: "%"},
{key: "fuelRange", keys: []string{"fuelRange", "rangeRemaining", "drivingRange", "fuelRangeTotal"}, unit: "km", distance: true},
{key: "batteryLevel", keys: []string{"batteryLevel", "chargeRemainingAmount", "stateOfCharge", "socLevel"}, unit: "%"},
{key: "evRange", keys: []string{"evRange", "electricRange", "batteryRange", "evRangeWithAc"}, unit: "km", distance: true},
{key: "evRange", keys: []string{"evRange", "electricRange", "batteryRange"}, unit: "km", distance: true},
// Range with the climate control running, which Toyota reports beside the
// plain one. Its own reading rather than a fallback for evRange: the two
// are different numbers and the gap between them is the point — a driver
// deciding whether to run the A/C wants to see both.
{key: "evRangeWithAc", keys: []string{"evRangeWithAc"}, unit: "km", distance: true},
}
out := []providerMetric{}
@@ -160,7 +160,8 @@ func TestFlattenJSONTruncates(t *testing.T) {
func TestHeadlineMetrics(t *testing.T) {
trees := []any{
decode(t, `{"payload": {"odometer": {"value": 270185, "unit": "km"}, "fuelLevel": 62}}`),
decode(t, `{"payload": {"batteryLevel": 80, "chargingStatus": "charging"}}`),
decode(t, `{"payload": {"batteryLevel": 80, "chargingStatus": "charging",
"evRange": {"value": 412, "unit": "km"}, "evRangeWithAc": {"value": 389, "unit": "km"}}}`),
decode(t, `{"payload": {"vehicleLocation": {"latitude": 52.2297, "longitude": 21.0122}}}`),
}
got := map[string]providerMetric{}
@@ -180,6 +181,14 @@ func TestHeadlineMetrics(t *testing.T) {
if got["chargingStatus"].Value != "charging" {
t.Errorf("chargingStatus = %+v", got["chargingStatus"])
}
// Range with the climate control on is its own reading, so a payload that
// reports both shows both rather than one standing in for the other.
if got["evRange"].Value != "412" || got["evRange"].Unit != "km" {
t.Errorf("evRange = %+v", got["evRange"])
}
if got["evRangeWithAc"].Value != "389" || got["evRangeWithAc"].Unit != "km" {
t.Errorf("evRangeWithAc = %+v", got["evRangeWithAc"])
}
if got["location"].Value != "52.22970, 21.01220" {
t.Errorf("location = %+v", got["location"])
}
+2 -1
View File
@@ -324,7 +324,8 @@
"fuelLevel": "Brændstofniveau",
"fuelRange": "Rækkevidde",
"batteryLevel": "Batteri",
"evRange": "Elektrisk rækkevidde",
"evRange": "Elektrisk rækkevidde (uden aircon)",
"evRangeWithAc": "Elektrisk rækkevidde (med aircon)",
"chargingStatus": "Opladning",
"location": "Position"
}
+2 -1
View File
@@ -399,7 +399,8 @@
"fuelLevel": "Fuel level",
"fuelRange": "Range",
"batteryLevel": "Battery",
"evRange": "Electric range",
"evRange": "Electric range (A/C off)",
"evRangeWithAc": "Electric range (A/C on)",
"chargingStatus": "Charging",
"location": "Position"
}
+2 -1
View File
@@ -328,7 +328,8 @@
"fuelLevel": "Poziom paliwa",
"fuelRange": "Zasięg",
"batteryLevel": "Akumulator",
"evRange": "Zasięg elektryczny",
"evRange": "Zasięg elektryczny (bez klimatyzacji)",
"evRangeWithAc": "Zasięg elektryczny (z klimatyzacją)",
"chargingStatus": "Ładowanie",
"location": "Pozycja"
}