Files
mg4/k8s
nilsandClaude Opus 5.5 ca2f899403 App 2.11.0, server 2.3.0: live data straight to ABRP; settings regrouped
ABRP keeps getting live data while the car server is down: with an ABRP
API key and user token set in the app (Live data tab, or abrp_api_key /
abrp_token in the config file), the car sends the newest sample to ABRP
itself at every upload. It tells the server the newest sample ABRP took
(abrpSentUtc), and the server forwards only newer ones, so ABRP gets
each sample once. Without credentials in the app the server forwards
everything, as before. The credentials sit in encrypted storage, go in
the request body, and neither they nor ABRP's answer are logged.

Settings are grouped by what they are for:
- Live data (was Upload): on/off, ABRP credentials, upload frequency.
- Settings (replaces the Wi-Fi tab): full screen and voice key,
  usable capacity and manual SoH (were on Consumption), charging price
  (was on Charging), Wi-Fi.
Charging and Live data get icons of their own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 12:15:21 +02:00
..

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

  1. Check ingress.yaml: Grafana's host (placeholder car-grafana.k8s.stinnesbeck.com). Both routes use the traefik-internal class, and both hosts must be covered by Traefik's default certificate.
  2. Create the Secrets. cp k8s/secrets/secrets.example.yaml k8s/secrets/secrets.yaml (gitignored), replace every CHANGE-ME there (openssl rand -hex 32): influxdb-auth, mg4-server (ingest token, approval password for pairing, your ABRP API key and user token), grafana-admin and grafana-influx (see below). Keep the template itself on placeholders only.
  3. Registry access. The mg4-server package on git.stinnesbeck.com is public, so no pull secret is needed. If you make it private, add an imagePullSecrets entry to server.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:

  1. With InfluxDB running, create the token. The influx CLI 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)"'
    
  2. Copy the "token" value from the output into grafana-influx → token in k8s/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-token in 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 mg4 bucket 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>).