Skip to content

Releases

v2.0.13

Choose a tag to compare

@github-actions github-actions released this 02 Nov 07:25
Immutable release. Only release title and notes can be modified.
8a8e81b

What's Changed

Full Changelog: v2.0.12...v2.0.13

v2.0.12

Choose a tag to compare

@github-actions github-actions released this 01 Nov 18:27
Immutable release. Only release title and notes can be modified.
794c12a

Large update with quite a few bug fixes as well as decoding alot of the data we recieved but didn't know what it contained

[2.0.12] - 2026-11-01

Added

  • decode the Polestar C3 per-period energy breakdown (driving, climate, battery, other), battery
    discharge power limit, manual preconditioning and cold-battery status, and climate warnings;
    show them in Battery Diagnostics and Needs Attention, and post a notice once per climate
    session when the run time is nearly used up or the battery is too low

  • show "Not reported by this vehicle" on the software card when the car does not report update
    status, instead of an unavailable badge

  • keep a local tyre-pressure history with a four-tyre chart and a possible-slow-leak hint, and a
    warning timeline that records when each warning first appeared and when a covering report
    cleared it

  • estimate the next service date from the last 30 days of driving, and hint at frost or a cold
    battery before a scheduled departure using an hourly Open-Meteo forecast fetched in the same
    request as current weather

  • offer Retry on a failed command when the failure proves it did not run, Undo on a reversible
    command for 30 seconds, and saved command routines that run steps in order and stop at the first
    failure

  • add opt-in notifications for a car left in convenience mode and a daily summary, plus Lock and
    Mute This Vehicle actions on vehicle alerts

  • add URL routes for cabin cleaning, windows, tailgate, trunk, charge-current limit, charging
    override, OTA and engine commands, through the same confirmation and capability checks

  • add VoiceOver actions to the menu bar item and an hour-and-price readout on the price curve

  • export a handover pack for selling the car: summary, charging and trip CSVs without locations,
    an optional VIN, and a checklist of the steps that happen in the manufacturer app or car

  • pace Polestar Data Portal polling so a day stays under 9,000 of the 10,000 daily calls, and show
    the projected count in Settings

  • name individual failed lamps under the exterior lighting row

  • document the recovered Polestar GetMyCars protobuf schema, with every tag of the app's own
    car_information classes, its enum tables and the verification against a captured frame, in
    docs/research/polestar-protobuf-field-decode.md

  • decode the Polestar GetMyCars lock, unlock, climatization and charge-timer enums and the gross
    vehicle weight rating, and gate remote locking, remote unlocking, preconditioning and saved
    charge locations on what the car reports instead of the model table

  • keep the tailgate control on cars whose unlock type is trunk-only, and explain a disabled
    Unlock on cars whose unlock type is none instead of promising an unlock that cannot happen

  • show the reported climatization type and maximum preconditioning runtime on the climate card
    instead of a fixed claim that fits every car

  • surface the per-location charge timer and departure-time limits from GetMyCars in the Info
    capabilities inspector under "Backend Control Settings"

  • show the reported gross vehicle weight on the Info specs card as well as the capabilities card
    and the factory passport export, localized in every supported language

  • claim plug and charge on the Info capabilities card only when the backend also sends the
    plug-and-charge identifier; the wire flag and the REST projection disagree on this car

  • name the vehicle type, front grille variant and model year groups of the Polestar
    visual_id string on the Info specs card, and keep the other groups positional until their
    code table is verified

  • show reported vehicle usage mode in Info connectivity details, including vehicles without
    separate network diagnostics

  • decode Polestar charging-status V2 and automatic-trip consumption from reconstructed
    descriptors, correct climate seat/wheel requests and normalize their heating levels

  • add opt-in read-only field research and anonymized idle/active capture regression fixtures

  • decode Polestar C3 vehicle usage mode, use range in miles when kilometre range is absent,
    and show separate manual-trip and automatic-trip energy totals in Battery Diagnostics

  • document accepted Polestar wire mappings and remaining evidence gaps in
    docs/research/POLESTAR_FIELDS.md and docs/research/polestar-live-decoding-2026-10-30.md

  • add THIRD_PARTY_NOTICES.md crediting Polaris, pypolestar and polestar_api, Sparkle,
    Open-Meteo and Elpriset just nu.se; the app bundle now carries it with LICENSE and
    Sparkle's own license

  • add regression coverage for privacy erasure, legacy migration failures, charging planner
    cancellation and vehicle switching, electricity price coverage, notifications and gestures

  • show whether scheduled charging will finish, including "cannot complete" and "smart charging
    will not finish", instead of collapsing every plan to "Scheduled"

  • add since-charge distance and average speed to the trip computer from the C3 odometer reading

  • compare measured tyre pressures with the car's reported reference pressures

  • explain why a climate session started or failed, including the reported error reasons

  • show "Update status not reported" on cars that do not advertise update status, instead of
    claiming that no update is available

  • offer windows, Charge Now / Resume Schedule and pre-cleaning from the menu-bar Quick Controls

  • erase cached car artwork from memory, disk and SQLite on sign-out and on "Erase local vehicle
    data"

  • estimate battery health from high-confidence charging sessions in addition to the 100% range
    reading, and show a fused value when both methods agree within tolerance instead of hiding
    a method conflict behind one number

  • keep the uncapped range-based health figure alongside the displayed value capped at 100%,
    so an understated WLTP reference stays visible instead of flattening to 100%

  • fit the health trend with a median-based slope that ignores a single bad range reading,
    and report the median of recent milestones as the stable figure

  • document every backend field Hisingen does not yet wire, with wire type, enum table, the
    live capture evidence behind it and the public cross-client sources, in
    docs/api/polestar-unwired-fields.md

  • decode the remaining named GetMyCars tags into the capabilities inspector: the reporting
    flags, notification matrix, end-of-ownership actions, account linking, parking assistance
    type, trip reporting, device pairing, bidirectional charging and the preconditioning
    duration appear as equipment rows and a new Backend Reporting disclosure, shrinking the raw
    "Unwired Backend Fields" list to Charging 35.43, the one field no client schema names

  • caption the climate card with the reported heater type and with whether the car heats seats
    and the steering wheel on its own in cold weather

  • read back the repeats-weekly flag on climate timers that Hisingen itself already writes,
    instead of inferring repetition only from the weekday list

  • retain unknown wire fields on the air-quality, charge-target and amp-limit reads as
    hidden-until-data rows, so a new backend field stays visible instead of being dropped

  • render retained raw binary fields as their decoded wire structure (for example
    "1: 1787835643") instead of a hex dump, so backend fields no client schema names stay
    readable until they are identified

Fixed

  • stop Polestar climate start and charge-level changes from failing with "The command may have
    reached the vehicle" when the car had answered: the backend keeps these streams open after
    replying, so the call deadline ended them, and a complete reply followed by that deadline was
    reported as an unknown outcome; it is now accepted, while a deadline inside a frame or before
    any reply still reports an unknown outcome
  • wait at most 15 seconds for a Polestar command to close instead of 60, and report a call
    deadline on the HTTP/2 connection as a deadline instead of a cancellation, which callers
    could mistake for the user cancelling
  • replace the Siri phrase value "undefined" in 14 locales and fail the localization check on any
    placeholder value
  • decode Volvo INITIALIZATION, POWER_AVAILABLE_BUT_NOT_ACTIVATED and
    OTA_INSTALLATION_IN_PROGRESS, read location speed, and stop fuel and engine-status reads for
    battery-electric Volvos
  • advance the database migration cursor after the v5 step, which left later migrations unreachable
  • stop a Data Portal health report without tyre fields from counting as a tyre all-clear
  • make sign-out stay signed out: an explicit per-brand flag now suppresses auto-restore
    from built-in developer credentials plus the lingering server-side grant, and relaunch
    no longer re-discovers the vehicle until an explicit save or sign-in clears it
  • clear all brand credentials on sign-out (email, portal IDs, Volvo custom app, VIN,
    Keychain items, memory cache) and invalidate the session cache, so deleting
    credentials and restarting does not auto-login
  • keep password and command grants across a cancelled or failed sign-in: authenticate
    and web authorization no longer wipe the warm session to open the window, and a
    dismissed login restores the prior session
  • scope dead-grant clearing to the grant the IdP refused: a dead web session no longer
    deletes the independent command grant, and password re-login preserves and re-verifies
    it instead of deleting it
  • discover OIDC before reporting command authorization state, persist a fresh command
    grant before verification and only discard it on definitive account mismatch, and
    require maximumAge: 600 on web callbacks
  • pair custom portal credentials (custom ID requires custom secret, no builtin mixing),
    remove the never-read portal token Keychain write, single-flight portal test grants,
    retry portal 401 once through the lifecycle with ...
Read more

v2.0.10

Choose a tag to compare

@github-actions github-actions released this 19 Oct 15:26

[2.0.10] - 2026-10-19

Added

  • add configurable electricity rates
  • add an Electricity section to Settings with a country choice (Sweden or other country);
    market-linked pricing and the Charging Planner are offered for Sweden, every other country
    uses the typed-in rate and the optional night tariff
  • add an Automatic electricity rate for Sweden that prices charging from the spot price for
    your zone (SE1 to SE4) plus your provider's markup, with optional tax and grid fee in
    öre/kWh and a VAT toggle, instead of a single typed-in price
  • choose the contract type for Automatic pricing: 15-minute price, as the market publishes
    it, or hourly price, which averages the four quarters in each hour
  • choose a Swedish electricity provider (Vattenfall, Fortum, E.ON, Tibber, Bixia, Greenely,
    Göteborg Energi, Skellefteå Kraft, Telge Energi, Jämtkraft, or other); the provider names
    the contract and carries no prices, because markups differ per agreement
  • show the current price your settings produce next to the Automatic controls, with
    fetching and unavailable states

Fixed

  • stop the repeated Keychain password prompts after rebuilding: make run now signs the debug
    binary with the app's identifier and team, so it has the same Keychain identity as the
    installed app instead of a code hash that changes on every build
  • skip writing a Keychain secret that has not changed, so an unchanged password, email or token
    no longer rewrites its item and its access list on every sign-in

Changed

  • charge costs follow the chosen rate everywhere: the charge-to-target estimate on the
    charging card, session costs, History totals, monthly and per-location breakdowns, cost
    per distance, and the CSV export; changing the markup re-prices past sessions that have a
    stored market cost, while sessions the market prices do not cover keep their saved cost
    or your fixed rate
  • move the electricity rate and night tariff out of Display, Units & Energy, and the
    Charging Planner out of Features, into the new Electricity section
  • the Charging Planner requires Sweden as well as its feature switch; choosing another
    country stops it and keeps its settings for when Sweden is selected again
  • test: make Volvo renewability setup deterministic
  • chore(updates): publish v2.0.6 appcast

v2.0.6

Choose a tag to compare

@github-actions github-actions released this 02 Oct 18:02

Full Changelog: v2.0.5...v2.0.6

v2.0.5

Choose a tag to compare

@github-actions github-actions released this 22 Sep 19:47

[2.0.5] - 2026-09-21

Added

  • Completely new deisgn
  • classify pending Keychain consent (errSecInteractionRequired) as its own, parked state
    with its own message, instead of reporting it as a failed sign-in or storage error
  • keep the first Keychain read of a launch off the main thread, so an unanswerable ACL
    approval can no longer hang the panel before it draws
  • show a one-sentence verdict of what the car is doing (charging with its finish time,
    climate running) at the top of the Vehicle instrument, built only from reported signals
  • offer Verify now on an acknowledged command receipt, which refreshes so the receipt can
    settle against a fresh vehicle reading
  • place the Smart Charging Planner on the Controls tab by default (feature- and
    powertrain-gated as on Vehicle; a rearranged Controls tab keeps its own layout and gains
    the planner through Tabs & Cards)
  • add a selected-trip detail line to the History overview's trip bars, pointer- and
    keyboard-reachable
  • state which credential served a refresh: a snapshot the consumer Polestar ID session
    delivered on the Developer Portal's behalf is labelled next to its age
  • drag card reordering as a real gesture: the dragged card tracks the pointer one-to-one
    from where the handle took hold, siblings part as it crosses them, and release settles
    it into its slot on the flick spring
  • lift unselected chips (garage, climate presets, charge presets, schedule days) under the
    pointer, so every clickable answers the pointer before the click
  • tick the pull-to-refresh control when a pull crosses its threshold; hysteresis below the
    line keeps a pull hovering at the edge from stuttering the haptic

Fixed

  • settle a tab swipe's page on the flick spring from wherever the drag left it, instead of
    snapping the offset back with no animation when the swipe lands where it started
  • give the floating charging panel's close button a 24pt target and press feedback; it was
    an 18pt plain-styled icon that answered no press
  • sweep the Info tab's refresh glyph forward on a cumulative angle instead of spinning it
    visibly in reverse when a refresh ended

Changed

  • stop the "Showing last-known values" banner from pinning forever: readings carried forward
    expire after seven days, so a domain the current provider can never serve (Developer
    Portal software and connectivity) ages out instead of holding the banner up indefinitely
  • validate the fuel fill-up form inline and state what is wrong per field; Save was
    previously a silent no-op on invalid input
  • draw no fake gauge on the Controls instrument map: the climate capsule filled a constant
    width and the charge blocks showed the target setting, not progress; the charge rail now
    fills only from real progress while actually charging
  • state both retention horizons with real numbers on the storage card
  • move the account card's decisions behind one model: connected, renewable and expired are
    classified from typed failure kinds instead of matched message text, and the credential
    draft lives with the sheet that edits it instead of a process-wide store, so typed
    secrets no longer outlive the Settings window
  • route every History surface through one workspace: dashboard loading, capacity, edits and
    exports reach the history ledgers through a single interface, and no panel view holds the
    database directly any more

Changed

  • localize the App Intents surface: titles, parameters and dialogs now have keys in every
    locale, AppShortcuts.strings exists for all sixteen languages (Swedish and German
    translated; other locales keep English entries where translation is still pending)
  • add Scripts/audit-l10n-literals.mjs with a committed baseline, so new user-facing
    strings cannot ship without an English key again; 322 pre-existing unkeyed literals are
    recorded there for retirement
  • settle the pull-to-refresh chip's collapse on the flick spring, the gesture-carried
    spring, rather than a fixed fade
  • roll the climate target temperature between steps like every other value on the panel

v2.0.4

Choose a tag to compare

@github-actions github-actions released this 18 Sep 21:57

Polestar finally released their offical API so moved a lot of the fethcing to that, which improves alot of features! You will need to get an client id and secret from your car from their portal:

https://data-portal.polestar.com/se/shared-access

[2.0.4] - 2026-09-18

Added

  • redesign the panel as a live instrument
  • surface consumer identity, truthful 404s and timer offsets
  • surface portal schedules, climate faults and charging estimates
  • unify polestar sign-in credential selection
  • display usage mode tire delta and trips
  • expand portal models and trip mapping
  • add eu data act telemetry and controls
  • add data portal fixtures and fix tests
  • expand Polestar Developer Portal support
  • add account id header and live portal tests
  • add polestar developer portal provider

Fixed

  • harden snapshot merging and command confirmation
  • add force-login path for polestar command sign-in
  • make polestar augmented session and fallback resilient
  • fix charger status and expand v2 states
  • rethrow primary error on fallback fail
  • support augmented mode in session resume
  • fix steering heat default and departure
  • clean duplicate tooltip and add a11y hint
  • refine control sizes and tab drag metadata
  • mark updater delegate methods nonisolated
  • synchronize climate button gate with command
  • default wire temperature to 22C for auto climate

Changed

  • test: create the renders directory the data-portal render refreshes
  • docs: add AGENTS.md and DESIGN.md
  • chore(l10n): add portal wiring strings to all locales
  • docs(docs): update polestar developer portal url
  • docs(changelog): update polestar data portal notes
  • test(tests): add polestar 2 e2e test and sendable fixes
  • test(tests): update decode verification target
  • docs(docs): update 2.0.3 changelog with climate fix

[2.0.3] - 2026-09-17

Added

  • Polestar Developer Portal (EU Data Act M2M) integration. Dedicated machine-to-machine integration using credentials from the official Polestar Data Portal (data-portal.polestar.com).
    • Two-tier primary with fallback architecture: PolestarDataPortalAPI serves as the primary data provider for all 15 vehicle endpoints (battery, charging, odometer, location, exterior, health, climate, and pre-cleaning), with automatic transparent failover to consumer Polestar ID credentials upon rate limiting (HTTP 429), token expiration, or upstream outages.
    • Augmented dual-stack mode: Combines official EU Data Act high-precision telemetry with consumer Polestar ID remote actuation commands for door locks (lock, unlock) and visual alerts (flashLights).
    • Isolated credential management: Developer credentials (Account ID, Client ID, Client Secret, OAuth Bearer tokens) are isolated in separate Keychain storage from consumer Polestar ID credentials, enabling seamless switching between connection modes without credential conflicts or session invalidation.
    • Live connection testing & vehicle linking guidance: Dedicated "Test Connection" button verifies token issuance and vehicle discovery, guiding users when an account is authenticated but pending VIN linking in the portal.
    • Daily quota tracking: Built-in tracking for the portal's 10,000 requests/day quota with UTC calendar rollover and live meter display in Settings.
    • Official OpenAPI 3.1.0 specification & documentation: Bundled complete OpenAPI schema and step-by-step onboarding guide (docs/api/polestar-developer-portal.md) with co-located portal screenshots for landing, API credentials overview, and M2M key management.
    • Build-time secret injection tooling: Scripts/inject-secrets.sh obfuscates developer credentials and compiles fallback accessors in BuiltinPolestarSecrets.
  • EU Data Act telemetry and smart energy expansion. Complete integration of all telemetry fields and remote charging management capabilities from the official Polestar OpenAPI 3.1.0 specification:
    • Battery & Smart Energy:
      • Bidirectional / V2X power sharing monitoring (isBidirectionalChargingEnabled) with vehicle-enforced minimumSoc discharge thresholds.
      • Dynamic spot-price optimization indicators (isOptimizedChargingEnabled, availableOptimizedCharging).
      • Milestone charging duration estimates for departure readiness (estimatedChargingTimeMinutesToMinimumSoc) and target distance (estimatedChargingTimeMinutesToTargetDistance).
      • Cold-weather battery discharge limits (dischargeInfo.powerLimit, energyAvailable, and energyAvailableIncrease restored once warm).
      • DC fast-charge preconditioning tracking (manualPreconditioning running status, countdown timer, and unavailability reason).
      • 3-way drive cycle energy breakdowns (driving, climate, battery conditioning, other) across automatic drive, since last charge, and manual trip meters.
      • "Charge Now" remote override status and schedule resumption (/charging/charge-now and /charging/override-charge-timer).
    • Climate & Air Quality:
      • Multi-zone seat heating status across all 4 seating positions (requestedFrontLeftSeat, requestedFrontRightSeat, requestedRearLeftSeat, requestedRearRightSeat) and steering wheel heating.
      • Live cabin thermal delta tracking comparing interior compartment temperature against requested setpoint with active ventilation mode.
      • Precision PM2.5 particulate air quality gauge (measuredParticulateMatter25 in µg/m³) with air cleaning cycle completion and validity tracking.
    • Diagnostics & Vehicle Health:
      • 38-point precision exterior lighting inspector mapping all lamp failure warnings in lightWarnings into vehicle health details.
      • Factory recommended tyre reference pressure comparison (frontTyresReferencePressureKpa, rearTyresReferencePressureKpa) displaying exact pressure deviations.
      • 12V low-voltage auxiliary battery warning tracking (lowVoltageBatteryWarning).
      • Service countdown tracking for operating hours, days, and distance (engineHoursToService, daysToService, distanceToServiceKm).
    • Trip Computers & Navigation:
      • Sub-kilometer high-precision odometer (odometerMeters).
      • Triple trip computers (manual, automatic, and since last charge) with corresponding average speeds.
      • Altimeter elevation (altitude), ground speed (speed), and compass heading (heading).
    • Closures & Geofencing:
      • Charge flap open warning (exterior.tankLid), sunroof closure state (exterior.sunroof), and vehicle alarm state (exterior.alarm).
      • Recognized charging location presence and dwell tracking (is-at-charge-location, locationId, arrivedAtTimestamp).
      • Vehicle operational usage mode tracking (availability.usageMode).
    • Direct M2M Remote Actuation:
      • Direct REST API actuation for climate (startClimate, stopClimate), cabin air purification (startPreCleaning, stopPreCleaning), target state of charge (setChargeTarget), current limits (setAmpLimit), schedule override (startChargingOverride, stopChargingOverride), charging schedules (setGlobalChargeTimer), departure timers (setClimateTimer, deleteClimateTimer), and saved charge locations (createChargeLocationAtCar, updateChargeLocationAlias, updateChargeLocationAmpLimit, updateChargeLocationMinimumSoc, setChargeLocationOptimisedCharging, deleteChargeLocation).

Fixed

  • Polestar 2 remote climate actuation. When starting preconditioning on Polestar 2 (where cabin temperature is vehicle-managed), the remote command now explicitly provides the 22.0 °C comfort default on the wire. Omitting the temperature field previously caused the vehicle's climate control module (CCM) to quietly drop the command, leaving the cabin unconditioned while optimistic UI state masked the refusal.
  • Climate card button gating & overlay synchronization. The Start Climate button's disabled state and in-flight spinner overlay now track the actual command being dispatched rather than the probe command, keeping the button interactive and showing clear in-flight progress.
  • Sparkle updater Swift 6 concurrency. Conformed UpdateService to SPUStandardUserDriverDelegate with nonisolated delegate methods to prevent protocol isolation errors under Swift 6 strict concurrency.
  • Web sign-in window teardown. Cleaned up WKWebView and window references upon dismissal to prevent retained views during re-authentication.

Changed

  • chore(updates): publish v2.0.2 appcast
  • test: serialize the suite at every gate, not just ci.yml

v2.0.2

Choose a tag to compare

@github-actions github-actions released this 16 Sep 13:06

V2.0.1 wasn't released due to some CI issues, so baked both changes into this one

[2.0.2] - 2026-09-16

Added

  • Polestar 3 and Polestar 4 owners see their own car in the doors and tyres cards. Both
    drew the Polestar 2 outline, so the panels, windows, wheels and lamps lit up wherever a
    Polestar 2 has them — the wrong car, and further off the more the two differ. Each model
    now carries its own silhouette and its own geometry read off that artwork: the doors,
    windows, hood, tailgate and charge flap follow its own panel lines, the glass roof its own
    roofline, and the tyre rings and lamp glows sit on its own wheels and lights. The three
    outlines are drawn at a matched size, so switching cars no longer changes how large the
    car is in the card. Polestar 1, 2, 5 and 6 and every Volvo keep the outline they had.
  • Tabs & Cards: every card is now the reader's to place. A new Settings pane
    (Settings → Tabs & Cards) lists every card, section and banner in the app, per tab,
    and lets each one be switched off, moved — by button or by dragging it onto another
    card — or removed. The order the pane shows is the order the tab draws, and the
    shipped tabs read the same layout record, so what Settings shows is what the panel
    draws.
  • Tabs of your own. Build a tab from anything in Hisingen: name it, pick an icon,
    and add cards from any of the shipped tabs — the charging card beside the lock
    controls, the render beside the tyre schematic. Cards are drawn by the same views
    the shipped tabs use, so a card behaves and looks the same wherever it is placed.
    Cards that own a tab's own state (the History charts, the Info section bars) stay on
    the tab that gives them that state, and are named as such instead of silently
    missing.
  • Shipped tabs can be hidden. Any of Vehicle, Info, History and Controls can be
    hidden from the tab bar; Settings is always there, because it is where the list is
    managed.
  • Card switches double as data switches. A card's own setting is a feature the
    provider fetch already consulted, so switching a card off is also the instruction to
    stop requesting the telemetry behind it — but only once no card the reader can still
    see needs that reading, and never for a reading they switched on by hand. Switching a
    card back on resumes the fetch, and the app is told the feature selection moved rather
    than guessing.
  • An installation that predates this reads its existing feature toggles once as its
    starting layout, so a card that was already switched off does not reappear. From
    then on the layout is the reader's, and the feature list no longer moves cards.
  • A card shown while its reading is switched off is labelled Data off in the pane
    with the reason, instead of drawing empty with no explanation.
  • A tab emptied on purpose stays empty. "Hide All" switches the cards off where they
    live rather than discarding the arrangement, so "Show All" is one click away and a
    tab you arranged yourself never has cards reappear in it that you did not put there.
    A tab you have never rearranged does keep receiving cards added in later versions.

Fixed

  • Cards no longer render as a black field in dark mode. A card was filled with the canvas
    — the panel's own colour — so in a dark appearance the cards, the panel and the desktop
    behind them composited into one near-black surface, and only a hairline said where a card
    ended. A card is a raised surface now: lifted toward white in the dark and off the tinted
    canvas in the light, with the chip fill inset from it in turn. The contrast check models the
    card surface it actually renders on rather than the canvas it used to sit on, and covers
    both appearances for every theme.
  • The footer gear no longer kicks the panel back to another tab. Settings was reachable
    two ways at once — a controller-owned mode and a tab — and the two could disagree: with the
    Settings tab already selected, tapping the gear flipped the mode off and the panel fell back
    to whichever tab was stored behind it. Settings is one tab now, and every route to it (the
    tab, the gear, ⌘,, the menu-bar item, a sign-in that ends inside Settings) writes that one
    selection, so the two cannot disagree. Backing out returns to the tab Settings was opened
    over.
  • Settings draws the same header navigation as every other tab again. The Settings
    screen replaced the panel's tab bar with a header of its own — a back button, a centred
    title and a close button — so the one navigation a reader had learned disappeared the
    moment they opened Settings. Settings is a tab like the others now: the tab bar stays on
    screen and marks the current tab exactly as it does everywhere else. Settings keeps its
    own header only before sign-in, where there is no tab bar to leave by.
  • The card list in Settings → Tabs & Cards no longer appears twice. The card rows were
    rendered once by the tab's controls and again by the page below them.
  • A rejected password no longer replays on every launch. With a password saved, Hisingen
    offered it again at each launch even after the sign-in service had refused it, because the
    "can resume" flag counted any stored password as a way in. A credential the IdP actually
    rejects is dropped now, so the app asks instead of repeating a failed sign-in against
    PingFederate's per-client attempt budget. A transient refusal — a 5xx, a timeout — still
    keeps the session, so an outage never costs you a sign-in.
  • A restriction learned on one car no longer switches off the same reading on another.
    Volvo stand-downs were recorded under the endpoint alone, so a vehicle that answered
    "region restricted" for, say, the environment reading made Hisingen skip that reading on
    every other car in the garage for the rest of the stand-down. It is scoped to the vehicle
    that earned it now.
  • One slow vehicle service no longer holds up the whole refresh. The PCCS readings are
    optional, and a hung one was allowed the full ten-second session budget before giving up;
    they now give up at six, and that service stands down instead of every other reading
    waiting on it.
  • The C3 discovery fallback is no longer recorded as a failure. Every launch wrote one
    error for a request that then succeeded: the version-shape rejection that makes Hisingen
    fall back is the fallback working, not a fault. It is classified as expected now, so a
    support export shows the failures that actually matter.

Changed

  • Authorizing remote commands no longer leaves a browser tab behind. The sign-in for
    remote commands now runs in a system browser sheet that dismisses itself the moment the
    grant is issued, instead of opening a tab you had to close yourself. It is the same
    Polestar sign-in page, still loaded outside Hisingen, so the app never sees the Polestar
    ID password, and it shares the browser session you already have — which is why a sign-in
    you have already completed finishes in a blink. Declining the sheet is not treated as a
    failure, and if the sheet cannot be presented at all Hisingen falls back to opening the
    page in your own browser as before.
  • Settings is one entry point again. The Settings tab in the tab bar and the gear
    in the footer now take the same path into Settings and the same path back out, so
    neither can leave the panel in a state the other cannot leave.
  • The section row inside Settings reads like the tab bar. The destinations
    (All, Accounts, Appearance, …) wore accent-filled pills of their own; they now use the
    tab bar's icon-and-label treatment, its ink emphasis and the same indicator moving under
    the current section, so the two navigation rows speak one language. The row still
    scrolls, so no section label is truncated at the narrowest panel width.
  • Switching a card off releases its reading only when nothing else you can see needs
    it, and a reading you switched on yourself in Settings → Features is never taken
    away by moving a card. When a card's reading is released, Hisingen tells the rest of
    the app the feature selection moved, so notifications, update checks, the charging
    planner and the live stream re-configure instead of running against a selection that
    no longer exists.
  • The Vehicle tab's two side-by-side rows follow the layout: hiding or moving one of a
    pair no longer leaves a card trying to share a row with something that is not there.
  • Diagnostics name the failure rather than the code. A non-zero gRPC status now keeps
    its status and the server's own message next to a stable operation name, the token
    endpoint's OAuth error code is recorded without retaining the response body, a request
    that never reached the server is marked as a transport failure instead of a missing
    status, and older entries report where their version is unknown. Existing archives still
    load, and the export carries a schema version.

[2.0.1] - 2026-09-13

Added

  • First-run setup pass. The first successful sign-in now opens a one-time
    "Set up Hisingen" pass instead of dropping the user straight onto the dashboard.
    It offers two quick-setup presets, Enable All Safe Features (recommended) and
    Enable Remote Controls (with an explicit confirmation spelling out what remote
    features can change), plus the one-time Polestar remote-command browser
    authorization, reachable from the same screen. Everything it touches can be
    changed later in Settings → Features. Completing (or skipping) the pass is
    remembered; the flag deliberately stays out of the settings archive, so an
    archive restored on a new Mac is a first run there and sees the pass. An install
    that upgrades with session material already on the Keychain counts as past the
    pass, and a popover closed mid-pass reopens onto it inst...
Read more

v2.0.0

Choose a tag to compare

@github-actions github-actions released this 12 Sep 09:38
7e3f047

[2.0.0] - 2026-09-12

Version 2.0 changes what a remote command means: Hisingen no longer takes the
provider's "accepted" at face value — it waits until fresh vehicle telemetry proves
the requested outcome before calling a command confirmed. The old spot-price
recommendation is reworked into an opt-in Smart Charging Planner, the battery-health
estimate is replaced by one auditable calculation, the vehicle state model is
reorganized into named clusters, and two provider integrations that never worked in
practice are gone.

Also whole architecture has been revamped to be cleaner and easier to work with etc

Added

  • Smart Charging Planner (opt-in feature, replaces the old spot-price card). It
    fetches Swedish day-ahead spot prices (elprisetjustnu.se, zones SE1 Luleå – SE4
    Malmö) and shows the cheapest contiguous whole-hour window that covers the energy
    still needed between the current battery level and the set charge limit, with the
    window's average price, the price of charging right now, and the estimated saving.
    The planner works with both hourly and quarterly price series, always recommends
    whole hours, and hides itself entirely once the battery is at the limit.
    • Prices are fetched once a day any time after 14:15 Stockholm time (when tomorrow's
      file is published), covering today plus tomorrow. The series persists in the SQLite
      database, so a relaunch mid-day serves from disk without touching the network;
      concurrent requests share one fetch, and a late publication is retried a bounded
      number of times during the evening instead of waiting a full day.
    • New Settings card picks the price zone (defaults to SE3, so a first run is one tap
      away) and the charger output used to turn missing energy into whole charging hours
      (1–250 kW, default 7.4 kW). While the car is charging, the live rate is used
      instead. When the vehicle reports a GPS position, Settings suggests the
      approximate zone from its latitude — a one-tap "Use" hint, never an automatic
      assignment.
    • The card tells "tomorrow's prices arrive after 14:15" apart from "this charge is
      longer than the whole price outlook" instead of showing a generic failure, and a
      48-hour price outlook chart shades each interval by cost with the planned window
      highlighted. A footnote shows when prices were fetched, and a hint appears when
      the car carries its own charging schedules the planner does not use.
    • Needed energy includes an estimated AC charging-loss factor, so recommended hours
      and cost figures reflect grid-side energy — what the meter actually sees.
    • Optional notifications: one banner per planned window (from 15 minutes before it
      opens until it ends, respecting quiet hours, with a "plug in" variant when the
      car is unplugged), and an opt-in daily banner when tomorrow's prices arrive,
      including the cheapest hour.
    • Auto-start (separate explicit consent). When enabled, Hisingen sends the same
      start-charging command as the Controls tab while the planned window runs — only
      when the vehicle is plugged in, not already charging, and below its charge limit,
      and only while the Charging Controls feature is on. Auto-start is not part of any
      bulk-enable action and never transfers through a settings archive.
  • Market-price session costs. Completed charging sessions are priced against the
    actual spot price of every interval they covered (charging power integrated across
    price slots, split at rate boundaries, scaled to the session's authoritative energy),
    backfilled after each daily price fetch, and shown as "Market Price Cost" on the
    session row next to the tariff estimate. Sessions outside the price coverage stay
    uncosted rather than being priced with invented rates; spot prices exclude taxes and
    grid fees, and the database migrates legacy installs to the new column on first
    launch.
  • Climate commands confirm from telemetry. Start/Stop Climate receipts are
    confirmed when a fresh climate-status reading shows the requested state, and hidden
    once confirmed because the climate activity itself is the durable confirmation.
  • Acknowledged — a new receipt outcome for providers without telemetry proof. When
    a provider accepts a command but exposes no reading that could verify it (currently
    Volvo's climate status), the receipt finishes as acknowledged by the vehicle
    service
    rather than silently polling until timeout.
  • Nothing the Polestar backend sends is silently dropped. Every GetMyCars wire
    field Hisingen has not decoded — top-level or nested (shown as "Field 35.5") — is
    retained raw and listed under a new "Undecoded Backend Fields" disclosure in the
    capability inspector, mirroring what the battery parser already did. The same
    retention now covers the climate-status fields Hisingen reads but has not decoded
    (surfaced in the same disclosure on the Interior & Cabin card) and the
    availability frame's timestamp plus its undecoded field, retained on the identity
    snapshot.
  • Factory content codes (paint, wheels, trim groups) are decoded from the GetMyCars
    content-code string and shown in the equipment details and Factory Passport.
  • Climate sessions now carry their real start and end times (wire fields 14 and 16);
    a running session shows "Session Started" and "Cycle Ends" rows on the Specs card.
  • Air-quality readings carry when the cabin air was last measured (wire field 2,
    verified live: the sensor also samples on vehicle wakes, not only during
    purification), shown as an "Observed" row and distinct from the frame report time.
  • Charging sessions carry their market-price cost. Every recorded session is
    priced against the hourly spot-price series for the configured zone: recorded
    charging power is integrated per interval and priced at that interval's rate, then
    scaled to the session's own energy figure. Sessions are priced by a backfill pass
    once price coverage reaches them — historical day files are fetched lazily,
    bounded to the seven most recent uncovered days — and a session the price series
    does not fully cover stays uncosted rather than being priced with invented rates.
    The session detail shows "Spot Cost" as a clearly-labelled estimate next to the
    flat-tariff "Estimated Cost", and the session summary prefers the spot figure.

Changed

  • The command-receipt system was rebuilt end to end.
    • RefreshCoordinator is the single owner of every receipt's lifecycle from
      awaiting through acknowledged, confirmed, or timed out. Confirmation is
      state-driven: a 2-second first check, then a 3-second targeted poll or stream —
      exact cadence, no jitter — for at most five minutes.
    • Only provider-authored state is persisted, entered into history, indexed for
      Spotlight, or used as notification evidence. Optimistic command values now live in
      a separate display projection that is rebuilt on every refresh and cleared on
      relaunch, instead of being patched into the stored snapshot.
    • Receipts freeze their target: the VIN and provider captured at approval stay fixed
      until the command finishes, even if the visible vehicle selection changes, and a
      dispatch for another vehicle is stored under that VIN rather than leaking into the
      active one.
    • Opposing commands share a conflict group, so sending Stop Climate supersedes a
      pending Start Climate (and likewise for locks, windows, tailgate, pre-cleaning,
      charge target, and more) instead of leaving two receipts racing each other.
    • Multiple commands in flight keep independent receipts with their own deadlines,
      dismissal, and relaunch behavior. Receipts are stored per VIN, survive relaunch
      without resending, resume their remaining confirmation window, and are restored as
      timed out when the deadline passed while the app was closed.
    • Confirmation selections bypass the normal 15–90 second capability caches, which
      otherwise kept answering confirmation polls with the pre-command value.
    • Diagnostic exports include every receipt's state, audit correlation IDs are
      written through to the SQLite command log, and the unified log records each
      lifecycle step.
  • Shortcuts, deep links, and menu-bar actions target vehicles directly. A command
    from Shortcuts or a hisingen:// link resolves and prepares its named vehicle
    through one awaited boundary (up to 30 seconds) instead of a racy select-then-send,
    and reports "Command accepted; waiting for the vehicle to report the result"
    instead of claiming the outcome. The menu-bar lock and resume-schedule actions send
    against their own vehicle without switching the selection.
  • Calendar preconditioning awaits the dispatch outcome. A deferred command (for
    example, no session yet) leaves the occurrence scheduled for retry instead of being
    consumed, and a refused one is consumed with the reason recorded.
  • Notifications no longer react to command echoes. The optimistic display
    projection cannot advance transition baselines or post alerts, a pending Start
    Climate cannot trigger a stray "Climate stopped", and a climate stop now requires
    two consecutive vehicle-timestamped readings before notifying.
  • Battery state of health is one auditable number: the vehicle-reported range at
    100% charge divided by the configured WLTP range. Hisingen remembers the result and
    updates it only after another 100% reading. The multi-signal weighted estimate and
    its smoothing are gone. Range estimation needs to be in Standard and not dynamic in car for this to be as close to accurate as possible
  • The vehicle state snapshot is organized into named clusters — identity, energy
    and charging, exterior, health, and snapshot freshness — with the vocabulary
    documented in the glossary, replaci...
Read more

v1.3.5

Choose a tag to compare

@github-actions github-actions released this 10 Sep 05:04

Quite a few changes and updates as I'm trying to get the CI works as I like. Also fixed that when starting fan etc the UX didn't update

[1.3.5] - 2026-09-10

Changed

  • chore: checkpoint current work before vehicle state refactor
  • chore(updates): publish v1.3.4 appcast

Fixed

  • run auto release on macOS
  • only apply skip release to HEAD commit
  • pass the tag explicitly to the publish action [skip release]
  • keep the Sparkle private key file in its native base64 format [skip release]
  • Remote controls re-render again after a successful command: the coordinator
    extraction had dropped the optimistic state patch, so the fan animation, Start/Stop
    Climate button, lock icon, and charge-target slider kept showing the pre-command
    state until a later telemetry refresh carried the car's answer. A successful command
    now patches the visible state immediately and holds it against stale telemetry for
    90 seconds via optimisticCommandLockUntil, which the merge logic already honored.
  • The restored patch corrects two quirks the pre-refactor code had: a trunk-only
    unlock no longer claims the car is centrally unlocked, and pre-cleaning updates the
    air-cleaning reading its button displays instead of synthesizing a climatization
    session (which surfaced a "Stop Climate" button that did not target pre-cleaning).
  • Chronos error-service authorization failures now enter capability backoff instead
    of being cached as empty results and retried every five minutes.
  • Network tests now inject an in-memory API diagnostic store instead of clearing and
    writing fixture traffic to the user's persisted diagnostic archive.

Full Changelog: v1.3.4...v1.3.5

v1.3.4

Choose a tag to compare

@github-actions github-actions released this 09 Sep 21:48

[1.3.4] - 2026-09-09

Fixed

  • CI documentation-link validation: the glossary's ADR-0012 target is committed, and
    the docs checker now catches files that exist locally but were never committed
    before they can break the CI job.
  • The vehicle connection layer is more stable and makes fewer requests: one persistent
    stream per vehicle instead of separate connections per reading, reconnects happen
    only when the server closes the stream or the session actually expires, and
    background telemetry polls less often.

Changed

  • Vehicle history persistence deepened behind ChargingSessionLedger and
    VehicleHistoryLedger.
  • Remote Command dispatch is unified: the Controls tab, hisingen:// deep links, and
    Shortcuts intents cross one awaited dispatch authority with brand policy in the
    capability gate (ADR-0012). Deep-link remote commands now work on Polestar, and
    Shortcuts intents return the awaited provider outcome instead of polling.

Added

  • make ci mirrors every CI job locally (workflows, scripts, localization, docs
    links, build, tests, bundle and DMG validation), so a sync cannot fail on checks
    that only run on GitHub.
  • Local Developer ID builds are notarized and stapled automatically when notarization
    credentials are configured, and make notarize staples an existing build.
  • Releases cut themselves: after a green CI run on main the patch version bumps, a
    changelog entry is generated from commit history, and the release workflow is
    dispatched automatically. [skip release] in a commit message opts out.