-
-
Notifications
You must be signed in to change notification settings - Fork 1
Vehicles
The Vehicles page (/vehicles) shows battery level, charging status, and range for every car your household has configured via Home Assistant. It supports multiple vehicles — the dashboard widget rotates through them every 8 seconds. Two drivers ship out of the box: Tesla (for Tesla Fleet via HA) and Generic EV (for any car Home Assistant can reach via its own integrations, including VW We Connect, BMW Connected Drive, Polestar, Hyundai BlueLink, OBD2 dongles, and others).
If you were running Kinboard before v1.0.12, you had a /tesla page and a /settings/tesla settings page. Both now redirect (HTTP 308) to the new pages. No action is required on your part — your existing Tesla configuration was automatically migrated to the vehicles table by migration_vehicles.sql, which runs on stack startup. After the upgrade, visit /settings/vehicles and you should see your Tesla listed with its existing entity IDs intact.
The widget_visibility.tesla flag in your saved dashboard preferences is also auto-migrated at read time: if your blob has tesla: true and no vehicles key, the dashboard treats it as vehicles: true so the widget keeps appearing without you touching /settings/widgets.
- Go to
/settings/vehicles(or follow the link from the main Settings page under Integrations). - Tap Add vehicle.
- Choose a vehicle type (Tesla or Generic EV).
- Enter a nickname (e.g. "Model Y" or "Mia's e-tron").
- Pick an accent color — used to tint the vehicle's card on the dashboard.
- Tap Add vehicle to create the row, then configure entity IDs on the next screen.
You can add as many vehicles as you have Home Assistant entities for. The /vehicles page tabs through them, and the dashboard widget rotates automatically.
The Tesla driver reads vehicle data from Home Assistant's Tesla Fleet integration. Before adding a Tesla vehicle, make sure the Tesla Fleet integration is set up in Home Assistant and your vehicle's entities appear in the HA entity registry.
On the vehicle's settings page (/settings/vehicles/[id]), map the following entity IDs from your HA instance:
| Field | Example entity | Notes |
|---|---|---|
| Battery level | sensor.model_y_battery_level |
Percentage, 0–100 |
| Battery range | sensor.model_y_battery_range |
km or miles |
| Charging rate | sensor.model_y_charging_rate |
kW; used for charging indicator |
| Charging state | sensor.model_y_charging_state |
"charging" / "not_charging" |
| Charge limit | sensor.model_y_charge_limit |
% |
| Time to full charge | sensor.model_y_time_charge_complete |
minutes |
| Charger power | sensor.model_y_charger_power |
kW (fallback if charging_rate absent) |
| Charge energy added | sensor.model_y_charge_energy_added |
kWh, used for session cost calc |
| Inside temperature | sensor.model_y_inside_temperature |
optional |
| Outside temperature | sensor.model_y_outside_temperature |
optional |
| Climate state | climate.model_y |
optional |
| Locked | lock.model_y |
optional |
| Windows | binary_sensor.model_y_windows |
optional |
| Doors | binary_sensor.model_y_doors |
optional |
| Trunk | binary_sensor.model_y_trunk |
optional |
| Frunk | binary_sensor.model_y_frunk |
optional |
| Tire pressure FL/FR/RL/RR |
sensor.model_y_tire_pressure_front_left etc. |
optional; bar or psi auto-detected |
| Odometer | sensor.model_y_odometer |
optional |
| Location | device_tracker.model_y_location_tracker |
optional; home / not_home / work / school |
| State | sensor.model_y_state |
"online" / "asleep" / "driving" |
Only Battery level is required for the widget to render meaningfully. Everything else is optional and enhances the detail view on /vehicles.
The settings page has a live entity search — start typing the entity name or ID and matching entities appear in the dropdown. Tesla entities bubble to the top of the list automatically.
The Generic EV driver works with any vehicle that Home Assistant has an integration for. All it needs is five entity IDs:
| Field | Accepts | Notes |
|---|---|---|
| Battery level | Any sensor with device_class: battery or unit_of_measurement: %
|
Required for meaningful display |
| Charging state | Any sensor or binary_sensor
|
"charging" / any truthy value triggers the charging indicator |
| Range | Any sensor with distance unit |
km or miles |
| Location | Any device_tracker
|
Displays home / away / etc. |
| State | Any sensor
|
Online / offline / driving / etc. |
Home Assistant integrations that feed Generic EV well:
-
VW We Connect —
volkswagen_we_connect_idintegration (HACS or core) -
BMW Connected Drive —
bmw_connected_drivecore integration -
Polestar —
polestar_api(HACS) -
Hyundai / Kia —
hyundai_kia_connect(HACS) -
OBD2 dongles —
obdintegration exposes battery voltage; pair with a smart charger integration for charging state - Any EV with a custom integration — as long as it exposes a battery level sensor, Generic EV will display it
If your car's integration exposes more entities than the five slots (e.g. tire pressures, cabin temperature), you can use the Tesla driver instead and leave most fields blank — the Tesla driver renders gracefully when optional fields are absent.
If your car needs entity mappings or a UI that neither Tesla nor Generic EV handles well — say you want a polished Polestar-specific dashboard with frunk-state, charging-cable status, and pre-conditioning controls, all wired to HA's polestar_api integration — add a new driver. The pattern is "copy Tesla, change the field list."
- Use Generic EV if your car's HA integration exposes battery, charging state, range, location, and overall state, and you don't need a deeper UI than that. No code required — the existing Generic EV driver covers it.
- Add a new driver if your car has unique surfaces worth a vendor-specific layout (e.g. Polestar's pre-conditioning, BMW's Efficient Dynamics breakdown, VW's charging-cable lock state) — anything where five fields aren't enough and the Tesla driver's tire-pressure / lock / climate grid would be a forced fit.
All bundled drivers today read data from Home Assistant entities. The VehicleDriver contract doesn't require this — a driver's Card could call any hook, including ones that talk to a vendor API directly — but the supporting infrastructure for that (encrypted credential storage, OAuth flows per vendor, server-side polling for cars that aren't online when the dashboard is open) doesn't exist yet. For now, build HA-backed drivers. If you have a use-case that genuinely needs to bypass HA, open a discussion before writing code.
The Tesla driver at webapp/src/plugins/vehicles/drivers/tesla.tsx is the canonical reference. To add a new HA-backed driver — let's call it polestar — follow these six steps. Effort: 30–60 minutes for someone comfortable with the codebase, longer if you want a polished vendor-specific UI.
1. Add <vendor> to the vendor enum
In webapp/docker/migration_vehicles.sql, the vendor TEXT NOT NULL CHECK (vendor IN ('tesla', 'generic-ev')) constraint locks the allowed values. Postgres has no ADD CONSTRAINT IF NOT EXISTS for CHECKs, so a new vendor needs a separate idempotent migration. Create webapp/docker/migration_vehicle_vendor_<id>.sql:
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.constraint_column_usage
WHERE constraint_name = 'vehicles_vendor_polestar_check'
) THEN
ALTER TABLE public.vehicles DROP CONSTRAINT IF EXISTS vehicles_vendor_check;
ALTER TABLE public.vehicles
ADD CONSTRAINT vehicles_vendor_check
CHECK (vendor IN ('tesla', 'generic-ev', 'polestar'));
END IF;
END $$;Then update the TypeScript union in webapp/src/types/database.ts — find vendor: "tesla" | "generic-ev" (Row, Insert, Update — three places) and add | "polestar".
2. Define the config shape and driver in a new file
Create webapp/src/plugins/vehicles/drivers/polestar.tsx. Start by copy-pasting tesla.tsx into it. Rename:
-
TeslaConfiginterface →PolestarConfig - Keep only the fields your vendor's HA integration actually exposes; remove the Tesla-specific ones (frunk, tire pressures if Polestar doesn't expose them, etc.)
-
TeslaCardfunction →PolestarCard -
TeslaConfigFormfunction →PolestarConfigForm -
teslaDriverconst →polestarDriver, withid: "polestar",displayNameKey: "polestar", your icon (lucide-react has 1500+ — pick one that fits) -
isConfiguredpredicate — the simplest version is(c) => Boolean(c.battery_level)
Inside PolestarCard's render, customize the layout to highlight what makes Polestar different — maybe the pre-conditioning state gets its own card, charging-cable status replaces the trunk indicator, etc.
3. Wire up entity-selector field rows
In PolestarConfigForm, the existing <EntitySelector> rows from Tesla map directly to Polestar's HA entity names. The shared EntitySelector from @/components/home-assistant/entity-selector accepts a priorityPattern?: string prop — pass priorityPattern="polestar" so Polestar entities float to the top of every dropdown for users who have many integrations configured.
4. Register the driver
In webapp/src/plugins/vehicles/drivers/registry.ts, add the import and array entry:
import { polestarDriver } from "./polestar";
export const VEHICLE_DRIVERS: VehicleDriver<unknown>[] = [
teslaDriver as VehicleDriver<unknown>,
polestarDriver as VehicleDriver<unknown>,
genericEvDriver as VehicleDriver<unknown>,
];5. Add i18n keys
Both webapp/messages/en.json and webapp/messages/de.json need:
-
nav.polestarfor the dropdown label (if you decide to surface the brand in nav) -
vehicles.drivers.polestar.*for any per-driver strings the Card renders (haNotConnected,notConfigured, etc. — copy the same keys Tesla uses) -
settings.vehicles.driver.polestarfor the vendor-picker label -
settings.vehicles.driverDescription.polestarfor the picker description
The CI i18n bundles job fails the PR if any key is in EN but missing from DE — keep them symmetric. If you don't speak German, machine-translate as a starting point and flag in the PR description; a maintainer or DE-speaking reviewer will polish.
6. Test + open a PR
- Run
npm run lintandnpx tsc --noEmitfromwebapp/. Both must be clean (the four pre-existingnews/apitype errors are unrelated to vehicles work). - If you have Docker locally:
docker compose build webapp && docker compose up -d webapp, then visit/settings/vehicles/newand confirm Polestar appears in the vendor picker and the create-then-edit flow renders your config form. - Open a PR against
mainofgithub.com/svenger87/kinboard. Reference the HA integration your driver is built on (with a link). Include a screenshot of the new Card if your UI deviates meaningfully from Tesla's.
- Driver covers a real HA integration that's available to users (HACS or core; not a paywalled bespoke API)
- Code follows the copy-Tesla shape — no clever new abstractions invented just for one driver
- i18n parity holds (en/de must have the same keys)
- A short note in the PR explaining which Polestar HA integration you tested against
- MIT-compatible (no copy-paste from a vendor's proprietary SDK)
If you want to discuss the approach before writing code — say you're not sure whether your car's case warrants a driver or just better Generic-EV docs — open a GitHub Discussion first. Faster than writing code that bounces in review.
Kinboard on GitHub · Sponsor · Buy me a coffee · Report a bug · MIT-licensed
Getting started
Operations
Integrations
Kiosk hardware
Built-in features
- Dashboard
- Calendar
- Shopping
- Recipes & meal planning
- Tasks & todos
- Notes
- Birthdays
- School schedule
- Smart home & energy
- Screensaver
- Family members
- Devices
- Notifications
- Themes
Plugins (per-family on/off)
Contributing