Repository navigation
Releases: joszz/GarageStack
Releases · joszz/GarageStack
Release list
v0.13.1
Upgrade Notes
- SAIC gateway 0.14.0-rc1.
docker-compose.ymland the all-in-one image now run the gateway's0.14.0-rc1release candidate. Its payloads are unchanged and it only adds topics. Its new opt-in cached status read (CACHED_STATUS_INTERVAL, off by default) is not used by GarageStack (#533)
Bug Fixes
- Joining trips asks in a dialog. On phones the armed Tap again to join label pushed a trip's map, hide and join buttons onto a row of their own. The join button now opens a confirmation dialog (Cancel / Join trips) and keeps its icon-only look (#532)
Security
- certifi and anyio come from the gateway itself. Gateway 0.14.0-rc1 ships certifi 2026.10.23 and anyio 4.15.1, so the all-in-one image no longer patches them into the gateway's environment (#533)
Dependencies
Full Changelog
v0.13.0...v0.13.1: v0.13.0...v0.13.1
v0.13.0
Upgrade Notes
- Database migrations run on start:
AddRdwLookups,DropRawTopic,AddCommutePlaceNotifyandAddTripIsHidden. Dropping the telemetry's raw topic column is instant in PostgreSQL. Its space comes back gradually, or at once withVACUUM FULL "TelemetrySnapshots";(#518, #519, #521) GET /api/vehicles/{vin}/topicsis removed. This undocumented diagnostic endpoint was the only reader of the raw topic column, which stored the MG account's email address in every telemetry row (#519)- New variables for the Dutch registration lookup:
RDW_ENABLED(defaultfalse),RDW_REFRESH_HOURS(default24) andRDW_APP_TOKEN(optional). Nothing changes until you switch it on (#518) - Home Assistant through a Mosquitto bridge: add
topic garagestack/# in 0to the bridge so GarageStack's own sensors reach Home Assistant. A broker GarageStack talks to directly needs nothing (#521) ForwardedHeaders__TrustedProxies__*now accepts ranges such as172.18.0.0/16. Behind a reverse proxy on a Docker network, list the network as a range so the frontend container stays trusted when it gets a new address. Entries GarageStack cannot read, and forwarded headers from a proxy it does not trust, are now logged (#526)
Features
- Dutch registration lookup (RDW). For a car with a Dutch plate, GarageStack shows what the RDW has on record: when the APK runs out, open recalls with their risk and repair, and whether the car has WAM insurance. It adds a dashboard card, a licence plate field in Settings, and notifications for open recalls, the APK 30 and 7 days ahead, an expired APK and missing insurance. It is off by default, and the plate is the only thing that leaves your network. No API key is needed (#518)
- Arrival and departure alerts. Home or work can notify you when the car arrives or leaves (Notify on arrival and departure). Warming the car up at home sends nothing (#521)
- Hide a trip, or join two. Hide a trip caused by a positioning glitch: it drops out of the map, the statistics, the dashboard and the trip log's totals and export, and stays listed under Show hidden trips. Join with next trip joins two trips that a short stop, such as a fuel station, split in two (#521)
- Show a trip from the trip log on the map. Each trip has a Show on map button that opens the map with that trip selected and framed. A trip older than the map's period is shown with the rest of its day (#529)
- APK, recalls, next maintenance and last trip in Home Assistant and the Homepage widget. Home Assistant picks them up over MQTT discovery on the car's existing device (#521)
- The OpenAPI document is served in every deployment at
/api/openapi/v1.json, to signed-in users and read-only tokens (#521) - More home screen shortcuts. Long-pressing the installed app now offers Trip log, Climate schedules, Maintenance and Logs alongside Map and Statistics (#530)
- Compact trip format for the map.
GET .../trips?format=compactsends trips as an encoded polyline, about half the size. The map uses it. The plain format stays the default, so scripts reading/tripsare not affected (#522)
Bug Fixes
- Live data after a reconnect. Telemetry pushed while the live connection was down now shows once it reconnects (#519)
- Unknown addresses in the app now redirect to the dashboard instead of showing an empty page (#519)
- Moved-while-parked warning no longer goes off for a GPS fix that strays from a garage, a multi-storey or between tall buildings: the margin is now 1.5 km instead of 300 m (#523)
- OIDC behind a reverse proxy on a Docker network. With only the host's address in
TrustedProxies, the API ignored the proxy'shttps, sent anhttp://redirect URI and the identity provider refused it. See Upgrade Notes for the range syntax that fixes this (#526) - Push notification icon on Android shows as a car silhouette instead of a solid square (#525)
- Pale car paints and the road on the overview. A white or silver car now stands out on the light card, and the road shown while driving looks like asphalt with lane markings (#528)
- Map selection on a cold load. A selected trip stays drawn on its own and framed, however the trips and the map load, and its row is brought into view in the sidebar. Whether the speed key is open or folded is now remembered on each device (#529)
- Trip log on phones is less crowded: the route reads from and to, one under the other, and the notes share a row with icon-only map, hide and join buttons (#531)
- Quieter Worker logs. Home Assistant discovery no longer logs a line, and writes to the database, for every entity the gateway announces. A database restart now logs the first failure in full, a warning every 5 minutes while it lasts, and one line on recovery, instead of a stack trace every 15 seconds (#524)
Security
- certifi 2026.10.19 in the all-in-one image (critical, GHSA-6q48-6c7w-9gw2). The SAIC gateway ships certifi 2026.2.25, whose CA bundle still trusts emSign roots with compromised intermediate CA keys. The image now upgrades it in the gateway's environment (#531)
- The MG account's email address is no longer stored in every telemetry row. It was part of the raw MQTT topic, which is now dropped (#519)
Performance
- Lighter dashboard. The tyre and level history dialogs, and Chart.js with them (about 67 KB gzipped), load on their first tap instead of on every dashboard visit (#519)
- Faster telemetry writes. Merging an MQTT message into its row sends one
UPDATEof just the fields the message carried, without reading the row first (#520) - Faster statistics. Finished days are kept in memory, so opening the statistics again reads today rather than the whole period (#520)
- Prebuilt compression. The frontend and all-in-one nginx configs share one server block and serve files gzipped at build time, at the highest level, instead of compressing each response (#520)
- Outside services back off as long as their
Retry-Afterasks: Nominatim, Valhalla, Overpass, Open Charge Map and the RDW (#519)
Documentation
- README: a contents list, a "What leaves your network" table, and sections for the RDW lookup, climate schedules and maintenance (#518, #519, #521)
- Every screenshot was retaken, Climate schedules was added, and
pnpm screenshotsretakes them from a demo stack (#521) - How the all-in-one image moves to a new PostgreSQL major version (#521)
- CONFIGURATION.md: listing the frontend container in
TrustedProxies, and giving a Docker network as a range (#526)
Internal
- Repository tests against a real PostgreSQL in CI, and specs for the dashboard, statistics, trip log and map views and the map layers (#522)
- One shared send path for the outside-service clients (#520)
- CodeQL action steps bumped together, as one Dependabot group (#513)
Dependencies
- .NET packages (ASP.NET Core, EF Core, Microsoft.Extensions) 10.0.12 to 10.0.13, and dotnet-ef 10.0.12 to 10.0.13 (#516)
- certifi 2026.2.25 to 2026.10.19 in the SAIC gateway's environment in the all-in-one image (#531)
- pinia 4.0.3 to 4.1.0 (#514)
- flag-icons 7.5.0 to 7.6.0 (#517)
- Development and CI only: vitest 5.0.3 to 5.0.5, jsdom 30.1.2 to 30.1.3, @playwright/test 1.64.0 to 1.64.1, eslint-plugin-oxlint 1.87.0 to 1.88.0, Microsoft.NET.Test.Sdk 18.10.1 to 18.11.0, github/codeql-action 4.38.3 to 4.39.0 (#506, #507, #508, #510, #512, #513, #515)
Full Changelog
v0.12.3...v0.13.0: v0.12.3...v0.13.0
v0.12.3
Performance
- Smaller all-in-one image: 530 to 415 MB. It no longer carries Perl, the
localespackage, the second Python (3.13) that Debian's supervisor package pulled in, curl or gosu; none of them was used. supervisord now comes from PyPI and runs on the image's own Python, and the health check is a small Python script.psqlandpg_dumpstill work from a shell in the container. If you added your own commands inside the container, such as a health check that callscurl, use/http-check.py <url>orpython3instead (#503) - Smaller frontend image: 73 to 23 MB. It is built on
nginx:alpine-slim: the same nginx without the optional modules GarageStack never loaded (njs, XSLT, GeoIP, image filter, ACME) and the libraries they pulled in, libexpat among them (#503) - Slightly smaller API and Worker images. Both use
setprivfrom the base image instead of gosu to drop to their non-root user, and the Worker no longer installs the unusedprocps(#503)
Dependencies
- supervisord 4.2.5 (Debian package) to 4.3.0 (PyPI, hash-pinned and kept current by Dependabot) in the all-in-one image (#503)
Full Changelog
v0.12.2...v0.12.3: v0.12.2...v0.12.3
v0.12.2
Bug Fixes
- The mobile menu closes on a link to the page you are on. Tapping the GarageStack brand on the dashboard, or the entry of the page already open (Map while on Map), left the drawer open. Any link in the drawer now closes it; its buttons (notifications, demo controls, sign out) still leave it open (#500)
- SAIC gateway 0.13.0-rc5 (rc4, rc5). The gateway's scheduled charging job runs again (it failed since the move to aiomqtt), pending MQTT messages are sent before it shuts down, and Home Assistant shows the gateway's release tag as its version. The gateway now exits when its MQTT connection ends; Compose and the all-in-one image restart it, so nothing has to be done. It is still a release candidate (#502)
Security
- libexpat 2.9.0 in the frontend image (CVE-2026-77214, high; CVE-2026-102633, medium). The
garagestack-frontendimage shipped libexpat 2.8.5 from Alpine 3.24, and the fixed package reached Alpine only after v0.12.1 was built. This release's images include it
Performance
- The log viewer pages through the whole history. The Logs page loads 50 entries at a time and fetches the next page as you scroll, back through every retained log file instead of only the last 8 MB of each service. Live mode reads only what was written since the last poll: with the Error filter on a 100 MB log a poll took 234 ms and 212 MB of allocations, now 0.1 ms.
GET /api/logsgainsolderandnewercursors to pass back asbeforeandafter; the existing fields and the default limit are unchanged (#501)
Dependencies
- SAIC gateway 0.13.0-rc3 to 0.13.0-rc5 (#502)
Full Changelog
v0.12.1...v0.12.2: v0.12.1...v0.12.2
v0.12.1
Features
- Fuel and battery history from the dashboard. The fuel and battery badges on the car diagram now open a dialog, as the tyre pressures already did. It shows the level now and the range it is good for (on a car that plugs in also the charger state, the remaining charge time, the charge target and when the last charge ended and at what level), the daily average over the last 30 days, and the trip computer's usage per day: fuel on a plain hybrid, kWh on a car that plugs in (#498)
Bug Fixes
- Footer on narrow phones. Below 480 px the copyright wrapped over two or three lines and the update notice's icon ran into the Refresh button; in Dutch it overlapped it. The footer buttons show only their icons there now, and screen readers still announce their names (#499)
Full Changelog
v0.12.0...v0.12.1: v0.12.0...v0.12.1
v0.12.0
Upgrade Notes
- The SAIC gateway moves to 0.13.0-rc3, a release candidate (its release notes). The all-in-one image ships it, and Compose pulls it on
git pullanddocker compose up -d --build. Nothing has to be done. What changes: a car only goes offline after three failed polls in a row instead of one, Home Assistant's charging sensors go unavailable while the car's charge data is stale, the charging cable lock is no longer reported on models that do not report it (such as the ZS EV; GarageStack hides the row within a week, once the old reading drops out), and stopping the container no longer ends in a forced kill after 10 seconds (#496) - Read-only API tokens no longer reach the export and the logs.
GET /api/exportandGET /api/logsnow answer403 token.sessionOnlyto a token; sign in to use them (#489) - Behind a reverse proxy with no trusted proxies configured, sign-ins are capped at 30 per 5 minutes per proxy address, shared by everyone behind that proxy. This stops a device on your network from forging
X-Forwarded-Forto dodge the login limit. SetForwardedHeaders__TrustedProxies__0and__1to the frontend container and your proxy to keep per-visitor limits only; that also switches the cap off (#489) - The Unraid template now really prefills
AUTH_COOKIE_SECUREwithauto, which the v0.11.0 notes already claimed, and its overview lists the newer features. An existing container keeps its value: set it toautoif you reach GarageStack over HTTPS (#489, #494) - Outside Docker only: the Worker's
appsettings.jsonno longer carries the Docker connection string and broker host as a fallback. SetConnectionStrings__DefaultConnection, as the API already needed; the broker host defaults tolocalhost. The API's CORS default is now the documentedhttp://localhost:8080(#494) - No database migrations in this release
Features
- A real light theme. The light theme used to recolour nine tokens and leave the rest dark-on-white. Status text (Online, Trip in progress, tyre callouts, the charge pill, alerts, badges) went from about 2.2:1 to 5:1 contrast. Fields and secondary buttons are white with a border instead of grey slabs, switch knobs are white, buttons darken on hover, and the phone drawer no longer leaves a grey band along the edge. Charts follow the theme, including on a switch without a reload, and a light page no longer flashes dark while loading. Sliders, trip rows, tyre labels and info buttons get a visible focus ring. Dark mode is pixel-identical apart from the badges below (#490)
Bug Fixes
- Readable badges in dark mode. White text sat on bright green, cyan and red at 2.3 to 3.8:1. Badges are now a tint of their colour with the colour as text (about 5:1 or better), and the solid green Live button, online toast and edit-mode badge get dark text (#491)
- Escape closes one layer at a time, the newest first, instead of the mobile menu and the notification panel together (#492)
- No slow-puncture alarm after a partial top-up. Topping up three tyres left the fourth behind the others, which read as a leak; a tyre now also has to have lost pressure itself. The tyre dialog and the alert use the same rule, so they can no longer disagree (#492)
- Moved while parked compares with the right spot. The gateway publishes the engine stopping before that poll's GPS fix, so the parking spot was the previous fix, at speed hundreds of metres back. The parking poll's own fix now replaces it (#492)
- Two-tap confirmations: deleting a maintenance log entry asks first instead of going on a single tap, and the token list's "Revoke?" times out like the other confirmations (#492)
- Logs page: changing filters, searching and live mode could overlap, and an older answer could replace a newer one. The newest request wins now, and live mode pauses in a hidden tab (#495)
- Quieter logs. Every successful request was an Information line (447 of 525 lines in a demo session, the log viewer's own polling included), and HttpClient added four lines per outgoing call. Successful requests are now Debug, refusals and requests over a second stay Information, and failures stay Error. A demo session through every page now writes 6 lines.
DEBUG_LOGS=truestill logs every request (#493) - A session no longer breaks behind a forward-auth proxy that passes its own
Authorization: Bearerheader: only aBearer gs_...token selects token sign-in (#489) - The data export stops reading when the browser goes away, and a database error while noting a token's last use is logged instead of failing the request (#489)
- All-in-one: the gateway reports its version again, in its log and to Home Assistant's gateway device, instead of "unknown" (#497)
- The Worker no longer warns about the gateway's new
drivetrain/chargingDataAvailabletopic as unmapped (#496) - Screen readers: the revoke buttons name their token, the online/offline toast is announced, and error lines in dialogs and views are announced as alerts (#492, #495)
- The demo panel's two OK buttons are translated (#492)
Security
- Read-only tokens could download the whole history (
/api/export) and read the logs (/api/logs); both are session-only now (#489) - Login limit: with no trusted proxies configured, a device on the LAN could forge
X-Forwarded-Forand never hit the limit; see Upgrade Notes (#489) - VINs in browser error reports are now redacted in the message and the stack too, not only in the page (#489)
- No forged log entries. Text an entry quotes from outside, such as an identity provider's error description or a browser error report, could carry a line break and a timestamp and show up in the log viewer as an entry of its own. The log files now indent an entry's following lines, and older files still read as before (#493)
Performance
- The log viewer reads 64 KB from the end of each log file and only reads further when the page is not yet full, instead of reading 8 MB per file on every request, every ten seconds in live mode (#493)
Documentation
- The README lists every push alert, the tyre history, the car colour and the vehicle type override, and says the export and the logs stay session-only for tokens. The quick start no longer passes
AUTH_COOKIE_SECURE=false(#494) CONFIGURATION.mddocumentsSerilog__MinimumLevel__Override__<category>(one source at Debug withoutDEBUG_LOGS) andMqtt__ClientId(#494)ARCHITECTURE.mdcovers API tokens, the log files, the log viewer and the export, and the all-in-one README its/datalayout and logs (#494, #496)- The issue templates know the all-in-one image, Unraid and the newer components, and point questions to Discussions (#494)
Internal
- Shared
ViewHeader,StatusBadgeandConfirmFootercomponents and auseAsyncRequestcomposable replace copies across the views; the backend folds its cooldown checks and local-date helpers together (#495) - Frontend tests run in about 4 seconds instead of 21, with the same tests and the same coverage (#495)
- The all-in-one image no longer prunes the gateway's virtual environment: the gateway now installs only its runtime packages itself (17 instead of 48) (#496)
Dependencies
- SAIC gateway 0.12.0 to 0.13.0-rc3, which replaces gmqtt with aiomqtt and requires saic-ismart-client-ng 0.10.0 (#496)
Full Changelog
v0.11.0...v0.12.0: v0.11.0...v0.12.0
v0.11.0
Upgrade Notes
- Four database migrations run automatically at API startup:
AddParkedPosition,AddApiTokens,ReplaceGpsIndexandRestoreChartIndex. No action needed. Rebuilding the GPS index and restoring the statistics index (see Performance) each take a moment on a large telemetry table (#484, #485, #488) - All-in-one: PostgreSQL authentication is tightened on the first start. The embedded database trusted every local connection, so any process in the container, the gateway included, could open a superuser session. On the first start the role's password is hashed again as SCRAM from
POSTGRES_PASSWORD, and the database then takespeeron its socket andscram-sha-256over TCP. It runs once, and nothing has to be done (#465) AUTH_COOKIE_SECUREhas a newautovalue, now the default in Compose, the all-in-one image and the Unraid template. It marks the session cookie Secure whenever the browser comes in over HTTPS, through a reverse proxy too, and plain HTTP still signs in.trueandfalsemean what they did. An existing Unraid container keeps thefalseit was created with: set it toautoif you reach GarageStack over HTTPS (#465)- Push notifications no longer send your MG login email to Google, Mozilla and Apple: the VAPID contact used to default to
mailto:plusSAIC_USER. The newVAPID_SUBJECTsets it; left blank, it isCORS_ORIGINwhen that is https, and a placeholder otherwise. Compose now passesCORS_ORIGINto the Worker too, since the Worker signs the pushes (#465) - Two new notification types are on by default: Slow puncture and Moved while parked. Untick them per device under Settings > Notifications, or set
TYRE_PRESSURE_DROP_BARto0to switch the slow-puncture alert off for everyone. Moved while parked starts once the car has parked on this version, since only then is its parking spot kept (#483, #484) - Compose: update with
git pullanddocker compose up -d --buildto pick up the new wiring: the API mounts the Worker's log volume read-only for the log viewer, the Worker getsCORS_ORIGIN, the broker gets a health check the gateway waits for, every container's console log rotates (3 x 10 MB), andMAP_STYLE_*reach the frontend build from.env. A compose file of your own needsWORKER_LOG_DIRECTORYand that mount for the log viewer to show the Worker; without them it shows the API alone (#465, #466, #472, #487) - The Unraid template has three new fields:
VAPID_SUBJECT,TYRE_PRESSURE_DROP_BARandLOG_RETAINED_FILES, andAUTH_COOKIE_SECUREdefaults toauto. They are all optional, so an existing container keeps running; update the template to see them (#465, #466, #467, #483)
Features
- Read-only API tokens. A script, a dashboard or a watch can read GarageStack's data without signing in: make a token under Settings > API tokens and send it as
Authorization: Bearer gs_.... A token reads as the account that made it and can only read: commands, changes and the token endpoints answer 403, so a leaked token can neither send a command nor make more tokens. The token is shown once, only its hash and first nine characters are stored, and an account holds up to 20 (#485) - Full data export. Settings > Your data downloads one zip with everything GarageStack keeps: your settings and notifications and, per car, the car, its trips, maintenance, climate schedules, home and work places, and every telemetry row as a CSV a spreadsheet opens. A read-only API token can download it too. Five downloads per quarter hour (#486)
- Log viewer. The new Logs page (in the sidebar, after Maintenance) shows the newest entries of the API's and the Worker's log files, newest first, filtered by service, lowest level and text. An exception's lines fold away under their entry, and Live reads again every ten seconds (#487)
- Tyre history and a slow-puncture alert. Tap a tyre pressure on the car diagram to see a month of tyre history and how each tyre is doing against the other three. A tyre that falls
TYRE_PRESSURE_DROP_BAR(0.15 bar) behind the others over two weeks sends a Slow puncture alert, at most once every three days. Comparing with the other three tyres cancels out the weather, so a slow leak shows before the tyre is low. It needs a week of days on which all four tyres reported (#483) - Moved while parked. An alert when a parked car reports a position more than 300 m from where it parked while the engine is off: towed, lifted onto a truck or taken on a ferry. Once per parking. A sleeping car only reports now and then, so the alert comes with the car's first report after the move (#484)
- Commands for plug-in cars, each in the card that shows its state: a charge target slider (40 to 100%, on cars that take one), start and stop charging, lock and unlock the charging cable, battery heating on and off, and open the boot. Unlocking the cable and opening the boot take a second tap. A command counts as done once the car reports the change, not on the gateway's "Success" alone, and a charge target the gateway would silently drop is refused up front (#462)
- Charging and battery heating schedules. The charging session card changes the car's charging schedule (until a set time, until the charge target, or off, with start and end times), and the battery heating card switches its schedule and sets its start time. The times are in the car's own time zone (#463)
- Browser errors reach the API log. An error in the web app used to show only in that browser's console. While someone is signed in it is now reported to the API log too, each distinct message once and at most ten per page load (#467)
- Push on plain HTTP explains itself: Settings > Notifications says push needs an
https://address, instead of leaving the push switch out (#466) - The demo carries commands out. Each command changes the demo car two seconds later, where every button used to wait out the 45-second timeout. Charging with the cable unplugged is refused with a reason, so the demo shows a refusal too (#482)
- A day's log file rolls over at 100 MB instead of stopping at 1 GB, and
LOG_RETAINED_FILES(30) sets how many files each service keeps (#467)
Bug Fixes
- Plain-HTTP installs load again. Since v0.7.0 the page stayed blank on
http://<LAN address>:8080, the address the README and the Unraid WebUI link use: the Content-Security-Policy made the browser fetch the app's own scripts over https. Browsers exemptlocalhost, and a reverse proxy that sets its own policy hides it, so it went unnoticed. A browser test now opens the demo over plain HTTP on a host name (#464) - Plug-in cards on a first visit. A new account with a plug-in car never showed the charging session and battery heating cards. A first visit now takes the drivetrain's defaults and saved layouts are untouched, so if you never saw these cards, switch them on in edit mode (#462)
- Maintenance: a refused delete closed the dialog as if it had worked, and a refused service log delete showed nothing; both now stay open and say why. Add is disabled until the car is known, instead of doing nothing, and an item that was never serviced has the same colour everywhere (#464, #468, #481)
- Notifications: a failed load read "No notifications"; the panel now gives the reason and a Try again button, and a failed action names its reason instead of "Error" (#464)
- Quieter logs during an outage. While the broker or PostgreSQL was down, the Worker and the API logged an error with a stack trace every 5 seconds, over 700 an hour. Now it is the first failure in full, a reminder every 5 minutes, and the recovery with how long it took (#467)
- A malformed payload on a known topic is logged as such instead of as an unknown topic, an unknown topic warns once instead of on every poll, and an OpenChargeMap rate limit logs one warning instead of every failure twice (#467)
- Keyboard and screen readers: trips in the trip list can be selected from the keyboard; dialogs and the notification panel take focus when they open, keep Tab inside and hand focus back when they close; Escape closes the mobile menu, the notification panel and the install prompt; the remember-me switch on the login page has a name (#470, #471, #481)
- The map's loading pills spin again (#464)
command.unsupportedandtrip.tooManyIdsrefusals have real messages instead of "bad request" (#464)- The API refuses NaN and Infinity in map queries (NaN used to fetch and cache tile 0,0), and refuses a maintenance note over 1000 characters instead of failing with a 500 (#464)
- The statistics tyre legend is translated (LV, RV, LA and RA in Dutch) (#468)
- The demo controls show speed and temperature in your own units (#471)
- The Unlock button in the doors card has its warning style, and a link drawn as a button is no longer underlined (#462, #486)
- On a day when midnight repeats at a clock change, statistics start the day at the first midnight instead of the second (#469)
Security
- Your VIN, email and push addresses are out of the logs. Every
/api/vehicles/{vin}/...request logged the full VIN; it now reads***0001. Sign-in lines shorten an email-shaped name, a failed push logs only the push service's host, and the POI cap warning rounds its area to about 10 km (#465) - Push subscriptions must be an https URL on a public host name and the default port, without credentials, an IP address or a LAN-only suffix, and their lengths are capped. The Worker posts to that URL, so any signed-in user could make it call an address on your network (#465)
- Rate limits behind an outer proxy. Only one forwarded hop was unwrapped, so behind Traefik or Nginx Proxy Manager every visitor got the outer proxy's address and shared one login limit. Trusted hops are now unwrapped all the way (#465)
- All-in-one: PostgreSQL no longer trusts local connections (see Upgrade Notes), the im...
v0.10.0
Upgrade Notes
- Four database migrations run automatically at API startup:
AddPushSubscriptionExcludedCategories,AddChargingDetails,AddCommutePlacesandAddTripSpeedFigures. No action needed. Every trip that already has a purpose is marked as chosen by hand, so the automatic commute marking never changes it (#451, #452, #455, #459) - Update the API, the Worker and the web interface together. Statistics read a new
/stats/dailyendpoint that replaces/history, and the API's readiness check listens for a heartbeat from the Worker. The all-in-one image always runs all of them from the same build (#454, #459) - Open Settings > Notifications once on each device that gets push. Switching a notification type off now stops its push (#451), but the server learns which types a device switched off only when that device opens its notification settings. Until then it keeps getting every type, as it did before.
- Five new notification types are on by default: Low 12V battery, Low fuel, No data from the car, MG sign-in failed and Charging interrupted. Untick them per device under Settings > Notifications, or set
AUX_BATTERY_LOW_VOLT,LOW_FUEL_PERCENTorSTALE_DATA_HOURSto0to switch that alert off for everyone (#451, #452) - The API asks GitHub for the latest release once a day, to show the update notice in the footer. Only the release number is fetched, and nothing about your car or account is sent. Set
UPDATE_CHECK_ENABLED=falseto stop it (#454) - Two API endpoints are removed:
GET /api/vehicles/{vin}/trips/last, which nothing used, andGET /api/vehicles/{vin}/history, replaced by/stats/daily. This only matters to your own scripts that call the API directly (#453, #459) - About 10 minutes after the Worker starts, it works out the top and average speeds of the trips saved before this release, so a year of statistics no longer has to read each trip's GPS fixes. It runs once, in the background (#459)
- The Unraid template has seven new fields:
AUX_BATTERY_LOW_VOLT,LOW_FUEL_PERCENT,LOW_EV_PERCENT,STALE_DATA_HOURS,UPDATE_CHECK_ENABLED,RATE_LIMIT_GLOBAL_PER_MINUTEandDEBUG_LOGS. They are all optional, so an existing container keeps running; update the template to see them (#451, #452, #454)
Features
- Statistics beyond 90 days. Statistics have their own period, apart from the map's: the last 7, 30 or 90 days, this or last month, this or last year, or custom dates up to ten years. Charts show a point per day up to 92 days, per week up to a year and per month beyond that, and periods longer than a month get a table of trips, distance and energy (or fuel) per month, with a total. Each day is counted from every reading in your own time zone, so a day's energy peak is no longer missed. A stored choice of 7, 30 or 90 days carries over (#459)
- Commutes are marked in the trip log automatically. Set home and one or more work places under Home and work, and every trip between home and a work place becomes a commute: the trips already in the log, and each new one as it is saved. Pick a place on a map or click a trip's start or end address, and set its radius from 50 to 1000 m (250 m by default). A car has one home. A purpose you chose yourself is never overridden, and the positions stay in your own database (#455, #460)
- New alerts: Low 12V battery (below
AUX_BATTERY_LOW_VOLT, 12.0 V, on several polls in a row while parked), Low fuel (belowLOW_FUEL_PERCENT, 15%, on hybrids and plug-in hybrids), No data from the car (nothing forSTALE_DATA_HOURS, 48 hours) and MG sign-in failed (once per outage). The low EV battery level is nowLOW_EV_PERCENT(20%) (#451) - Charging interrupted: a charge that stops on a named fault (charger fault, port too hot, plug not fully in, voltage mismatch) sends its own notification with the reason, instead of "Charging complete" (#452)
- A push switch per device: Settings > Notifications (was Notification types) has "Push notifications on this device". Ticking a type no longer subscribes or unsubscribes, so it never brings up a permission prompt (#451)
- The HV battery card shows the charge target and which charge current limit is in use, and the charging session card shows when the last charge started. The BMS status, schedule mode and battery heating schedule are worded instead of shown as gateway codes (#452)
- Readiness check at
/api/healthfor uptime monitors: it reports the database, the MQTT broker and the Worker, answers200while all are up and503when one is down, and needs no sign-in. The Worker image's health check now reads a heartbeat, so a Worker that lost the broker or the database shows unhealthy instead of merely running, and the all-in-one image checks/api/healthwith a 120 s start period (#454) - Update notice: the footer links to the release page when a newer GarageStack is out (#454)
Bug Fixes
- Switching a notification type off now stops its push. It used to hide the type in the panel only: every device still got every alert pushed (#451)
- Turning push on works on a fresh device. It used to subscribe only when the number of unticked types changed, so turning push on meant unticking and re-ticking a type (#451)
- No more hourly repeats of tyre and low EV alerts on a sleeping car. They now go out once per report from the car, and a message the broker replays on reconnect cannot set them off again (#451)
- Scheduled climate retries when the car is busy. After a night's sleep the car could refuse the climate command with "Other remote command in progress". The schedule now sends it again after 30 seconds, up to three times, so a run starts at most about three minutes late (#460)
- A BEV gets the daily energy chart. It was only offered to cars that burn fuel; every known drivetrain now has it, in kWh on a plug-in and litres on a plain hybrid (#452)
- The Worker no longer warns on every message for the gateway's charging stop reason, charge target, charge current limit and last charge start (now stored), or for topics it leaves out on purpose (#452)
- A language set on your account on another device now applies on first load, instead of after a reload (#456)
- The notification buttons name the unread count for screen readers ("Notifications, 2 unread") (#456)
- The web manifest is served as
application/manifest+jsoninstead ofapplication/octet-stream(#456) - The install prompt no longer promises offline use, which the app does not offer; it now says "Opens in a tap from your home screen" (#458)
- The API notices a broker that came back before the next command is sent, and Docker's 10-second
/healthprobe no longer writes an Information line to the log every time (#454)
Performance
- The first load is smaller: the app's entry script goes from 92.0 to 83.5 kB gzipped and its stylesheet from 20.0 to 17.4 kB. Dutch loads only when it is the chosen language, and the map filters' dropdown styles load with the map filters (#456)
- The dashboard opens a connection to the map tile server while it loads, when you are already signed in (#456)
- Each trip keeps its top and average speeds, so trip summaries over a long period no longer read every trip's GPS fixes. A year of daily statistics at one reading per minute takes about 420 ms (#459)
Documentation
- The README gains a Monitoring section and a note on the update notice, updating a Compose install reads
git pull,docker compose pull,docker compose up -d --build, and the dashboard cards and alert lists are current (#452, #454) CONFIGURATION.mdexplains that settings set by their .NET key need adocker-compose.override.yml, with an example, and covers the new alert levels andUPDATE_CHECK_ENABLED(#451, #452, #454)DEMO.mdhas the right trip count and history span, and the docs say the 90-day floor onTELEMETRY_FULL_DETAIL_DAYSis now there for the map alone (#452, #459)RELEASING.mdsyncs the Community Apps template through a pull request in that repository (#461)
Internal
- The demo covers 400 days and reports a daily energy counter, so the demo site shows last year, the month table and the energy chart (#459)
- One guarded reconnect in the MQTT publisher, shared by publishing and the health check (#454)
- Remove unused translation keys (#452)
Dependencies
- Development tools: vue-tsc 3.3.12 (#457)
Full Changelog
v0.9.2...v0.10.0: v0.9.2...v0.10.0
v0.9.2
Bug Fixes
- Tiles in a row are the same height again. Since v0.9.1 wraps tile text instead of cutting it off, a tile with a longer label or value grew taller than its neighbours on the dashboard and statistics. Every tile in a row now takes the height of the tallest one, on phones, in edit mode and on wide screens alike (#450)
- Tiles no longer get too narrow. The grid fits as many tiles as it can at 13rem or wider, instead of a fixed 4, 6, 8 or 12 columns, so readings such as "71% · Active" stay on one line and every row from 700px up is the same height. Wide screens and tablets show one or two columns fewer than before (for example 10 instead of 12 at 2560px, and 2 instead of 3 on an 820px tablet); phones keep two (#450)
Full Changelog
v0.9.1...v0.9.2: v0.9.1...v0.9.2
v0.9.1
Bug Fixes
- Tile text wraps instead of being cut off. Dashboard, statistics and trip log tiles cut labels such as "Climate control" and values such as "71% · Active" short with an ellipsis, on phones and in the wide desktop grid alike. Labels now take up to two lines, a value keeps its number and unit together, and long Dutch words are hyphenated (#447)
- Dashboard tiles say what they mean. Lights no longer turns red when the lights are off, Find my car reads "Off" instead of "-" while idle, and Maintenance names the worst state (Overdue, Due soon, OK) instead of a bare count (#447)
- The page tells the browser and screen readers which language it is in. It always said English, so Dutch pages were read out in an English voice (#447)
- The trip log on a tablet stacks each trip as on a phone, so addresses are no longer cut down to a street name, and the totals sit two to a row (#447)
- Statistics charts label their axis with short dates ("10 Sep") instead of full ones, which crowded a phone. Tooltips keep the full date (#447)
- Cards in the light theme get a faint shadow, so they no longer blend into the page, and readings use tabular figures, so numbers line up (#447)
- The sidebar logo and the page title sit on one line on desktop and tablet (#448, #449)
- Clicking the GarageStack title in the sidebar opens the dashboard, as the mobile title already did (#444)
- Even spacing and card titles across the views: every card heading shares one style and icon, chart cards and the trip log totals use the standard padding and spacing, and phones use one 0.75rem gutter (#445)
- Every form field is the same size. Native selects, text fields and the multiselect share their padding, font, corners and focus ring, and the vehicle type in Settings is a native select like region and units (#445)
- The map's charging power filter shows its label and description on separate lines. They ran together, and the slider's tooltips covered both (#445)
Internal
- pnpm 12.11.2 (#446)
Dependencies
- Scalar.AspNetCore 2.17.14 (#446)
- Frontend: vite 8.3.4, vite-plugin-pwa 2.0.0, maplibre-gl 6.13.0, vue-router 5.4.0 and vue-i18n 11.4.13. vite-plugin-pwa 2.0.0 is a major only because it widens a peer range for a package this project does not use (#446)
- Development tools: eslint 10.12.0, oxlint and eslint-plugin-oxlint 1.87.0, @playwright/test 1.64.0 and jsdom 30.1.2 (#446)
- Actions: actions/setup-node v7.1.0 and github/codeql-action v4.38.3 (#446)
Full Changelog
v0.9.0...v0.9.1: v0.9.0...v0.9.1