package main import "time" // Totals are one day's (or one chunk's) consumption counters. type Totals struct { Km float64 `json:"km"` Kwh float64 `json:"kwh"` Hours float64 `json:"hours"` SocDrop float64 `json:"socDrop"` } func (t *Totals) add(o Totals) { t.Km += o.Km t.Kwh += o.Kwh t.Hours += o.Hours t.SocDrop += o.SocDrop } // ConsumptionChunk is one 2-minute delta of a day's consumption, as the car sends it. // Days are built from these when history is read. type ConsumptionChunk struct { InstallationID string Date string // the car's local date, YYYY-MM-DD RecordedAt time.Time Day Totals SohPercent *float64 } // DailyConsumption is a day folded from its chunks. type DailyConsumption struct { InstallationID string `json:"installationId"` Date string `json:"date"` RecordedAt time.Time `json:"recordedAt"` Day Totals `json:"day"` SohPercent *float64 `json:"sohPercent,omitempty"` // Lifetime is the running total up to and including this day; not part of the // car's history response, which carries one lifetime for all days. Lifetime Totals `json:"-"` } type CurvePoint struct { Timestamp time.Time PowerKw float64 SocPercent *float64 } type ChargingSession struct { InstallationID string SessionID string StartedAt time.Time EndedAt time.Time DurationSeconds float64 EnergyKwh float64 ChargingLossPercent float64 GridEnergyKwh float64 PricePerKwh float64 TotalCost float64 IsDemo bool StartSocPercent *float64 EndSocPercent *float64 Curve []CurvePoint } // telemetryNumbers are the numeric live fields, named and unit-ed as ABRP's tlm/send // expects them, with the range each one must fall in. var telemetryNumbers = map[string][2]float64{ "soc": {0, 100}, // % "speed": {0, 400}, // km/h "power": {-1000, 1000}, // kW, positive leaving the battery "est_battery_range": {0, 2000}, // km "capacity": {0, 500}, // kWh "soe": {0, 500}, // kWh "soh": {0, 100}, // % "kwh_charged": {0, 1000}, // kWh, this charge session "odometer": {0, 10_000_000}, // km "lat": {-90, 90}, // ° "lon": {-180, 180}, // ° "elevation": {-1000, 10_000}, // m "heading": {0, 360}, // ° "batt_temp": {-60, 100}, // °C "cabin_temp": {-60, 100}, // °C "ext_temp": {-60, 70}, // °C "hvac_setpoint": {0, 40}, // °C "hvac_power": {0, 50}, // kW "voltage": {0, 1500}, // V "current": {-2000, 2000}, // A "tire_pressure_fl": {0, 1000}, // kPa "tire_pressure_fr": {0, 1000}, // kPa "tire_pressure_rl": {0, 1000}, // kPa "tire_pressure_rr": {0, 1000}, // kPa } // telemetryFlags are the boolean live fields; ABRP takes them as 0/1. var telemetryFlags = []string{"is_charging", "is_dcfc", "is_parked"} // TelemetrySample is one live sample. Only UTC is always present; an unread signal is // absent from Numbers and Flags, never 0. type TelemetrySample struct { UTC int64 // epoch seconds Numbers map[string]float64 Flags map[string]bool } type TelemetryBatch struct { InstallationID string Samples []TelemetrySample }