{"id":50305507,"url":"https://github.com/boraita/hass-ev-trip-logger","last_synced_at":"2026-06-27T11:00:30.343Z","repository":{"id":360913427,"uuid":"1252250831","full_name":"boraita/hass-ev-trip-logger","owner":"boraita","description":"Vehicle-agnostic EV trip logger for Home Assistant. Configurable with any odometer/battery/vehicle-on sensors. Live + historical trip stats with SQLite persistence.","archived":false,"fork":false,"pushed_at":"2026-06-24T19:34:41.000Z","size":1223,"stargazers_count":2,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-24T20:10:41.129Z","etag":null,"topics":["byd","electric-vehicle","ev","hacs","hacs-integration","home-assistant","homeassistant","kia","tesla","trip-logger"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/boraita.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-28T10:36:25.000Z","updated_at":"2026-06-24T19:34:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/boraita/hass-ev-trip-logger","commit_stats":null,"previous_names":["boraita/hass-ev-trip-logger"],"tags_count":130,"template":false,"template_full_name":null,"purl":"pkg:github/boraita/hass-ev-trip-logger","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boraita%2Fhass-ev-trip-logger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boraita%2Fhass-ev-trip-logger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boraita%2Fhass-ev-trip-logger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boraita%2Fhass-ev-trip-logger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/boraita","download_url":"https://codeload.github.com/boraita/hass-ev-trip-logger/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boraita%2Fhass-ev-trip-logger/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34850575,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["byd","electric-vehicle","ev","hacs","hacs-integration","home-assistant","homeassistant","kia","tesla","trip-logger"],"created_at":"2026-05-28T16:00:34.331Z","updated_at":"2026-06-27T11:00:30.336Z","avatar_url":"https://github.com/boraita.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/brand/logo.png\" alt=\"EV Trip Logger\" width=\"640\"\u003e\n\u003c/p\u003e\n\n# EV Trip Logger for Home Assistant\n\n\u003cp\u003e\n  \u003ca href=\"https://github.com/boraita/hass-ev-trip-logger/actions/workflows/validate.yml\"\u003e\u003cimg src=\"https://github.com/boraita/hass-ev-trip-logger/actions/workflows/validate.yml/badge.svg?branch=main\" alt=\"Validate (hassfest + HACS + tests)\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/boraita/hass-ev-trip-logger/actions/workflows/release.yml\"\u003e\u003cimg src=\"https://github.com/boraita/hass-ev-trip-logger/actions/workflows/release.yml/badge.svg\" alt=\"Release\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/boraita/hass-ev-trip-logger/releases/latest\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/boraita/hass-ev-trip-logger?label=version\" alt=\"Latest release\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/hacs/integration\"\u003e\u003cimg src=\"https://img.shields.io/badge/HACS-custom-41BDF5.svg\" alt=\"HACS custom repository\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/boraita/hass-ev-trip-logger\" alt=\"License\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n**Health at a glance:** the *Validate* badge runs on every push and every night (hassfest, HACS validation, and the full pytest suite of 108+ tests) — green means the integration installs and its trip/charge logic passes against the latest Home Assistant.\n\nA vehicle-agnostic Home Assistant custom integration that records every drive and charge from the entities your manufacturer integration already exposes, derives accurate consumption / cost / journey aggregates, **calibrates itself to your specific car over time**, and surfaces everything through standard HA sensors so any dashboard can consume the data.\n\nWorks with **any cloud-polled EV integration** — BYD, Tesla Fleet, OVMS, Bouncie, native CAN-bus dongles, even a manual setup. You point it at the entities you already have; it does the rest.\n\n\u003e Companion dashboard with ~25 ready-to-use cards: **[hass-ev-trip-dashboard](https://github.com/boraita/hass-ev-trip-dashboard)**.\n\n---\n\n## Screenshots\n\nA few views from the companion [`hass-ev-trip-dashboard`](https://github.com/boraita/hass-ev-trip-dashboard) — every value below comes from sensors / attributes this integration exposes.\n\n| | |\n|---|---|\n| ![Status, live charging \u0026 driving](docs/screenshots/01-status-charging-driving.png) | ![Trips list with search \u0026 filter](docs/screenshots/02-trips-list-search.png) |\n| Live status: battery curve, plug state, today's journey + charging / driving sparklines. | Recent trips with kWh/100km, score, cost — filter by date / score / max consumption. |\n| ![Calendar activity](docs/screenshots/03-activity-calendar.png) | ![Trends \u0026 savings vs petrol](docs/screenshots/04-trends-savings.png) |\n| Monthly calendar with trips + charges per day. | Savings vs petrol baseline, monthly cost projection, long-trip / avg-trip records. |\n| ![Driving patterns + per-driver stats](docs/screenshots/05-patterns-drivers.png) | ![Efficiency analytics](docs/screenshots/06-efficiency-analysis.png) |\n| When you drive (hour-of-day, weekday) + per-driver breakdown when a `driver_sensor` is wired. | Consumption by speed / season / time-of-day / temperature, scatter chart, battery health (SoH 100 %). |\n| ![Charges history \u0026 insights](docs/screenshots/07-charges-history.png) | |\n| Per-period kWh charged / spent / driving, charging insights (cheapest / DCFC / avg session), full charge history. | |\n\nThe dashboard is **optional** — every metric is a regular HA sensor or sensor-attribute, so you can build your own card or template against them.\n\n---\n\n## Why\n\nCloud-polled EVs have stale, integer-step SoC, sparse odometer ticks, and unreliable `vehicle_on` transitions. Out of the box that makes:\n- consumption per trip off by 1–2 % (or NULL on short trips),\n- single drives split into multiple rows,\n- overnight charges silently dropped on reload,\n- journeys (casa → … → casa) shown as 1-stage fragments,\n- addresses stuck as `not_home`,\n- score curves that assume a Tesla and unfairly rate a BYD in the Alps as 1/10.\n\nThis integration solves all of that with explicit state machines, **per-car self-calibration**, weather correlation, and a battery-health model anchored in real fleet data (Geotab 22,700 EVs, Tesla 2023 Impact Report, BYD warranty, ADAC, Recurrent). The hard work of v0.5.x is documented in [the release notes](https://github.com/boraita/hass-ev-trip-logger/releases).\n\n---\n\n## Highlights (v0.5.49 – v0.5.59)\n\n| Area | What you get |\n|---|---|\n| **Trip detection** | Live-open retry chain when odometer lags `vehicle_on=on` flanco (BYD cloud poll 6 min off-edge protection). 180 s off-grace so a red-light / pickup stop no longer closes the trip. Synthetic finalize cancelled when ignition returns. |\n| **Score calibration** | The 10/10 anchor is the car's own **P5 historical consumption** (over trips ≥ 5 km, ≥ 10 trips). Falls back to 14.5 kWh/100 km — the calibration can only RAISE the bar, never lower it. Configurable battery chemistry. |\n| **Energy precision** | Effective battery capacity auto-calibrated from real charges (median of `kwh / ΔSoC × 100` over recent charges ≥ 30 % ΔSoC). Heals all historical SoC-derived trips when calibration shifts. |\n| **Weather correlation** | Optional `weather.*` entity captures temperature / condition / humidity / wind / precipitation at trip open + close. Three new bucket sensors: consumption-by-season, by-time-of-day, by-temperature. |\n| **Battery health (SoH)** | Live `battery_soh` (% of declared capacity actually delivered). Plus `expected_battery_soh` modelled from your km / age / chemistry / climate / DCFC habits with constants from Geotab + Tesla + ADAC + NREL + BYD warranty (8 yr / 250 k km, ≥ 70 %). `battery_health_vs_expected` enum tells you if you're ahead/on-track/behind the curve. |\n| **Degradation tracking** | `capacity_history` table appends a snapshot whenever the calibrated capacity drifts ≥ 0.5 kWh — long-term degradation curve visible from day one. |\n\n---\n\n## What you get (full feature set)\n\n### Trip detection\n- `vehicle_on` off → on opens a trip via a **retry chain** (15 / 30 / 60 / 120 s) — covers cloud-polled cars where the odometer lags the ignition flag.\n- on → off applies a **180 s grace window**. A flicker, a red light, a brief stop with engine off all keep the trip open. Grace is cancelled by either a fresh on-edge or by the timer expiring; close time backdates to the actual off-edge.\n- Stuck / missed cycles reconstructed from monotonic odometer growth (synthetic trips, tagged `confidence='reconstructed'` or `'reconstructed_polling_paused'`).\n- Synthetic finalize **aborts** if `vehicle_on=on` at fire time — prevents the path-mix bug where a trip closed mid-drive losing the remaining km.\n- Idle watchdog defers to the off-grace when a close is already pending.\n- Manual `log_manual_trip` and `recover_missing_trips` services for back-filling.\n\n### Energy accounting\n- **Effective battery capacity calibration** (v0.5.51): each charge with ≥ 30 % ΔSoC and `soc_start` populated contributes a sample `kwh / ΔSoC × 100`. Median of the last 30 such charges (minimum 5) replaces the declared capacity. Heals all historic SoC-derived trips on each shift.\n- **Stale SoC resolution**: pick `soc_start` from `last_charge.soc_end`, the ring buffer, or current value — whichever is most trustworthy.\n- **Power integration backup** (∫ |power| dt during the trip), capped at 250 kW and 20 min trapezoid width. Pessimistic `max(energy_soc, energy_pwr)` is the canonical figure.\n- **Inline `distance × avg_consumption` fallback** at close when both SoC delta and power-integration come back empty.\n- **Regen tracking** via negative-power trapezoidal integration. Aggregated to today / week / month / 30d / year / lifetime sensors.\n\n### Score (per-car calibrated, v0.5.50/52)\n- The 10/10 anchor (the kWh/100 km that maps to a perfect score) is no longer hardcoded to a vendor's marketing curve (the original 14.5 came from the BYD app, but Tesla's, Hyundai's, Ford's would all give different defaults). It's the P5 of YOUR consumption over trips ≥ 5 km, once 10+ such trips exist.\n- Clamped to `[14.5, 20.0]` — the calibration can only **raise the bar** (a Tesla needing 18 kWh/100 km for 10/10 is realistic) but never **lower it** (a freak downhill trip at 5 kWh/100 km can't pin the curve unfairly).\n- Live, last-trip and best-ever scores all use the per-car anchor.\n- `score_baseline_kwh_100km` and `score_baseline_trip_count` exposed as attributes of `recent_trips` for dashboards.\n\n### Battery health \u0026 degradation tracking (v0.5.54 / v0.5.57)\n- **`sensor.\u003cdevice\u003e_battery_soh`** — observed state of health (calibrated capacity / declared × 100). Stays at 100 until 5+ valid charges build the calibration.\n- **`sensor.\u003cdevice\u003e_expected_battery_soh`** — modelled SoH from your km, age, chemistry, climate and habits. Floor at 70 % (most manufacturers' battery warranty floor — BYD, Tesla, Hyundai/Kia, VW all guarantee ≥ 70 % at the warranty horizon).\n- **`sensor.\u003cdevice\u003e_battery_health_vs_expected`** — enum: `calibrating` / `ahead` (\u003e +2 pp) / `on_track` (±2 pp) / `behind` (\u003c −2 pp).\n- **`capacity_history`** table: every shift ≥ 0.5 kWh in calibrated capacity gets a row. Lets the dashboard plot the degradation curve.\n- Three chemistry profiles supported with constants derived from real research:\n  - `lfp` (BYD Blade, Tesla SR, MG, Atto3, Sealion 7 ← default for ≥ 75 kWh packs)\n  - `nmc` (Tesla LR, BMW iX, VW ID, most 2018+)\n  - `nca` (older Tesla Model S/X)\n\n### Weather \u0026 seasonal analytics (v0.5.54)\n- Optional `weather.*` entity is sampled at trip open and close; averages persisted on the trip row as `ambient_temp_c`, `weather_condition`, `humidity_pct`, `wind_kmh`, `precipitation_mm`.\n- **`sensor.\u003cdevice\u003e_consumption_by_season`** — winter / spring / summer / autumn (Northern hemisphere). State = current season; attributes carry all four.\n- **`sensor.\u003cdevice\u003e_consumption_by_time_of_day`** — night (22-06) / morning (06-12) / midday (12-15) / afternoon (15-19) / evening (19-22).\n- **`sensor.\u003cdevice\u003e_consumption_by_temp_bucket`** — \u003c 5 / 5-15 / 15-25 / 25-35 / ≥ 35 °C (uses the optional `exterior_temp_sensor`).\n\n### Journeys\n- A journey opens iff a trip starts at home and ends away; closes iff a trip ends at home. Time gaps between intermediate trips are irrelevant.\n- Auto-stitch: a trip ending at home with no open journey mints a fresh id AND absorbs orphan trips since the last home-arrival into it, so the full `casa → … → casa` chain renders as one row.\n- Resume on restart via SQL (not in-memory state), so a mid-trip reload never loses the open journey.\n\n### Charges\n- Auto-detected from your `charge_sensor`. Plug-sensor wired ⇒ multiple charging pulses inside one plugged interval merge into a single session.\n- `_maybe_resume_charge` recovers a session that started before HA restarted (without it, the entire charge would be dropped).\n- `kwh_charged_before` and `kwh_charged_during` attributes on every trip let the dashboard show \"+24 kWh between trips\" so a SoC bump isn't mysterious.\n- Per-session `soc_start` + `soc_end` are stored so the battery-capacity calibration can derive the real pack size from observation.\n- **Power-integration during charge (v0.5.89+)** — if your `power_sensor` is wired, the integration sums ∫P·dt over the whole charge and uses it as the kWh persisted when it's within ±30 % of the SoC-derived number. Captures the full charge curve including the high-SoC taper where each percent represents more time → more accurate than `Δ% × nominal_capacity`.\n- **EVSE / wallbox tracking (v0.5.90+, optional)** — wire any wallbox power sensor as `evse_power_sensor` (W or kW auto-detected). The integration measures AC-side energy delivered and computes real AC→DC efficiency = `battery_kwh / evse_kwh × 100`. Works with **any wallbox**: V2C Trydan, Shelly EM/Pro 3EM, Wallbox Pulsar / Quasar, Tesla Wall Connector, Easee, Zappi, Smartfox, OpenEVSE, etc. Five new sensors expose the data — see [Sensors exposed](#sensors-exposed). A 30-day rolling-median efficiency catches lossy cables / derated chargers (drop below 85 %).\n\n### GPS / routing\n- Every cloud poll fills a ring buffer of `(ts, lat, lon)` samples. Trips open with a real start anchor; synth trips persist a route to `trip_positions`.\n- `gps_distance_km` is the haversine sum over the route — compared against the odometer-derived `distance_km` it surfaces sensor lag or fused trips.\n- New trips reverse-geocode their endpoints via Nominatim; old trips backfilled from recorder history at startup.\n\n### Driver tracking (v0.5.43+)\n- Optional `driver_sensor` entity (any sensor whose state names who is driving — e.g. the car's \"connected bluetooth device\" entity, an `input_select`, or a template sensor mapping BT MAC → person).\n- Captured at trip open with retry on every live tick until BT pairs.\n- `sensor.\u003cdevice\u003e_driver_stats_30_days` and `sensor.\u003cdevice\u003e_current_driver` surface per-driver km, hours, trip counts.\n\n### ABRP (A Better Route Planner)\n- In-tree client. Configure `abrp_token` + `abrp_api_key` + `abrp_car_model` in the options flow.\n- Telemetry piggy-backs on existing metric events — **no new poll forced** on the manufacturer's cloud.\n- `switch.abrp_push` (RestoreEntity) — runtime kill switch your automations can toggle. Pushes immediately when turned on (no waiting for the next metric tick).\n- `abrp_push_interval_s` is user-configurable (5..600 s, default 30).\n- Sensor `\u003cdevice\u003e_abrp_next_charge_soc` reads ABRP's next-charge target every 2 min while a route is active.\n\n### Recovery \u0026 corrections\n- **`recover_missing_trips`** — scans the recorder for odo growth not covered by any existing trip and inserts synth records. Never modifies existing rows.\n- **`set_trip(trip_id, …)`** — patch any field on any trip (origin, destination, energy, journey_id, timestamps, GPS, address, etc.).\n- **`set_charge(charge_id, …)`** — same for charges. kWh edits auto-recompute total_cost.\n- `confidence` column tags every trip as `live` / `reconstructed` / `reconstructed_polling_paused` / `reconstructed_recovery` / `orphan` / `orphan_odo_only` so dashboards can warn about low-quality rows.\n\n---\n\n## Install (HACS)\n\n1. HACS → Integrations → ⋮ → Custom repositories → add `https://github.com/boraita/hass-ev-trip-logger`, category **Integration**.\n2. Install **EV Trip Logger**, restart HA.\n3. Settings → Devices \u0026 Services → **Add Integration** → \"EV Trip Logger\".\n\n---\n\n## Configuration\n\nThe wizard asks for the entities the integration consumes. **Required** first, optional after. Everything except the four required-✅ fields can be added later via *Configure* without losing history.\n\n| Field | Required | What it's for |\n|---|---|---|\n| **Name** | ✅ | Device label (free text). |\n| **Odometer sensor** | ✅ | `sensor.…_odometer` — km, monotonic. |\n| **Battery sensor** | ✅ | `sensor.…_battery_level` — %, 0..100. |\n| **Vehicle-on binary sensor** | ✅ | `binary_sensor.…_vehicle_on`. Primary trip trigger. |\n| **Battery capacity (kWh)** | ✅ | E.g. 82.5 for a Sealion 7 Extended Range. Used as the **declared** capacity; the integration auto-calibrates the effective capacity from charges. |\n| **Home zone** | ✅ | Usually `zone.home`. Journey logic uses it. |\n| Power sensor | optional | kW, +discharge/-charge. Enables regen + power-integration backup + ABRP push. If your car reports the opposite convention (e.g. some BYD cloud entities are -discharge/+charge), toggle **Power sign inverted**. |\n| Power sign inverted | optional | Default off (positive = discharge). Flip ON when your car's `power_sensor` reports the inverse — telltale sign: persistent `regen_kwh` higher than `energy_kwh` even on flat trips. Auto-detected sensors that need this: BYD cloud-API `*_power`. |\n| **EVSE power sensor** | optional | Any wallbox or socket-meter power entity (W or kW auto-detected). Enables AC-side energy + AC→DC efficiency measurement. Works with V2C Trydan, Shelly Pro/EM, Wallbox Pulsar/Quasar, Tesla Wall Connector, Easee, Zappi, Smartfox, OpenEVSE, generic Shelly relays. See [Wallbox examples](#wallbox-examples). |\n| Charge sensor | optional | `binary_sensor.…_charging` OR any `sensor.*` whose state names the charging mode. Recognised \"charging\" values: `on`, `true`, `1`, `Charging`, `Starting`, `Engaged`, `ac_charging`, `dc_charging`, `slow_charging`, `fast_charging` (case-insensitive). Anything else (`off`, `Disconnected`, `Complete`, `Stopped`, `NoPower`, `idle`, `done`…) counts as \"not charging\". |\n| Plug binary sensor | optional | Lets multi-pulse plugged sessions merge into one charge row. |\n| Polling-paused sensor | optional | A switch or binary_sensor that goes ON when the manufacturer integration sleeps. Synth trips in that window get tagged `reconstructed_polling_paused`. |\n| Location tracker | optional | `device_tracker.…_location`. Drives origin/destination + route map. |\n| **Weather entity** | optional | Any `weather.*` (AEMET, Met.no, OpenWeatherMap…). Enables the season / temperature / time-of-day buckets. See [Get the most out of it](#get-the-most-out-of-it). |\n| Outside temp sensor | optional | Per-trip avg temp + the historical `consumption_by_temp_bucket` sensor. |\n| Driver sensor | optional | Entity whose state names who is driving (e.g. car's bluetooth-connected-device sensor). Powers per-driver stats. |\n| Speed sensor | optional | Refines the idle watchdog + ABRP `speed`. |\n| **Battery chemistry** | optional | `lfp` (default for packs ≥ 75 kWh — covers BYD Blade, Sealion 7, MG, Tesla SR), `nmc`, `nca`. Drives the `expected_battery_soh` model. |\n| **Vehicle first-registered date** | optional | ISO date (YYYY-MM-DD). Feeds the calendar-aging component of expected SoH. When missing, falls back to a `km / 15 000` proxy and lowers `confidence` to `medium`. |\n| Min trip distance | ✅ | Default 0.5 km. Trips under this are discarded (precon/climate, not real drives). |\n| Idle timeout | ✅ | Mid-trip stop tolerance (minutes). |\n| Energy price (€/kWh) | ✅ | Home tariff. Trip cost = energy × this price (NOT per-charge price — see [why](#why-trip-cost-is-the-home-tariff)). |\n| Currency | ✅ | \"EUR\", \"USD\", etc. |\n| Recent trips limit | ✅ | How many rows the `_recent_trips` attribute exposes (5..200, default 50). |\n| ABRP token / api_key / car_model | optional | Enables ABRP telemetry push. |\n| ABRP push interval (s) | optional | Throttle for outbound pushes (5..600, default 30). |\n\n---\n\n### Vehicle examples (the integration is car-agnostic)\n\n| Car / source | `odometer` | `battery` | `vehicle_on` | `power` | Notes |\n|---|---|---|---|---|---|\n| **BYD** (cloud) | `sensor.\u003ccar\u003e_odometer` | `sensor.\u003ccar\u003e_battery_level` | `binary_sensor.\u003ccar\u003e_vehicle_on` | `sensor.\u003ccar\u003e_power` | Enable **Power sign inverted** (BYD cloud uses +charge/-discharge). |\n| **Tesla** (Fleet / Teslemetry) | `sensor.\u003ccar\u003e_odometer` | `sensor.\u003ccar\u003e_battery_level` | `binary_sensor.\u003ccar\u003e_vehicle_on` | `sensor.\u003ccar\u003e_power` (when exposed) | Power sign inverted **OFF** (Tesla uses +discharge). |\n| **BMW** (BimmerConnected) | `sensor.\u003ccar\u003e_mileage` | `sensor.\u003ccar\u003e_remaining_battery_percent` | `binary_sensor.\u003ccar\u003e_charging_status` (inverted) | — | No live power → SoC-only trip math, still works. |\n| **Hyundai/Kia** (Bluelink) | `sensor.\u003ccar\u003e_odometer` | `sensor.\u003ccar\u003e_ev_battery_level` | template from `Engine` enum | — | Same as BMW. |\n| **OVMS** (CAN dongle) | `sensor.ovms_\u003cid\u003e_v_p_odometer` | `sensor.ovms_\u003cid\u003e_v_b_soc` | `binary_sensor.ovms_\u003cid\u003e_v_e_on` | `sensor.ovms_\u003cid\u003e_v_b_power` | Best-case: real CAN-rate power → consumption math near-perfect. |\n| **MQTT manual** | any `sensor.*` | any `sensor.*` | any `binary_sensor.*` | optional | DIY setups: just publish the metrics. |\n\n### Wallbox examples\n\nAny HA entity that reports **charger output power in W or kW** works as `evse_power_sensor`:\n\n| Wallbox / meter | Typical entity_id | Unit |\n|---|---|---|\n| V2C Trydan | `sensor.evse_\u003cip\u003e_charge_power` | W |\n| Shelly EM / Pro 3EM (meter on the cable) | `sensor.shellyemxxx_channel_\u003cn\u003e_power` | W |\n| Wallbox Pulsar Plus / Quasar | `sensor.wallbox_\u003cid\u003e_charging_power` | kW |\n| Tesla Wall Connector | `sensor.tesla_wall_connector_power` | kW |\n| Easee | `sensor.easee_\u003cid\u003e_session_energy_or_power` | W or kW |\n| Zappi (myenergi) | `sensor.zappi_\u003csn\u003e_ct_ev` | W |\n| Smartfox | `sensor.smartfox_charging_power` | W |\n| OpenEVSE | `sensor.openevse_\u003chost\u003e_charge_power` | W |\n| Generic Shelly relay metering charger socket | `sensor.\u003cshelly\u003e_power` | W |\n\nThe integration auto-detects the unit (`W` → divides by 1000 internally). Pick the sensor that reports **only the EV charging power**, not the whole house — otherwise the AC→DC efficiency will be skewed by background loads.\n\n---\n\n## Get the most out of it\n\nThe integration works with just the 6 required fields, but **enabling the optionals unlocks the analytics that make the dashboard useful**. Here's the minimum-effort path to full tracking:\n\n### 1. Add a `weather.*` integration to HA (5 minutes, free)\n\nAny one of these:\n- **AEMET OpenData** (Spain): Settings → Devices → Add Integration → AEMET OpenData → request a free token at `opendata.aemet.es`. Produces `weather.casa`.\n- **Met.no**: built-in HA integration, no API key. Just add the integration.\n- **OpenWeatherMap**: free tier, requires API key.\n\nThen in EV Trip Logger → Configure → set **Weather entity** = `weather.casa` (or whatever yours is called).\n\nThis unlocks:\n- `ambient_temp_c`, `humidity_pct`, `wind_kmh`, `precipitation_mm`, `weather_condition` on every new trip\n- `sensor.\u003cdevice\u003e_consumption_by_season` (state = current season's avg consumption)\n- `sensor.\u003cdevice\u003e_consumption_by_time_of_day` (night vs morning vs ...)\n- The `climate_hot` factor in the expected-SoH model gets real input (raising your `confidence` from `medium` to `high`)\n\n### 2. Set battery chemistry + first-registered date\n\nIn Configure:\n- **Battery chemistry**: `lfp` for BYD Blade / Tesla SR / MG / Atto 3 / Sealion 7. `nmc` for Tesla LR / BMW iX / VW ID / most 2018+ premium EVs. `nca` for older Tesla S/X.\n- **Vehicle first-registered**: pick the matriculation date of your car.\n\nThis makes the `expected_battery_soh` curve align with real research data for YOUR chemistry, and pushes the model `confidence` from `low` → `medium` → `high`.\n\n### 3. Drive normally for a week\n\nThe integration calibrates itself automatically as data flows in:\n\n| Self-calibrating thing | What it needs |\n|---|---|\n| **Effective battery capacity** | 5 charges with ΔSoC ≥ 30 % AND `soc_start` populated. After that, all historical trips' energy/consumption auto-update. |\n| **Score per-car anchor** | 10+ trips with `distance ≥ 5 km` and `consumption ∈ [5, 50]` kWh/100 km. After that, the 10/10 reference moves to your P5. |\n| **Weather aggregates** | 5+ trips with the weather entity sampled (i.e. trips opened/closed after step 1). |\n| **Degradation curve** | Each ≥ 0.5 kWh shift in calibrated capacity adds a row to `capacity_history`. Real degradation typically becomes visible at 6-12 months. |\n\n### 4. (Optional) Install the dashboard\n\nThe companion dashboard at [hass-ev-trip-dashboard](https://github.com/boraita/hass-ev-trip-dashboard) consumes every sensor and attribute documented here, with ready-made cards for trips, journeys, charges, weather, seasonal stats, battery health, SoH curve, driver stats, etc.\n\n---\n\n## Why trip cost is the home tariff\n\nA charge at a €0.40/kWh public DC fast-charger is a one-off event; the energy already mixed with home-charged kWh in the battery. Trip cost is therefore modelled as `energy × home_tariff`. Each individual charge record keeps its **actual** price in its own row, visible in the AC / DC monthly averages.\n\n---\n\n## Services\n\nAll services accept an optional `entry_id` to target a specific config entry when you have multiple vehicles.\n\n| Service | Purpose |\n|---|---|\n| `start_trip` / `end_trip` | Manually bracket a trip when sensors fail you. |\n| `log_charge` | Manually insert a charge (kwh + optional price/location/notes). |\n| `log_manual_trip` | Insert a full trip backfill (started_at, ended_at, distance, soc, etc.). |\n| `set_trip(trip_id, …)` | Patch any column on a logged trip. |\n| `set_charge(charge_id, …)` | Patch any column on a logged charge. |\n| `set_last_charge_price(price_per_kwh \\| total_cost \\| charge_id, …)` | Correct a charge's price; triggers a trip cost recompute. |\n| `delete_last_trip` / `delete_last_charge` | Drop the most recent row. |\n| `purge_trips(since, until)` | Bulk delete in a date range. |\n| `recover_missing_trips(since, until?)` | **Recovery mode** — scan recorder for odo growth not covered by any trip and insert synth rows. Existing trips are never modified. |\n| `export_csv(path)` | Dump every trip to CSV. |\n\n---\n\n## Sensors exposed\n\nA complete list lives in the source (`sensor.py`). The headline ones, all prefixed `sensor.\u003cdevice\u003e_`:\n\n### Live/last/aggregates per metric\n`current_trip_*`, `last_trip_*`, `distance_today`, `distance_this_week`, `energy_this_month`, etc., for: distance, duration, energy, consumption, avg_speed, max_speed, max_power, regen, battery_used, score, cost, avg_temperature.\n\n### Charges\n`last_charge_*`, `current_charge_*`, `charges_30d_*`, plus AC/DC price breakdowns.\n\n**EVSE / efficiency (v0.5.89+, requires `evse_power_sensor` wired)**\n- `last_charge_evse_kwh` / `current_charge_evse_kwh` — AC-side energy delivered by the wallbox.\n- `last_charge_efficiency` / `current_charge_efficiency` — `battery_kwh / evse_kwh × 100`.\n- `avg_charging_efficiency_30d` — rolling median across the last 30 charge sessions with an EVSE sensor wired. AC home charger: 88–94 %. DCFC: 92–97 %. Below 85 % signals a lossy cable / wallbox derating / inefficient onboard charger.\n\n### Journeys\n`current_journey`, `last_journey`, `recent_journeys` (with stages list).\n\n### Routing\n`recent_trips` (attribute `trips` = list of dicts with everything; also `score_baseline_kwh_100km`, `effective_battery_capacity_kwh`, `battery_capacity_calibration_charges` for transparency).\n`last_trip_route` (attribute `points` = downsampled route).\n`trip_patterns` (by hour / weekday).\n\n### Records \u0026 rankings\n`trip_records.totals.{distance_km, energy_kwh, cost, regen_kwh, trips}`, `tops` (longest, top_efficiency, cheapest, …).\n\n### Battery \u0026 range\n`battery_energy` (kWh in battery), `energy_to_full_charge`, `battery_percent`, `range_at_recent_efficiency`.\n\n### Battery health (v0.5.54 / v0.5.57)\n- **`battery_soh`** — observed state of health (%). Stays at 100 until the calibration kicks in (5+ charges).\n- **`expected_battery_soh`** — modelled SoH for your km/age/chemistry/climate/habits. Attributes break the loss down: `year1_knee`, `calendar`, `cycle`, `climate_hot`, `dcfc`, `soc_habit`. Also: `confidence` (low/medium/high based on what config you've filled).\n- **`battery_health_vs_expected`** — enum: `calibrating` / `ahead` / `on_track` / `behind`. Attributes: `observed_soh_pct`, `expected_soh_pct`, `delta_pp`.\n\n### Seasonal / temporal (v0.5.54)\n- **`consumption_by_season`** — state = current season's avg consumption; attributes carry the full `by_season` dict.\n- **`consumption_by_time_of_day`** — state = current bucket's avg consumption (night / morning / midday / afternoon / evening).\n- **`consumption_by_temp_bucket`** — \u003c 5 / 5-15 / 15-25 / 25-35 / ≥ 35 °C (requires `exterior_temp_sensor`).\n\n### Driver\n`current_driver`, `driver_stats_30_days` (per-driver km, hours, trip counts).\n\n### ABRP (only when configured)\n`switch.abrp_push`, `abrp_next_charge_soc`.\n\n---\n\n## ABRP setup (optional)\n\n1. In the ABRP app: car → *Edit Car Connection Details → Generic OEM → Link*. Copy **user token** and **api key**.\n2. HA → Settings → Devices \u0026 Services → EV Trip Logger → **Configure** → paste them. `car_model` example: `byd:sealion:25:82:rwd`.\n3. The new `switch.abrp_push` defaults to ON. To replicate the legacy `abrp_telemetry` \"only while driving\" pattern, point your automations at it:\n\n```yaml\n- alias: ABRP only while driving\n  triggers:\n    - trigger: state\n      entity_id: binary_sensor.\u003cvehicle\u003e_vehicle_on\n      to: \"on\"\n      id: \"on\"\n    - trigger: state\n      entity_id: binary_sensor.\u003cvehicle\u003e_vehicle_on\n      to: \"off\"\n      id: \"off\"\n  actions:\n    - choose:\n        - conditions: [{ condition: trigger, id: \"on\" }]\n          sequence: [{ action: switch.turn_on, target: { entity_id: switch.abrp_push } }]\n      default:\n        - action: switch.turn_off\n          target: { entity_id: switch.abrp_push }\n```\n\n---\n\n## Recovery workflow\n\nWhen you notice a trip missing or with wrong data:\n\n```yaml\n# Developer Tools → Actions\nservice: ev_trip_logger.recover_missing_trips\ndata:\n  since: 2026-06-01 00:00:00\n  until: 2026-06-08 23:59:59     # optional, defaults to now\n```\n\nExisting rows are never touched (±2 min tolerance). New rows are tagged `confidence='reconstructed_recovery'` so the dashboard can show a \"low confidence\" badge.\n\nFor one-off corrections:\n\n```yaml\nservice: ev_trip_logger.set_trip\ndata:\n  trip_id: 130\n  origin: home\n  started_at: 2026-06-07 22:20:00\n  journey_id: 13\n```\n\n---\n\n## Tracking checklist\n\nFor dashboards / analytics to make full use of the integration, every box should be ticked. Most of them are zero-effort one-off setups.\n\n- [ ] **Required entities configured** (odometer, battery, vehicle_on, capacity, home zone)\n- [ ] **Charge binary sensor** wired so charges are auto-detected\n- [ ] **Power sensor** wired so regen / max_power / power-integration backup work\n- [ ] **Location tracker** wired so origin/destination + route map work\n- [ ] **`weather.*` entity** configured (unlocks season / temp / time-of-day buckets and the climate factor of the SoH model)\n- [ ] **Battery chemistry** set explicitly (`lfp` / `nmc` / `nca`)\n- [ ] **Vehicle first-registered date** set (raises SoH model confidence to `high`)\n- [ ] **Driver sensor** configured if multiple drivers (BT-connected device entity or input_select)\n- [ ] **Plug binary sensor** wired so multi-pulse charging sessions merge into one row\n- [ ] **Polling-paused sensor** wired if your manufacturer integration sleeps the cloud poll\n- [ ] **Outside temperature sensor** wired (separate from weather entity — this is the car's own probe)\n\n---\n\n## Reporting issues\n\nThe integration logs at INFO when it drops or repairs a trip, and emits a `_LOGGER.exception` when the expected-SoH model fails — so the stack lands in `system_log` directly. Enable debug for the namespace to see every state-machine decision:\n\n```yaml\nlogger:\n  default: info\n  logs:\n    custom_components.ev_trip_logger: debug\n```\n\nOpen issues at https://github.com/boraita/hass-ev-trip-logger/issues with the relevant log lines + a description.\n\n---\n\n## License\n\nMIT.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboraita%2Fhass-ev-trip-logger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fboraita%2Fhass-ev-trip-logger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboraita%2Fhass-ev-trip-logger/lists"}