Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,19 @@ WIDGET_API_KEY=
# Leave empty to disable the charging stations feature (the map still works).
OPENCHARGEMAP_API_KEY=

# ── Dutch registration (RDW open data) ────────────────────────────────────────
# For a car with a Dutch plate: the APK expiry date, open recalls and whether the
# car is insured, shown on a dashboard card and sent as notifications. The plate,
# entered under Settings, is the only thing sent (to opendata.rdw.nl); nothing
# about your account or the car's position goes with it. No API key required.
# Off by default; the plate field and the card only appear once this is true.
# RDW_ENABLED=false
# Hours a lookup is kept before the Worker asks the RDW again.
# RDW_REFRESH_HOURS=24
# Optional Socrata app token (sent as X-App-Token). Without one, requests share
# the lower rate limit every anonymous caller gets.
# RDW_APP_TOKEN=

# ── Overpass API (OpenStreetMap POI data) ─────────────────────────────────────
# The Overpass API is used for the fuel station, motorway service area and speed
# camera overlays on the map. No API key is required (free/FOSS data). The default
Expand Down
25 changes: 22 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ The statistics, trip log, maintenance list and light theme are in the [screensho
- **Trip history** -- Browse past journeys on an interactive map, each drawn on the roads it took and coloured by speed or by the speed limit, with a heatmap of the roads you drive most. Each trip is saved to the database a few minutes after the car parks. After upgrading from a version that did not save trips, the existing history is saved in the background on the Worker's first start.
- **Trip log** -- Mark each trip as business, commute or private (commutes between your home and work are marked automatically), add notes, and export a month or a year as a spreadsheet with the addresses and odometer readings a tax trip log (such as the Dutch *rittenregistratie*) asks for. See [Trip log](#trip-log).
- **Maintenance** -- Keep the car's service items (oil, tyres, the yearly inspection, ...) with a distance interval, a time interval or both. GarageStack works out from the odometer and your service log when each one is due, shows the most urgent on the dashboard, and sends a notification when an item reaches 90 % of its interval. Log each service with its date, odometer reading and notes.
- **Dutch registration (RDW)** -- For a car with a Dutch licence plate, a dashboard card with the date the APK runs out and the days left, open recalls with what can go wrong and what the dealer does about it, and whether the car is insured, from the [RDW's open data](https://opendata.rdw.nl). Notifications come for a new recall, the APK a month and a week ahead, and a car with no insurance on record. Off until `RDW_ENABLED=true`; the plate, entered under Settings, is the only thing sent. See [Dutch registration (RDW)](#dutch-registration-rdw).
- **Energy statistics** -- Track daily energy consumption, efficiency (Wh/km on a plug-in car, L/100 km on a hybrid), fuel use, electric share, average driving speed, and more, for any period from a week to several years.
- **Remote commands** -- Trigger climate pre-conditioning (normal climate, fan only or front defrost), lock or unlock the car, open the boot, and activate the horn and lights remotely from the dashboard. On a plug-in car also start or stop charging, lock or unlock the charging cable, switch battery heating on or off, set the charging and battery heating schedules, and set the charge current limit and, where the car takes one, the charge target. Opening the boot and unlocking the cable ask for a second tap. Each command reports whether the car carried it out, and if it refused, the reason the MG servers gave.
- **Climate schedules** -- Switch climate on at a set time on chosen weekdays, or once. A schedule sets the temperature or mode, seat heating and the rear defroster, and can skip mild days by the car's outside temperature. Schedules run on the server, so no browser needs to be open, and each run sends a push notification saying whether the car started climate.
- **Push notifications** -- Browser and in-app alerts for key events: engine started, low or high tyre pressure, a slow puncture, low EV battery, low fuel, a weak 12V battery, car left unlocked, doors or windows left open, the car moving while parked, a charge that finished or stopped early, maintenance coming due, a climate schedule that ran, the messages the official MG app receives, and data that stopped arriving because the MG sign-in failed or the car went quiet. Each device chooses which ones it gets.
- **Push notifications** -- Browser and in-app alerts for key events: engine started, low or high tyre pressure, a slow puncture, low EV battery, low fuel, a weak 12V battery, car left unlocked, doors or windows left open, the car moving while parked, a charge that finished or stopped early, maintenance coming due, the APK running out or a recall on a Dutch plate, a climate schedule that ran, the messages the official MG app receives, and data that stopped arriving because the MG sign-in failed or the car went quiet. Each device chooses which ones it gets.
- **Homepage widget** -- A read-only API endpoint for the [gethomepage.dev](https://gethomepage.dev) Custom API widget, exposing key vehicle stats at a glance.
- **Log viewer** -- The Logs page shows the entries of the API's and the Worker's log files, newest first and older ones loading as you scroll, filtered by service, level and text, with exceptions folded open on request and a live mode that adds what was written every ten seconds. The files themselves stay on the server, one per day (`LOG_RETAINED_FILES`).
- **Full data export** -- Settings > Your data downloads everything GarageStack keeps as one zip: per car its trips, maintenance, schedules, places and every telemetry reading (as CSV), and your notifications and settings.
Expand Down Expand Up @@ -103,6 +104,7 @@ Cards are shown or hidden automatically based on vehicle type (HEV / PHEV / BEV)
| Charging Session | OBC power, cable lock, charging type, last start and end; start or stop charging, lock or unlock the cable, set the charging schedule | PHEV, BEV |
| Battery Heating | Pre-heating status and schedule; switch it on or off, set the schedule | PHEV, BEV |
| Maintenance | The most urgent state of your maintenance items, linking to the Maintenance page | All |
| APK & recalls | The APK expiry date and days left, open recalls with their risk and repair, and the insurance on record, from the RDW | All (only with `RDW_ENABLED` and a plate set) |
| Climate Schedule | When a climate schedule starts climate next | All (off by default) |

### Statistics insights
Expand Down Expand Up @@ -146,7 +148,7 @@ Before installing, make sure the following are available on your host:
- **Docker** 23.0 or later (or Podman with Docker Compose compatibility); the quick start's relative `./garagestack-data` mount needs 23.0
- **Docker Compose** 2.20 or later (bundled with Docker Desktop; on Linux install the `docker-compose-plugin` package) -- required for Option B only
- An **MG iSmart account** with your vehicle already linked in the official app
- Outbound internet access on the host so the container can reach the SAIC API and (optionally) Overpass / Open Charge Map
- Outbound internet access on the host so the container can reach the SAIC API and (optionally) Overpass / Open Charge Map / the RDW

---

Expand Down Expand Up @@ -351,12 +353,16 @@ GarageStack checks your vehicle's state every 5 minutes and sends both a browser
| Charging complete | Charging stops while the cable is still connected (plug-in vehicles) |
| Charging interrupted | Charging stops because of a fault the car names: the charger, an overheating port, a plug not fully in, or a voltage mismatch (plug-in vehicles; unplugging mid-charge sends nothing) |
| Maintenance due | A maintenance item reaches 90 % of its interval, or passes it (checked every 6 hours, 7-day cooldown per item) |
| Open recall | The RDW lists a recall on the car's plate that has not been repaired (once per recall; a recall later reported repaired sends nothing) |
| APK due | The APK runs out within 30 days, and again within 7 days, of the date the RDW has (once each per APK date) |
| APK expired | The APK's last valid day has passed (repeated monthly until the RDW has a new date) |
| No insurance on record | The RDW has no WAM insurance on record for the car (repeated monthly while that lasts) |
| MG app message | The official MG app receives a message, such as an alarm or a reminder (sent as it arrives, once per message) |
| Scheduled climate | A climate schedule ran: climate started, the car refused, or it did not answer (nothing is sent for a run skipped because the car was in use or the day was mild) |

Push notifications require VAPID keys to be configured (`VAPID_PUBLIC_KEY` / `VAPID_PRIVATE_KEY`). Without them, alerts still appear in the in-app notification panel. While GarageStack is open in a browser that allowed notifications but is not subscribed to push, the same alerts show up as system notifications too; a subscribed browser gets them through push instead, so nothing arrives twice.

Settings has a push switch for the device you are on and a per-type checklist for these alerts, which offers only the types the car's drivetrain can produce: the plug-in alerts (low EV battery, charging complete, charging interrupted) are left out for a plain hybrid, and low fuel for a full electric car. Both are kept per device: a type switched off on your phone still reaches your laptop, and still shows up in the notification panel. Only the switch turns push on or off; the checklist never asks the browser for permission.
Settings has a push switch for the device you are on and a per-type checklist for these alerts, which offers only the types the car's drivetrain can produce: the plug-in alerts (low EV battery, charging complete, charging interrupted) are left out for a plain hybrid, low fuel for a full electric car, and the RDW type (APK, recalls and insurance) wherever `RDW_ENABLED` is off. Both are kept per device: a type switched off on your phone still reaches your laptop, and still shows up in the notification panel. Only the switch turns push on or off; the checklist never asks the browser for permission.

Notification texts are written by the background worker, which has no browser to take a language from, so their language is a deployment setting: `NOTIFICATION_LANGUAGE=en` (default) or `nl`. The web UI's own language toggle does not affect them.

Expand Down Expand Up @@ -398,6 +404,19 @@ Only trips the Worker has saved can be logged, so the trip being driven, and one

---

## Dutch registration (RDW)

For a car with a Dutch licence plate, GarageStack shows what the [RDW](https://opendata.rdw.nl) has on record for it: when the APK runs out, the recalls on the car, and whether it is WAM insured. It is off until the deployment sets `RDW_ENABLED=true`; until then nothing is sent and none of the below appears.

- **The plate.** Enter it under **Settings > Licence plate**, which is drawn as a Dutch plate. Type it with or without dashes: they are placed as the plate has them while you type (`HPK-98-B`, `12-ABC-3`). The plate is kept per car in GarageStack's own database, without the dashes, and **Remove** clears it along with what the RDW said about it.
- **The lookup.** Saving the plate looks it up straight away, so the card fills at once. After that the Worker asks again every `RDW_REFRESH_HOURS` (a day by default). The plate is the only thing sent, to `opendata.rdw.nl`, together with the RDW's own reference codes for the recalls it lists; no key is needed.
- **The card.** The **APK & recalls** card shows the days the APK has left and how many recalls are open. Clicking it shows the APK date, the insurance on record, each open recall with what can happen and what the dealer does about it, the recalls already repaired, and when the RDW was last asked. The recall texts are the RDW's own, in Dutch. A plate the RDW does not know is said so, rather than shown as an error.
- **Notifications.** A new open recall (once per recall: one reported repaired later sends nothing), the APK a month and a week before it runs out and once it has, and a car with no WAM insurance on record. They are listed under [Push notifications](#push-notifications), and can be switched off per device like the other types.

The settings, including an optional Socrata app token for a higher rate limit, are in [`CONFIGURATION.md`](documentation/CONFIGURATION.md#dutch-registration-rdw).

---

## Homepage dashboard widget

GarageStack has a read-only endpoint for the [gethomepage.dev](https://gethomepage.dev) Custom API widget, switched on by setting `WIDGET_API_KEY`. The setup and every field it returns are in [`WIDGET.md`](documentation/WIDGET.md).
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.demo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ services:
# The browser smoke tests drive several pages in parallel from one address, which is far
# more traffic than the default per-IP budget is sized for.
RATE_LIMIT_GLOBAL_PER_MINUTE: "${RATE_LIMIT_GLOBAL_PER_MINUTE:-2000}"
# The demo's stand-in RDW asks nothing upstream, so the card is on unless this says false.
RDW_ENABLED: "${RDW_ENABLED:-}"
ports:
- "127.0.0.1:${API_PORT:-5001}:8080"
volumes:
Expand Down
5 changes: 5 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ x-dotnet-environment: &dotnet-environment
OVERPASS__BASEURL: "${OVERPASS__BASEURL:-}"
SPEEDCAMERAS__ENABLED: "${SPEEDCAMERAS__ENABLED:-}"
OPENCHARGEMAP_API_KEY: "${OPENCHARGEMAP_API_KEY:-}"
# The Dutch registration: the API looks a plate up as it is entered, the Worker keeps it current
# and sends the notifications, so both need the switch. See .env.example.
RDW_ENABLED: "${RDW_ENABLED:-}"
RDW_REFRESH_HOURS: "${RDW_REFRESH_HOURS:-}"
RDW_APP_TOKEN: "${RDW_APP_TOKEN:-}"

# Docker keeps container output forever unless told otherwise. The .NET services also write their
# own rotated files (LOG_RETAINED_FILES), so a few megabytes of console history per container is
Expand Down
2 changes: 1 addition & 1 deletion docker/all-in-one/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ By default the web login uses the same `SAIC_USER` and `SAIC_PASSWORD` credentia

### Optional

Every other variable works here as well, under the same name as in Docker Compose. They are all listed, with their defaults, in [`CONFIGURATION.md`](../../documentation/CONFIGURATION.md): push notifications, single sign-on, the map's data sources, tyre pressure bands, the traction battery's real size, the rate limit and the Home Assistant broker login. A few behave differently in this image:
Every other variable works here as well, under the same name as in Docker Compose. They are all listed, with their defaults, in [`CONFIGURATION.md`](../../documentation/CONFIGURATION.md): push notifications, single sign-on, the map's data sources, the Dutch registration (RDW) lookups, tyre pressure bands, the traction battery's real size, the rate limit and the Home Assistant broker login. A few behave differently in this image:

| Variable | In this image |
|----------|---------------|
Expand Down
Loading
Loading