The car updates itself again, from this fork's own releases, while the
repository stays private:
- publish-car (flake) creates the pre-release car-<version> on the
forge and attaches the APK and its .sha256. It needs a forge token
that may write releases, from ~/.config/nilsmg4/forge-token or
$FORGE_TOKEN; it is sent in a header and never printed.
- The server relays releases and attachments (/v1/app/releases,
/v1/app/assets/...), read with a read-only FORGE_TOKEN from its
Secret, GitHub-shaped with download URLs back at itself. Redirects
away from the forge are not followed; off (404) without a token.
- The app asks its server with its own paired token, allows exactly
the server's host, downloads the APK itself instead of through the
DownloadManager (so the token stays in the app), verifies SHA-256 and
package name, and tries a PackageInstaller session (it may install
silently as the system user) before falling back to Downloads.
OTA.md is rewritten for this flow; the k8s and server READMEs explain
the new token.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
Same endpoints, request formats, validation rules and InfluxDB layout as
the Next.js server, so the car needs no change: POST /v1/telemetry,
PUT /v1/consumption/daily, PUT /v1/charging-sessions/{id}, GET
/v1/consumption/history/{id}, GET /v1/health. The dashboard, login and
the /v1/history reads are gone; Grafana takes over the dashboards.
- Go 1.26 standard library (net/http routing, log/slog) plus the
official InfluxDB 2 client. Fails closed at startup on a missing
InfluxDB setting or an ingest token under 24 characters.
- ABRP forwarder ported: newest fresh sample, rate limited, never
queued, credentials only in the form body.
- 22 tests: validation, aggregation, forwarding, config, and the
handlers through a fake store. govulncheck clean (x/net 0.60.0,
toolchain go1.26.9).
- Image: static binary on distroless, about 11 MB, UID 65532, port
8080; the build runs vet and the tests.
- Dev shell: Go, gopls and govulncheck instead of Node.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
- MongoDB replaced by InfluxDB 2 (one bucket, installationId tag).
Consumption is stored per chunk at its recordedAt and summed on read,
so a chunk the car re-sends from its cache overwrites itself instead
of being counted twice ($inc did count it twice). Lifetime is a
running total derived on read.
- POST /v1/telemetry takes batches of samples in ABRP's tlm fields; every
field is bounded, unknown fields are dropped, unread signals stay absent.
- After a successful write the newest fresh sample is forwarded to ABRP
with ABRP_API_KEY / ABRP_USER_TOKEN from the server environment; rate
limited, never queued. The car no longer needs ABRP credentials.
- Self-hosting: standalone output, Dockerfile (tests run in the build,
runs as UID 10001), .env.example and README for the new setup.
- Dev shell gains Node 22 and InfluxDB 2.
Verified locally against InfluxDB 2.7.12: all endpoints, retry
idempotency, and the dashboard pages. Unit tests: 17 pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- applicationId com.evsuite.abrp -> com.stinnesbeck.nilsmg4 (the car
build is .unstable); the Java namespace is unchanged. Installs next to
upstream's app rather than over it.
- APK names NilsMG4-*.apk, debug builds included; build-car follows.
- OTA install-result action, cache/download names, User-Agent and log
tags follow the new name.
- About credits fatihdonmezdev / FatihsMG4.
- SPECS.md journals what changed and what is still to do, starting
with pointing the About link and QR code at git.stinnesbeck.com/nils/mg4.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The MG4 head unit's platform certificate (c8a2e9bc…192ab8, per
tools/README.md) is the public AOSP test key. build-car fetches that key
into the gitignored tools/ directory from a pinned android-9.0.0_r1 tag,
builds assembleUnstableDebug, zipaligns and signs it, and refuses to
finish unless both the key's certificate and the resulting signer match
the expected SHA-256. Output lands in build/car/ with a .sha256 sidecar.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Provides JDK 21 and an Android SDK (platforms 36/36.1, build-tools
36.0.0) via `nix develop`. Points AGP at the SDK's aapt2 and Gradle at
the Nix JDK, since the binaries they would otherwise download do not
run on NixOS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>