Reused one of your capabilities and added more translations, remove ps2 - #6
Open
kaohlive wants to merge 93 commits into
Open
Reused one of your capabilities and added more translations, remove ps2#6kaohlive wants to merge 93 commits into
kaohlive wants to merge 93 commits into
Conversation
Contributor
Author
|
Here is a new pull request, it cleans up the vehicle driver and adds translations for NL in your driver. |
Contributor
Author
|
@Coderaxx can you merge this request please? |
Contributor
Author
|
@Coderaxx hey, I added support for the new feature of showing the charing KW and amps to the vehicle driver. Very nice that it is now available. |
Changelog: Added support for charge speed details
Changelog: Changed polestar vehicle to new device class car
Changelog: Fix for trigger events
Changelog: hotfix on the csv driver
Changelog: Improved insights on power measurements
Changelog: update to fix api changes
Changelog: Update npm modules
Changelog: Widget, service warning and login bug fix
Changelog: preview images
Changelog: fix widget update on device state change
Wire the C3 chronos services (ChargeNow, TargetSoc, AmpLimit) through the
JS client so users can actually control their car from Homey, not just
read status. Adds flow action + condition cards and in-tile sliders for
charge limit and amp limit plus momentary Start/Stop charging buttons.
Device setting "Allow remote commands" is a master-switch kill-flag —
writes fail instantly when turned off. Replaces an earlier PIN prototype
that produced ugly titleFormatted strings.
Device setting "Charge limit slot" (Daily/LongTrip/Custom/Unspecified)
is exposed because Polestar 4 silently rejects writes to the Daily slot
but commits to Custom — and we don't yet know which slot other models
prefer. Default stays on Daily to match the Python reference; Polestar 4
users switch once. Writes that don't land surface a log warning pointing
at this setting.
gRPC reliability: HTTP/2 keep-alive ping every 30 s, goaway-event handler
that nulls the session eagerly, and one automatic retry on transient
errors (INTERNAL/UNAVAILABLE/GOAWAY/ECONNRESET/ETIMEDOUT) with a fresh
session. Resolves the cold-session GOAWAY hit we saw on the first write
after idle.
UNIMPLEMENTED responses are now captured in a persistent device-store
flag so unsupported features (e.g. Polestar 4 returns "Functionality not
supported: AMP_LIMIT") hide the slider tile and skip further calls on
subsequent runs instead of spamming the log forever.
Charge limit polling moved to the fast 60 s cycle (down from 15 min) so
changes made in the Polestar app or in-car menu show up within a minute.
Amp limit stays on the slow 15 min cycle — it rarely changes and is
skipped entirely on vehicles that don't support it.
Set-response parsing no longer trusts the echoed level: the P4 chronos
envelope returns a stale value, so we rely on a delayed Get 3 s after
the write to reflect the committed state. The slider stays on the
user-chosen value until that re-read either confirms or corrects it,
avoiding the disorienting snap-back-then-forward UX.
The custom measure_polestarTyrePressure{FL,FR,RL,RR} capabilities are
also migrated to measure_pressure.{front_left,front_right,rear_left,
rear_right} with a kPa unit override — the standard capability gets
better UI + Insights integration. Legacy JSON files remain with a
_deprecated marker so existing devices can migrate via removeCapability;
they will be deleted in a future release.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire two more C3 services so the car's external closures and parking
climatization show up as Homey tiles:
ExteriorService/GetLatestExterior — locks, per-door/window open state,
hood, tailgate, sunroof, charging-port cover
ParkingClimatizationService/GetLatestParkingClimatization — running
state, target temperature, interior temperature, minutes remaining
Both are unary calls on the 60 s fast cycle so a user walking up to the
car sees door-opened alarms within the minute.
Homey capabilities chosen so they can be switched to setable later
without a rename, once lock/unlock + climate start/stop writes land:
locked — central lock state (setable:false for now)
onoff.climate — climatization running/not (setable:false)
target_temperature — last requested temp (setable:false)
measure_temperature — interior temperature (inherently read-only)
measure_polestarClimateRemaining — minutes left on the 30-min parking
climatization session; blank when idle
alarm_contact.door_{fl,fr,rl,rr} — per-door open alarms
alarm_contact.window_any — aggregate window-open alarm
alarm_contact.{tailgate,hood,sunroof,tank_lid} — body + charge port
open alarms
The capabilitiesOptions setable:false overrides keep the tiles visible
as read-only indicators. When writes arrive they just drop the override
and register listeners.
DigitalTwin flat-field format was reverse-engineered against a live
Polestar 4 session: exterior fields 2-16 hold ints (LockStatus enum on
2/16, OpenStatus 1/2/3 on all others), climate fields 2,3,7,8 are the
ones we trust (running_status, time_remaining in minutes, current and
requested temperature as float32). ventilation_only and request_type
are still speculative per-model so they stay in debug logs only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Complete the invocation surface so every write Polestar's mobile app
offers is available from Homey flows and device tiles, plus a couple
of reads that round out the picture.
Writes (via /invocation.InvocationService):
lock / unlock — wired to the setable `locked` tile
unlock_trunk — tile button + flow action
honk_flash — tile button (flash-only default) +
flow action with HONK/FLASH/BOTH
climate_start / climate_stop — onoff.climate toggle reads seat and
steering-wheel heating defaults from
new device settings; a separate flow
action exposes all 6 params per-call
for one-off custom sessions
windows_open / windows_close — flow actions (OPEN_ALL / CLOSE_ALL —
the API doesn't support per-window)
Reads:
Location (/dtlinternet.DtlInternetService/GetLastKnownLocation) —
parser handles three documented response layouts, populates a
measure_polestarLocation string tile on the 15-min slow cycle.
A get_location flow action refreshes on-demand and exposes
latitude, longitude, and a formatted "lat, lng" string as tokens
for downstream cards (push notifications with a map link).
OTA (/ota_mobcache.OtaDiscoveryService/GetSoftwareInfo) —
alarm_polestarOtaAvailable fires on DOWNLOAD_READY /
DOWNLOAD_COMPLETED / INSTALLATION_DEFERRED / INSTALLATION_SCHEDULED.
State text falls back to a friendly "No pending update" when the
car returns an empty CarSoftwareInfo (no update queued).
Write side (schedule/install/cancel) deliberately omitted — the
risk of a misconfigured flow triggering an install mid-drive
outweighs the convenience over the Polestar app.
Flow cards:
11 action cards (charge ±, limits, lock ±, trunk, honk, climate ±,
windows ±, get_location)
3 conditions (is_locked, target_soc_is, amp_limit_is)
1 condition trigger (is_locked) + standard triggers from button.*,
locked, onoff.climate capabilities.
Housekeeping:
The four legacy measure_polestarTyrePressure{FL,FR,RL,RR} JSONs are
removed — they never shipped in a release and the migration loop
that would auto-remove them from existing devices is gone too, since
no one has those capabilities in their device state. All current and
future users take the standard measure_pressure.* sub-IDs directly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps to 3.0.0 and wraps up the C3-migration work.
- Mark the legacy polestar-2-csv driver as deprecated via Homey's
official driver flag so new pairings are rejected but existing
devices keep working. The Car Stats Viewer webhook still supplies
live telemetry the C3 backend doesn't expose (speed, gear,
ignition, battery temperature, trip summaries) so it stays around
for P2 owners who rely on it.
- Rewrite README.md with real feature list and deprecation note,
rewrite README.txt (app-store listing) with concrete read/write
capabilities and a privacy section, and refresh the
.homeycompose/app.json description + tags to reflect what the
app actually does now instead of generic marketing copy.
- Drop the `measure_power: { approximated: true }` override. The
new C3 client returns real power_watts from the car, not a
calculated estimate, so Homey Energy can treat it as a real
sensor reading.
- Add a `windows_supported` device setting and wire it into the
same OPTIONAL_FEATURES machinery that already auto-hides
amp_limit on Polestar 4. Unchecking hides the two window
buttons; the backend auto-disables the feature when it returns
UNIMPLEMENTED.
- Make `target_temperature` fall back to the configured climate
default when the C3 climatization response has no
requested_temp (happens whenever climate isn't running). Tile
no longer stays empty on a fresh device.
- After every state-changing write (lock, climate, windows,
charging, trunk) schedule two follow-up reads at +3 s and +10 s
so the UI reflects the actual state faster than the 60 s regular
poll cycle. Window opens/closes use a wider +15 s second refresh
because physical movement takes longer to complete.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Point every custom capability used by the active vehicle driver at an SVG in drivers/vehicle/assets/ so the driver stops depending on files that live in the deprecated polestar-2-csv driver's folder. Copies battery-75, battery-100, powerdc, hvbattery, location and update from the CSV driver into the vehicle driver's own asset folder. Add tire-pressure.svg and wire it to alarm_polestarTyrePressure — Homey threw a render error on the iconless alarm tile. Fill in the two remaining missing icons (alarm_polestarOtaAvailable, measure_polestarOtaVersion) with update.svg so all three OTA capabilities share the same glyph. CSV-only capabilities (speed, gear, ignition, temperature, etc.) keep pointing at their own driver's assets — they live together and will move as a set when that driver is eventually removed. Adds a 3.0.0 changelog entry. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Changelog: Polish on icons etc
Polls kept firing after a device was removed or while the app was restarting, so each in-flight updateVehicleState() eventually hit setCapabilityValue on a device Homey had already forgotten about — surfacing as 'Not Found: Device with ID …' in the app log. Adds a _cleanup() that clearIntervals both poll timers and closes the gRPC session, invoked from onDeleted() and onUninit(). Every update method (vehicle, health, exterior, climate, location, ota) and the post-write _scheduleStateRefresh closures now early-return when _destroyed is set, so in-flight promises can't race past the cleanup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- CHARGING_STATUS_DONE now surfaces as 'plugged_in' instead of 'plugged_in_paused'. A completed session is not a pause — the Polestar app shows "Finished" for this state, and users were getting "Paused" on their Homey tile. - Honk/flash flow card retitled to "Find my car — [action]". The previous titleFormatted was just the action value, making the card hard to identify in a flow list. - Added a 'Start climate (defaults)' flow action that takes no arguments and reads temperature + seat/steering heating from device settings. Mirrors the one-tap climate behaviour of the Polestar mobile app; complements the existing argument-driven climate_start action for custom sessions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Car Stats Viewer Android app sometimes pushes driving points with no altitude or state-of-charge field (GPS dropout, sensor delay). trip-ended trigger then crashed on undefined.toFixed(0). Replaces the bare .toFixed() calls with a fmt() helper that checks Number.isFinite first and falls back to the existing "Unavailable" localization. energy_delta accumulator also now defaults a missing field to 0 so a single bad point can't NaN the whole sum. Touches only the deprecated CSV driver; the new vehicle driver is unaffected. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two issues spotted in a tester's pair-flow log.
- The settings-changed listener was logging user_email and
user_password values verbatim. Even though the password is
encrypted-at-rest, dropping the ciphertext in a debug log is the
kind of thing that ends up in a screenshot. Now we log only
'[N chars]' or '[empty]' for user_email, user_password, and
polestar_token.
- testlogin returned a plain boolean, so the pair UI couldn't tell
the difference between 'login failed' and 'login OK but the
account has no vehicles'. Both paths showed the same red
'Login validation failed' alert, which confused at least one
tester whose login was actually fine. testlogin now returns
{ ok, reason } so the HTML can show a specific 'no vehicles'
message that points at account selection or a transient backend
hiccup as likely causes. Old boolean return is still accepted
by the pair view as a fallback.
While in the area, fixes a small bug where a 'Credential test ok'
log line referenced `vehicles` before its var was declared.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mark_Beech (self-hosted Homey) hit an unhandledRejection during
pairing because his network interfaces are not named wlan0/eth0/eth1
— the salt derivation in lib/homeycrypt.js fell off the if-else chain
with mac=null and crashed on null.join('').
Adds a fallback that iterates os.networkInterfaces() and picks the
first non-internal interface with a non-zero MAC, sorted by name so
the same interface keeps being chosen across reboots. Preserves the
preferred wlan0/eth0/eth1 order so existing users' encrypted
passwords still decrypt with the same MAC they were salted with.
If no usable MAC can be found at all (extremely rare, would only
happen in a stripped-down container), throws an explicit error
instead of the cryptic null.join crash.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Translations: added de, fr, it, sv, es, da, ru, pl, ko, ja to every capability title/unit, driver name, driver capabilitiesOptions, flow cards (titles, hints, titleFormatted, dropdown labels, tokens), and device settings (labels, hints, dropdown values). Source en/no/nl strings preserved verbatim. AI-generated — non-elegant phrasing can be reported and fixed in follow-ups. Widget: the charging block now mirrors the orange-label / white-value pattern of charge and range. Power (kW) is the primary number; current and time-remaining form a subtitle. Numbers gracefully fall back to "— kW" / omitted parts when capability values are missing, instead of showing "0 A | 0 kW · 0h 0m". Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The legacy Car Stats Viewer driver stored a webhook_slug only when the deprecated trip-image API was used. Newer pairings leave it null, but the trip-ended handler still ran `base64url.encode(this.slug)` as the first step. That throws ERR_INVALID_ARG_TYPE on null and aborts the trigger before any flow ever fires. The encoded slug fed only image URLs that are now fully commented out, so the line is removed entirely along with its commented-out block. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3.2.2 left the lastTrip/tripInfo/tripScore image tokens in the flow definition (removing them would break user flows referencing those tokens) but the trigger payload no longer supplied them, so every trip-ended event threw "Invalid value for token lastTrip. Expected object but got undefined". Create three Homey images on device init, all pointing at the driver brand asset. The token payload is schema-valid again; existing flows keep firing. Per-trip renders are gone with the deprecated backend, so notifications now show the Polestar driver image instead. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The auto-generated alarm_contact flow cards render as "{title} is open" /
"{title} is not open". With the previous titles ending in "open" ("Door
FL open", "Raam open", "Laadklep open") the card text read awkwardly
("Door FL open is open") or the UI dropped the redundant suffix, leaving
several "is open" cards in a flow indistinguishable from each other.
Renamed all nine alarm_contact sub-capabilities to a sensor noun only —
e.g. "Front-left door", "Side window", "Charge port lid" — so the auto-
generated cards read naturally and identify the sensor in the flow
editor. Applied across all 13 languages. Doors switched from FL/FR/RL/RR
abbreviations to fully-spelled positions for legibility in the flow
card library.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Homey's auto-generated alarm_contact triggers all show "Contact alarm turned on for [Duration]" in the card library without any sub-cap discriminator, making the nine alarm_contact triggers visually identical in the picker. Renaming the capability titles in 3.2.4 fixed the device tile but did not help here — the auto-card title comes from the base capability text. Add three explicit Polestar-owned flow cards instead: - contact_opened (trigger) - contact_closed (trigger) - contact_is_open (condition) Each carries a dropdown that lists the nine alarm_contact sub-caps with their localized sensor labels (all 13 languages). titleFormatted renders e.g. "Front-left door opened" once the user picks the sensor. Wiring: _setContact() in device.js wraps setCapabilityValue, detects false→true / true→false transitions, and fires the matching trigger with state.sensor = sub-cap id. The driver registers run-listeners that gate by args.sensor === state.sensor. The auto-generated Contact alarm cards still exist (we can't hide them without breaking existing flows that already use them) but users are now nudged toward the unambiguous explicit cards. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
A 2021 Polestar 2 owner reported "no car found" during pairing. Logs showed C3 login succeeded but getVehicles() returned an empty list — the new C3 backend doesn't list every older P2. The c3_backend_disabled escape hatch exists but the user has no way to discover it from the pair dialog, only by spelunking through app settings. testlogin (pair + repair) now silently retries with the legacy backend when C3 returns 0 vehicles. If legacy finds vehicles, c3_backend_disabled is persisted so all later discovery / refresh / write calls go through the legacy client too. Only when both backends return empty does the "no_vehicles" friendly error reach the UI. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
A user reporting "no vehicles found" sent a log with the line: "Credential test ok, vehicle count:" ending mid-sentence. Cause: app.log uses `if (data)` to decide whether to append the data argument, so 0 / false / '' silently fall through to the no-data branch. We logged the right call but the count never made it to disk. Switched to a nullish check (data !== null && data !== undefined). Also guarded the `data.message` access so a non-object/non-error data value no longer throws. Next time we ask a user for a log, "vehicle count: 0" will actually say 0 instead of leaving us guessing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace GraphQL GetVDMSCars vehicle discovery with the C3 gRPC GetMyCars service. Discovery now uses the same session / auth / retry machinery as every other C3 call and drops the pc-api.polestar.com app-backend dependency (with its versioned user-agent and apollo headers). New GetMyCars response fields userIsLinked and userIsOwner are surfaced on each vehicle for future diagnostics. Includes the first fixture-based test under test/ — hex-encoded GetMyCars proto response for a linked non-owner Polestar 3, verified via node:test. Tested by olemarkus on a non-owner Polestar 3.
Follow-up to olemarkus' PR #3. Two small additions on top of the merge: 1. package.json: "test" script runs the new fixture suite via `node --test test/*.test.js`. Future PRs can drop a hex proto response in test/ and get regression coverage for free. 2. driver.js discover_vehicles: log `linked:<y/n> owner:<y/n>` per vehicle at pair time. Non-owner accounts (lease, secondhand without ownership transfer) can now pair thanks to the C3 GetMyCars endpoint, but we don't yet know which features — if any — require owner rights. Logging the state so we can correlate any feature-availability reports later. No user-facing message for now; only add one once we see actual missing capabilities. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
--- 'Car at home' feature ---
New boolean capability measure_polestarAtHome that flips true whenever
the vehicle's last-known location is within a configurable radius of
Homey's own geolocation. Default radius 150 m; adjustable 25–2000 m
via a new device setting home_radius_m.
Three explicit flow cards (custom capabilities don't get auto-generated
ones — corrected from my earlier assumption in the interim commit):
- Trigger "Car came home" — fires on false→true transition
- Trigger "Car left home" — fires on true→false transition
- Condition "Car is / is not at home" — invertable via the !{{is|is not}}
tokens so the same card serves both semantics
Wiring: _evaluateAtHome() runs at the end of every successful location
refresh, reads Homey's lat/lng via the geolocation manager (new
`homey:manager:geolocation` permission), Haversines the distance, and
fires the appropriate trigger card on transition. Only fires if the
previous capability value was a boolean, so the first-ever set at boot
does not spuriously trigger "Car came home". If Homey has no usable
geolocation (permission missing / manual mode with no fix) the eval
skips silently rather than pinning the tile to false.
Titles + hints + settings label/hint translated across all 13 languages.
fixCapabilities() adds the new cap to existing paired devices.
--- Location refresh diagnostics ---
A user reported their location tile stopped updating after pair. Their
log covered 30 minutes / two slow-cycles but contained zero location-
related lines, because updateLocationState was silent on every non-
throw path. Added a "Retrieve vehicle location" start marker (mirrors
updateHealthState), distinct DEBUG lines for null-result vs. non-
finite-coords early returns (with raw payload for the latter),
UNIMPLEMENTED handling, and a success line. Next log we get will tell
us which of the four cases applies.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Audited every boolean capability in the app against the flow cards in
driver.flow.compose.json. Five caps had gaps that made obvious "when X
happens" / "if X is true" flows impossible to build. This commit fills
them all in — 6 new triggers + 5 new conditions, 13 languages each.
Filled gaps:
- alarm_polestarOtaAvailable: no trigger, no condition
→ 'New software update available' / 'Software update no longer
pending' triggers + 'Software update is/is not available' condition.
- alarm_polestarTyrePressure: no trigger, no condition
→ 'Tyre pressure warning raised' / 'cleared' triggers + condition.
- onoff.climate (sub-cap, no auto-gen per SDK): no trigger, no condition
→ 'Climate started' / 'Climate stopped' triggers + condition.
- measure_vehicleChargeState: had triggers, no condition
→ 'Car is/is not charging' condition.
- measure_vehicleConnected: had triggers, no condition
→ 'Car is/is not connected to a charger' condition.
Wiring: new _setBoolAndTrigger(capId, val, trueKey, falseKey) helper in
device.js wraps setCapabilityValue and fires the matching device-trigger
card on real boolean transitions (skips when the previous value was not
yet a boolean, so device boot doesn't spuriously fire "climate started").
updateOtaState, updateHealthState (tyre pressure), and updateClimateState
now call this helper instead of raw setCapabilityValue. driver.js holds
refs to the six new trigger cards + registers five bool-reading condition
run-listeners with a small shared closure.
All condition titles use !{{is|is not}} tokens so users can invert them
in the flow editor without extra cards.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two housekeeping changes prompted by PR #4 review. 1. Removed the @andysmithfal/polestar.js entry from dependencies. The legacy client has always loaded from the local kaohlive/polestar.js fork under clone_modules/polestar.js — the npm package sat in the tree unused. Its presence made two identically-named, differently- patched copies look interchangeable, which triggered PR #4. Added LEGACY_CLIENT_FORK_NOTES.md at the repo root documenting exactly what our fork changes vs upstream 1.8.0 (CarTelematicsV2 migration, GraphQL error surfacing, getAccessToken/getVehicleVin helpers) so the next contributor doesn't need to diff to find out. 2. Security bumps. axios floor raised to ^1.7.4 (installed 1.18.1) to cover CVE-2024-39338 (SSRF). qs and ws direct deps refreshed via npm audit fix to patched versions (qs 6.15.3, ws 8.21.1). Four moderate CVEs remain in transitive deps of homey-api (parseuri, engine.io-client, socket.io-client) — all in the AthomCloudAPI OAuth path used only by the deprecated Car Stats Viewer driver and, within that, only the REST portion, not the socket.io real-time transport where the vulnerabilities live. Will clear when Athom bumps their transport stack. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ev_charging_state (cars) and evcharger_charging_state (chargers) are the same five values in homey-lib, so a car and the charger it is plugged into should report the same value for the same physical moment. Checked against the Tesla car app, the Tesla Wall Connector, Easee and SolarEdge; three mappings disagreed with all of them: - SMART_CHARGING reported plugged_in_paused while power was flowing. - DISCHARGING reported plugged_in, discarding plugged_in_discharging even though C3 reports the state explicitly. - UNSPECIFIED and any unrecognised status reported plugged_out with the connector still in — the one value consumers act on as "nothing here". Two coupled defects shared a root cause: "is it charging?" was derived twice. The energy accrual gate compared the raw status against CHARGING_STATUS_CHARGING, so smart-charging sessions accrued no meter_power or session kWh at all, and the switch set measure_vehicleChargeState per-branch, letting it contradict ev_charging_state within a poll. Resolve the plug state once per poll in a pure lib module and let the accrual gate, measure_vehicleChargeState, measure_vehicleConnected and ev_charging_state all read it. Connection status now wins outright, so the device can no longer report plugged_in_charging alongside measure_vehicleConnected=false. Also drops dead code: CHARGING_STATUS_FAULT is a ChargerConnectionStatus value, never a ChargingStatus, so its case and set entry were unreachable; and the unconditional plugged_out pre-set was always overwritten by the switch, firing ev_charging_state_changed twice per poll where the two disagreed. ERROR stays at plugged_in: chargers report plugged_out on a fault, but both car apps keep it at plugged_in because the car knows its own cable is still in. Charging and smart charging remain distinct statuses that happen to share a plug state — isSmartCharging() keeps that axis addressable. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Merges PRs #6, #8 and #9 from olemarkus, plus the parts of #1 (kvolden) and #5 (olemarkus) worth keeping. ev_charging_state (#9) — "is it charging?" was derived twice, and the energy accrual gate only recognised CHARGING_STATUS_CHARGING, so smart charging sessions accrued no meter_power or session kWh at all. Plug state now resolves once per poll in lib/evChargingState.js and every consumer reads it. Also maps V2L/V2G to plugged_in_discharging and fails toward plugged_in on an unrecognised status. Pairing (#8) — vehicles without a registrationNo paired as "Polestar 3 (null)"; they now use the bare model name. Submodule (#6) — adds the .gitmodules entry for clone_modules/polestar.js pointing at our own fork (kaohlive/polestar.js @ 75dcf9a, verified to match the committed gitlink), so fresh clones can initialise it. measure_polestarBattery — declared deprecated rather than removed, which is what #5 proposed. No longer added to newly paired vehicles, still fed on existing ones: removeCapability would drop their Insights history and break tiles and widgets already pointing at it. The capability definition stays regardless — polestar-2-csv still uses it. Took #5's widget fix, so the dashboard reads measure_battery and works on new devices too. Norwegian (#1) — cherry-picked the native-speaker wording over our current strings; the rest of that PR had been overtaken by the locale expansion since May 2025. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The dashboard widget keyed on the registration number, which the Polestar
API treats as optional — cars that report none (notably some Polestar 3
accounts) were unaddressable, and getVehicleStatus threw Vehicle Not Found
for them. The registration is also mutable in a way a VIN is not: import,
re-registration or new plates would orphan a configured widget.
The VIN was already the device identity (pairing sets id and data.vin);
the widget simply never used it.
The identity is decided in app.js, not in the widget API: the settings
picker is served by the autocomplete listener registered there, and Homey
stores the entry it returns verbatim. That listener returned
{name, registration}, so a widget's settings could never contain a VIN no
matter what the widget API offered. It now returns the VIN as well.
Resolution order is VIN first, registration second. The fallback is
permanent — a widget cannot rewrite its own settings, so widgets already
configured out there hold only a registration and would otherwise have to
be set up again by hand.
Both keys are validated as non-empty strings before matching. Without
that, an absent key matches a car whose registration is null, which would
bind the widget to whichever car happens to lack a plate.
Also drops an unguarded `devices[0].getData().registration` debug line
that would throw on an account with no paired vehicles, and logged a plate
on every keystroke in the picker. getVehicles in the widget API returns an
explicit {id, vin, registration, name} shape rather than raw Device
instances, and now says in a comment that it is not what feeds the picker.
Verified on a real Homey: an existing widget keeps working untouched, and
re-picking the car stores name|vin|registration.
Rides along with 3.3.0, which is pushed but not yet published.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.