The ABRP credentials are long to type on the car. "Enter on phone" (Live data tab, and Settings next to the charging price) shows a QR code; it opens a form on the server where the phone sends the ABRP API key and user token, charging price and usable capacity, confirmed with the approval password. The car polls with its own token and collects the values once, then saves them through the same checks as the fields on screen. Same device-flow shape as pairing. The server keeps the values in memory only, at most ten minutes, hands them out once with no-store, and never logs them or puts them back into the page; a paired token only reaches its own installation's request. Pairing's QR dialog is now shared (PhoneQrDialog), and the phone pages share one stylesheet. The config file also takes charging_price and usable_kwh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
Kubernetes manifests — car.k8s.stinnesbeck.com
Plain manifests for the car server, InfluxDB 2 and Grafana. They are only files: nothing here is applied automatically. Apply them yourself.
| File | What |
|---|---|
namespace.yaml |
Namespace mg4 |
influxdb.yaml |
InfluxDB 2.7.12 StatefulSet (10Gi PVC, default storage class), cluster-internal Service, NetworkPolicy admitting only the server and Grafana |
server.yaml |
Go server Deployment (1 replica, non-root, read-only root filesystem) and Service |
grafana.yaml |
Grafana 13.2.3 Deployment (1Gi PVC), Service; datasource and dashboards provisioned |
grafana/ |
The provisioned InfluxDB datasource and the MG4 dashboards (Live, Consumption, Charging) |
ingress.yaml |
Traefik IngressRoutes for car.k8s.stinnesbeck.com and Grafana, TLS from Traefik's default certificate |
secrets/secrets.example.yaml |
Template for the Secrets; placeholders only, not in kustomization.yaml |
secrets/secrets.yaml |
Your filled-in copy — gitignored, never committed |
kustomization.yaml |
Everything except the Secrets; generates the Grafana ConfigMaps |
Before the first apply
- Check
ingress.yaml: Grafana's host (placeholdercar-grafana.k8s.stinnesbeck.com). Both routes use thetraefik-internalclass, and both hosts must be covered by Traefik's default certificate. - Create the Secrets.
cp k8s/secrets/secrets.example.yaml k8s/secrets/secrets.yaml(gitignored), replace everyCHANGE-MEthere (openssl rand -hex 32):influxdb-auth,mg4-server(ingest token, approval password for pairing),grafana-adminandgrafana-influx(see below). Keep the template itself on placeholders only. - Registry access. The
mg4-serverpackage on git.stinnesbeck.com is public, so no pull secret is needed. If you make it private, add animagePullSecretsentry toserver.yaml.
Apply
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/secrets/secrets.yaml
kubectl apply -k k8s/
Use -k, not -f k8s/: plain -f applies the files without kustomize, so the Grafana
ConfigMaps (datasource and dashboards) are never created and Grafana does not start.
Grafana's InfluxDB token
Grafana reads InfluxDB with a token that can only read the mg4 bucket, from the
grafana-influx Secret. InfluxDB has to create that token, so it is a step of its own:
-
With InfluxDB running, create the token. The
influxCLI in the pod is already signed in as admin:kubectl -n mg4 exec influxdb-0 -- sh -c \ 'influx auth create --org mg4 --description grafana-read-only --json \ --read-bucket "$(influx bucket find --name mg4 --hide-headers | cut -f1)"' -
Copy the
"token"value from the output intografana-influx→tokenink8s/secrets/secrets.yaml, apply that file, and restart Grafana:kubectl -n mg4 rollout restart deployment/grafana.
Until the Secret exists, Grafana does not start (the container waits for the missing Secret). On a fresh install, apply everything once without Grafana working, create the token, then apply the Secret.
Notes
- InfluxDB's setup mode runs only on an empty volume. Changing
admin-tokenin the Secret later does not change the token inside InfluxDB. - The server uses the InfluxDB admin token; a token scoped to read/write on the
mg4bucket can replace it later. Grafana has its own read-only token (below). - The dashboards are read-only in Grafana's UI. Change the JSON in
grafana/dashboards/; the ConfigMap name changes with its content, which rolls Grafana. - The server image is pinned by digest in
server.yaml. To upgrade, push a new tag and put its digest there (skopeo inspect docker://git.stinnesbeck.com/nils/mg4-server:<tag>).