feat(vag_vehicle): read VW Group charge state from the EU Data Act portal - #141
Conversation
Read-only VW / Audi / Škoda / SEAT / Cupra SoC from the VW Group EU Data Act portal. We Connect third-party APIs are blocked. The driver emits DerVehicle, binds VIN identity, ages vendor datasets and stops emitting when they are stale. No wake or charge_start. Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Set make/serial from brand+VIN even when the portal cookie is missing so the car still appears. Sort portal files by createdOn instead of array order. No wake or charge_start. Signed-off-by: Cursor Agent <cursoragent@cursor.com>
The newest file at the first listing after start was reported as a fresh reading, though it can be hours old when the car has slept. The host has no wall clock, so that file is now reported stale until a newer one arrives. Unzipping kept one table slot per output byte. The newest 32 KiB now stay per byte for back-references and older text is flushed into chunks, which cut allocation for 1 MB of JSON from 9 MB to 3 MB, and a dataset over 4 MiB is refused. Entries from streaming writers, which put their sizes in a data descriptor after the data, now decode too. A file without SoC was downloaded again on every poll; each file is now read once. The file list is fetched every 5 minutes instead of 2, and every poll sets the interval, since the host ignores driver_poll's return value. As in evcc, the newest point among candidate fields wins. The data-point keys were checked against VW's data dictionary V5.0, and upstream_docs now watches that dictionary instead of the portal's web app. Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # CHANGELOG.md
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 086259b00e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| local known_age = name ~= baseline_file | ||
| remember(soc, limit, state, ttf, known_age) |
There was a problem hiding this comment.
Avoid treating files found after an outage as fresh
If list polling fails for an extended period while one newer dataset is produced, the next successful poll treats that dataset as fresh solely because its name differs from the startup baseline, regardless of its createdOn or data-point timestamps. This resets the local age and emits soc_fresh=true even when the file is hours old, allowing Core to use stale SoC as a new observation; track the last successful listing interval or otherwise downgrade files discovered after a long gap.
AGENTS.md reference: AGENTS.md:L75-L75
Useful? React with 👍 / 👎.
| elseif es:match("HTTP 404") then | ||
| host.log("debug", "vag: no dataset files yet") |
There was a problem hiding this comment.
Re-resolve the request ID after list 404s
When an owner cancels and recreates the continuous data request, the cached identifier can start returning 404, but this branch leaves request_id intact. Every later poll therefore reuses the obsolete identifier because ensure_request_id() returns its cache, so the driver never discovers the replacement request until it is restarted; invalidate the cached ID on this response so metadata can be queried again.
Useful? React with 👍 / 👎.
Adds
vag_vehicle, a read-only driver that reads charge state for VW, Audi, Škoda, SEAT and Cupra cars from the VW Group EU Data Act portal. This is path B for srcfl/ftw#1442: a vendor driver, with no Home Assistant ingest in Core. The other vehicle drivers are #139 (TeslaMate) and #140 (Tesla Fleet API).How it works
VW has closed We Connect's third-party APIs. The EU Data Act portal is the door left: the owner orders their own car data there, and the portal delivers it as files.
key,dataFieldName,value,timestampUtc). While the car sleeps the file is an empty_no_content_found.zip.vehicle(DerVehicle):soc,charge_limit_pct,charging_statein Tesla's words,time_to_full_min,staleandsoc_fresh.The portal needs a VW ID login (OIDC), which the Lua host cannot do: it has no cookie jar. The owner pastes the
Cookieheader of a logged-in portal tab into YAML, masked byconfig_secrets. When that session ends the driver stops and the owner must paste a new one. evcc, which reads the same portal, logs in with email and password instead.No wake, charge start or climate control.
read_only = true,verification_status = "experimental". Porsche is not on this portal and is refused.Where it came from
A Cursor cloud agent wrote the first two commits against
mainat92adaf0. The Cursor GitHub App can only reachsrcfl/ftw, so its push here failed with 403, and the commits were applied unchanged from Fredrik's machine. The third commit fixes what review found.Fixed in review
_no_content_found, so the newest content file can be old, and the host has no wall clock to tell. The newest file at the first listing is now reported stale until a newer file arrives.ZipOutputStream, for one) puts its sizes after the data and 0 in the header. The driver could not read those; it now can.driver_poll's return value.upstream_docsnow watches that dictionary instead of the portal's web app.typeandfilenamego as request headers.Evidence
make test-driver ID=vag_vehicle: 36 passed, 16 skippedmake check: 4639 passed, 883 skippednot_recorded.Still open
host.unzipin Core would remove the Lua unzip. That is a Core change and not needed to test.How to test
After merge the driver is in the signed
drivers-betachannel. Until an FTW release bundles it, put the Lua file on the box as a local override at the path the YAML names. Report how long the cookie lasts, the size of a real file, and whether SoC and charging state match the car.Merge notes
CHANGELOG.md,index.yaml,devices.yaml,support-status.jsonandSUPPORT_STATUS.md. Merge one, rebase the next and rerun the generators;make checkshows any drift.drivers/BUNDLED_SOURCE.json.🤖 Generated with Claude Code