Commit Graph
37 Commits
Author SHA1 Message Date
nilsandClaude Opus 5.5 5e2e354bdd About dialog points to our repository; SPECS status refreshed
The About dialog's link and QR code open
https://git.stinnesbeck.com/nils/mg4 instead of Fatih's GitHub
repository (the credits to upstream stay). SPECS.md: the Status section
describes the current versions and what has and has not been tried on
the car; the architecture notes list the current tabs and data paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 17:42:54 +02:00
nilsandClaude Opus 5.5 727da51a3c App 2.14.2: "Range, 5-min average"
Same form as "Usage, 5-min average" and "Power, 5-min average".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 17:25:35 +02:00
nilsandClaude Opus 5.5 010a0cd50d App 2.14.1: right-aligned values with equal-width digits
The Overview tiles' values (and the notes under them) are right-aligned
and use tabular figures, so a value going from 9 to 10 to 100 grows to
the left instead of shifting the whole text, and digits no longer
change width as they tick. The labels stay left; tyre pressures stay
centred but use tabular figures too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 17:22:22 +02:00
nilsandClaude Opus 5.5 9b5fcc0734 App 2.14.0: accent colour after the MG4 paints; car colour probe
The accent is selectable in Settings → Display: Dynamic Red (default),
Volcano Orange, Holborn Blue, Racing Green, Camden Grey, Monument
Silver, Arctic White and Black Pearl. White, silver and black cannot be
an accent on the black screen as they are, so they become light greys
and a pearl blue-grey.

The accent palette is now theme attributes (attrs_accent.xml) with one
overlay per paint (accents.xml), applied before the activity inflates;
layouts, colour lists, drawables and the views that draw in code use
them, including the red tints that were hard-coded. A change recreates
the activity on the same page. Android 9 crashes on gradients with
theme colours, so the battery card is built from layers.

Logs → "Look for the car colour" lists the head unit's system
properties that mention colour, paint or car model, to find out whether
the paint colour can be read from the car.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 13:52:57 +02:00
nilsandClaude Opus 5.5 40906ec4a7 App 2.13.0: tyre pressures in bar; 5-minute average power
Tyre pressures show in bar by default; Settings → Display offers kPa
and psi as well. Display only: the car reports kPa and the server keeps
storing kPa.

A "Power, 5-min average" card under Power: the time-weighted mean
battery power over the last five minutes, standing included, from the
same samples as the 5-minute range.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 13:26:02 +02:00
nilsandClaude Opus 5.5 66fed48aae App 2.12.1: no scroll bars; energy since start
The pages' scroll bars never faded on the car: a ScrollView shows its
bar on every layout, and the live values lay the page out every two
seconds. StableScrollView, the root of every page, now has none.

A new "Energy since start" tile, left of "Usage since start", shows the
net kWh taken from the pack since the trip began, recuperation counted
back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 13:12:12 +02:00
nilsandClaude Opus 5.5 d711e0cfda App 2.12.0, server 2.5.0: enter settings on the phone
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
2026-10-18 12:59:03 +02:00
nilsandClaude Opus 5.5 9f184362f0 Server 2.4.0, app 2.11.1: ABRP forwarding removed from the server
The car sends live data to ABRP itself, and the car and the server go
over the same mobile connection: when the car cannot reach ABRP, it
cannot reach the server either, so the server's fallback bought
nothing. The forwarder, its ABRP_* settings and abrpSentUtc are gone;
the server only stores. The app stops sending abrpSentUtc (the server
ignores unknown fields, so 2.11.0 keeps working) and its texts no longer
promise a server fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 12:49:46 +02:00
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
nilsandClaude Opus 5.5 087f193f8c App 2.10.2: infinity as the range while recuperating
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 11:01:02 +02:00
nilsandClaude Opus 5.5 3ae1e18a43 App 2.10.1: show negative usage while recuperating
Net regeneration over the window (or the trip) used to hide both
estimates behind "needs a few minutes of driving". It is a real
reading: the usage now shows as negative kWh/100 km, and the range as
"> 999 km" with "while recuperating" beneath it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 10:07:08 +02:00
nilsandClaude Opus 5.5 2a0c4c9675 App 2.10.0: range since start, usage in its own cards
"Range since start" replaces the range at current power: remaining
energy over the consumption since the car was switched on, standing
with the climate on included. A trip starts again after 10 minutes
without samples (the car was off) or when charging.

The kWh/100 km for both estimates moved out of the range tiles into
two cards of their own, directly below them; the overview still fits
the full-screen 1920x720 display without scrolling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 10:01:11 +02:00
nilsandClaude Opus 5.5 a5db5604d3 Code review fixes: app 2.9.0, server 2.2.0
Telemetry no longer loses queued batches. The server drops a bad value,
or a sample without a plausible time, instead of rejecting the batch,
and answers 200 with what it dropped. The app sends only values inside
the server's ranges (speed as a magnitude, so reversing is fine) and no
samples before the head unit's clock is set.

Server:
- Pairing hands out and accepts a token only after the device is saved;
  a failed save leaves the request pending.
- A paired token serves only the installation id it was paired with
  (403 otherwise); the shared INGEST_TOKEN still serves any.
- Wrong-password lockouts and open pairing requests are limited per
  client address (last X-Forwarded-For entry), so a stranger cannot
  lock the owner out; a car starting again replaces its own request.
- ABRP forwarding skips samples stamped ahead of the server's clock,
  which used to stop it until a restart.

App:
- Settings written to plaintext during a keystore failure move back
  into encrypted storage; the stored installation id wins.
- The installation id is derived from ANDROID_ID on first start, so a
  reinstall finds its history; a stored or imported id still wins.
- The scanned config file is deleted after import (it holds the token).
- GPS stops while live telemetry is off or the server unconfigured, and
  pauses while parked and idle, keeping the fix the car parked with.
- Range estimates use the monotonic clock.
- One HTTP helper (ServerHttp) for telemetry, sync and pairing.
- Last Turkish strings translated; mise logs shows the NilsMG4 tags.

Grafana reads InfluxDB with its own read-only token (new grafana-influx
Secret, created by hand as described in k8s/README.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 00:36:19 +02:00
nilsandClaude Opus 5.5 9bebf56b3a Docs: new package ID and APK names
OTA.md, mise.toml and docs/MG4_PLATFORM_INSTALL.md now use
com.stinnesbeck.nilsmg4(.unstable) and NilsMG4-*.apk. OTA.md says the
updater is switched off and that its publishing steps are upstream's
GitHub process; it also drops the old four-part version example.
CHANGELOG.md keeps the old ID as upstream history.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 00:09:52 +02:00
nilsandClaude Opus 5.5 1b918e3c39 App 2.8.2: full screen fills the space the bars leave
On the MG4 the immersive flags hid SAIC's bars but left a black band
where they had been. SYSTEM_UI_FLAG_LAYOUT_STABLE reports the bars'
insets even while they are hidden, and the fitsSystemWindows root
padded itself by them. In full screen the flag is dropped and the root
no longer fits system windows; switching full screen off restores both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 00:00:58 +02:00
nilsandClaude Opus 5.5 8bad5fc024 Three-part version names for the car build
The unstable flavor appended upstream's CI build number as a fourth
part (2.8.0.0-unstable; always .0 without CI). Versions are now the
plain three-part defaultConfig version: 2.8.1-unstable, and build-car
names the APK NilsMG4-unstable-2.8.1.apk. The version code keeps the
x100000 factor (2.8.1 = 6700000): without it the code would fall below
the 6600000 already installed, and the installer refuses downgrades.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 23:55:08 +02:00
nilsandClaude Opus 5.5 3f1e196817 App 2.8.0: full screen
Immersive full screen while the app is in front: the system's top and
bottom bars are hidden, and a swipe from the edge shows them briefly.
Re-applied whenever the window regains focus. A "Full screen" switch in
the Upload tab (default on) turns it off.

On the Android 9 emulator the bars are hidden (system UI flags 0x1706),
stay hidden after leaving and returning, and the switch toggles them
through the UI. Whether SAIC's own bars on the MG4 obey the flags is
only known on the car; if they do not, nothing changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 23:52:33 +02:00
nilsandClaude Opus 5.5 55710fb722 App 2.7.1: voice-key double press works; floating button removed
The car's key report, from the on-screen key log in 2.7.0:
android.intent.extra.hardkey.keycode = 287 (Integer),
android.intent.extra.hardkey.down (Boolean; one report on press, one on
release) and android.intent.extra.hardkey.longpress (Boolean). 2.7.0
only looked for short names like "keyCode", so it never found the code.
SteeringKeyReport now matches extras by the last part of their name,
case-insensitively, and is Android-free; its tests include the exact
double press logged on the car (releases 279 ms apart). Replayed in the
car's format on the emulator: double press opens the app, single and
long presses do not.

The floating button is removed (class, geometry and test, the overlay
permission, setting, switch and strings): it did not show over the MG4
launcher.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 23:38:36 +02:00
nilsandClaude Opus 5.5 af15b15db1 App 2.7.0: voice-key double press opens the app; no scroll jumps
Steering wheel: a double press of the voice key (code 287) opens the
app. The floating button from 2.6.0 does not show over the MG4
launcher, so this is the way back into the app. The head unit reports
keys as the broadcast com.saic.keyevent.hardkey.report, whose extras
are not documented: the receiver tries the usual names (and an
embedded KeyEvent), and counts one press per report whichever way the
up/down field turns out to work; long presses never open the app. The
last 20 reports are listed raw on the Logs tab, so if the guess
misses, a photo of that list gives the real format. A switch in the
Upload tab turns it off. DoublePressDetector (500 ms window) has 5
tests; on the emulator, simulated double presses open the app and
single presses, other keys and long presses do not.

Scrolling: pages jumped back to the top on every 2 s refresh. A stack
trace on the emulator showed why: ViewPager2's RecyclerView lays the
pages out while measuring, at a provisional height, and
ScrollView.onLayout clamps the position to 0. StableScrollView keeps
the driver's position across layouts and is now the root of every
page; the scrolled Charging page stays put across refreshes.

Vehicle tab: all six value tiles, including both range estimates, sit
in one row at the top, so nothing needs scrolling at 1920x720.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 23:24:48 +02:00
nilsandClaude Opus 5.5 fde963533d Head unit is 1920x720, not 1920x1080
FIRMWARE.md, the mise emulator profile and SPECS.md said 1920x1080.
The MG4's display is 1920x720 at 160 dpi (an app window has been seen
at 1778x720, the car's sidebar taking the rest). The floating button's
geometry test now uses 1920x720.

The app itself assumed no height: checked on an Android 9 emulator at
1920x720, all tabs render (longer ones scroll), the sidebar holds all
seven tabs, and the floating button starts at 1840,312.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 22:58:28 +02:00
nilsandClaude Opus 5.5 11d53e7bc7 App 2.6.0: floating button to open the app
The MG4's launcher does not list third-party apps, so the app could
only be opened by reinstalling it. Now a small round MG-red button
floats over the car's screens: tap opens the app, drag moves it (the
position is kept and clamped to the screen), and it hides while the
app itself is open. A switch in the Upload tab turns it off.

The always-on service owns the overlay, so the button is there from
boot. It needs the overlay permission (SYSTEM_ALERT_WINDOW), which the
car build has through the system UID; without it, or if the window
manager refuses, the button stays away and nothing crashes, and the
Upload tab offers the system permission screen.

Tested on an Android 9 AOSP emulator at the head unit's 1920x1080 /
160 dpi with the car APK (installs as UID 1000): button appears over
the home screen, tap opens the app, hidden while open, drag moves it
without opening the app, position survives a force-stop, the switch
works through the UI. FloatingButtonGeometry has 3 unit tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 22:55:15 +02:00
nilsandClaude Opus 5.5 582c084b35 Live dashboard: show what the car sends, compute pack energy
The car publishes no battery, cabin or outside temperature and no pack
energy (checked against the fields that reached InfluxDB). Instead of
panels that stay empty:

- Battery temperature tile -> Climate setpoint.
- Outside temperature tile -> Last update ("2 minutes ago").
- Energy in pack = SOC x usable capacity, from the hidden dashboard
  constant usableKwh = 50.8 (51 kWh battery).
- Temperatures chart -> Battery voltage and current.

Checked with a simulated drive carrying exactly the car's fields: all
11 panels return data, energy matches 61 % x 50.8 kWh. SPECS.md lists
the missing signals and why.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 22:17:41 +02:00
nilsandClaude Opus 5.5 f3de272c69 Grafana: map zooms to the route; plain hyphens in titles
- "Where the car was" fits the route again: in Grafana's fit view the
  zoom value is the maximum zoom, and 6 held it at country level. Now
  15 with 10 % padding. Checked by rendering the Live dashboard with a
  simulated 10 km drive.
- Dashboard titles use "-" instead of an em dash: "MG4 - Live",
  "MG4 - Consumption", "MG4 - Charging".
- SPECS.md: Grafana keeps its state in SQLite on its PVC, which is why
  it runs as one replica with Recreate; high availability needs
  PostgreSQL or MySQL first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 21:59:17 +02:00
nilsandClaude Opus 5.5 84fb3aac21 k8s: work with kubectl apply -f as well as -k
- The secrets template moves to k8s/secrets/, and the filled-in copy to
  k8s/secrets/secrets.yaml (gitignored). `kubectl apply -f k8s/` does
  not recurse, so neither the placeholder template nor the real secrets
  can be applied by accident.
- The server image digest is pinned in server.yaml instead of through
  kustomize's images override, which `-f` ignores (it would have pulled
  a nonexistent :latest).
- README and kustomization.yaml say to use `-k`: plain `-f` never
  creates the generated Grafana ConfigMaps.
- The IngressRoutes drop `tls: {}`, like the other routes on this
  Traefik: TLS is configured on the websecure entrypoint.

Manifests validated both ways (14 resources rendered with kustomize,
11 as plain files — the difference is the Grafana ConfigMaps).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 21:36:17 +02:00
nilsandClaude Opus 5.5 6f57351866 Use the traefik-internal ingress class
Both IngressRoutes (server and Grafana) now use traefik-internal, like
the rest of *.k8s.stinnesbeck.com, instead of the traefik-external
placeholder. README and SPECS updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 18:16:52 +02:00
nilsandClaude Opus 5.5 315586f94c Move the server to car.k8s.stinnesbeck.com
The server's host is car.k8s.stinnesbeck.com, not car.stinnesbeck.com:
IngressRoute, PUBLIC_URL (so the pairing QR code points there), the
app's pre-filled server URL and hint, and the docs. Grafana's
placeholder host follows to car-grafana.k8s.stinnesbeck.com, so one
*.k8s.stinnesbeck.com default certificate covers both. App 2.4.1 for the
new default; the server image is unchanged (its URL comes from the
manifest).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 18:08:35 +02:00
nilsandClaude Opus 5.5 59ee2cae3b Deploy server 2.1.0; keep filled-in secrets out of git
- kustomization pins mg4-server 2.1.0 by digest; server.yaml sets
  PUBLIC_URL for the pairing QR code; the secrets template gains
  APPROVAL_PASSWORD.
- Filled-in Secrets now go into k8s/secrets.yaml, which is gitignored;
  the template stays on placeholders. This follows a leak where real
  values typed into the template were committed and pushed (amended and
  force-pushed since; both values regenerated).
- SPECS.md records pairing and the incident.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 16:16:52 +02:00
nilsandClaude Opus 5.5 4fe29189c0 Pin the pushed server image; drop the pull secret
mg4-server:2.0.0 is on git.stinnesbeck.com and pulls anonymously, so
the Deployment no longer references a registry pull secret. The image
is pinned by digest (sha256:6feea777…) so a re-pushed tag cannot
change what the cluster runs. README and secrets template updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 16:14:53 +02:00
nilsandClaude Opus 5.5 5473ab1c2b Dashboards in Grafana; clean up after the Next.js app
- k8s/grafana.yaml: Grafana 13.2.3 with a 1Gi PVC, sign-up and
  anonymous access off. The InfluxDB datasource (URL and token from the
  environment) and three dashboards — Live, Consumption, Charging — are
  provisioned from k8s/grafana/ via kustomize-generated ConfigMaps.
- server.yaml for the Go server (port 8080, UID 65532, smaller limits),
  image tag 2.0.0. The NetworkPolicy now admits Grafana to InfluxDB.
- ingress.yaml: IngressRoutes for car.stinnesbeck.com and Grafana
  (placeholder host car-grafana.stinnesbeck.com) with tls: {}, using
  Traefik's default certificate; the cert-manager Certificate is gone.
- secrets.example.yaml: drops the dashboard secrets, adds grafana-admin.
- AGENTS.md loses its Next.js block; SPECS.md describes the new setup.

The removal of web/ (the Next.js app) and of the stale .next/ cache
upstream had committed already landed in 51e6f6f, which was staged
together with the Go server by mistake.

Checked end to end in podman (Go server + InfluxDB 2.7.12 + Grafana
13.2.3): all 25 dashboard queries return the expected data, and the
dashboards were rendered with headless Chromium. Manifests validated
offline with kustomize and kubeconform. Nothing applied to a cluster.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 15:18:09 +02:00
nilsandClaude Opus 5.5 538d03361d Translate the dashboard to English; euro instead of lira
Dashboard: every label, empty state, chart legend and the login page
are English; numbers and dates use en-GB (24-hour clock, day-month
dates), money is EUR, percentages read 80% instead of %80, durations
"2 h 05 min". html lang is en. Server version 1.1.2; manifests pin it.

Car app: the charging tab's price suffix, validation message and total
cost use € instead of ₺.

Checked by rendering all three pages from the 1.1.2 image against
InfluxDB 2.7.12 in podman.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 14:39:59 +02:00
nilsandClaude Opus 5.5 818442db08 Rename the web app from FatihsMG4 to Nils' MG4
Browser title, login heading, hidden password-manager username, session
cookie (nilsmg4_session) and package name. The README keeps the credit
to fatihdonmezdev/FatihsMG4. Server version 1.1.1; the manifests pin it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-17 14:34:16 +02:00
nilsandClaude Opus 5.5 6145736c97 App 2.3.0: Server tab, live telemetry to the car server
- New Server tab: server URL, ingest token and installation id, with
  Save, Test connection (health, then a read-only token check) and the
  config-file import that upstream removed (app folder / USB stick first,
  document picker as fallback). Settings are kept encrypted and read on
  every use, so the service picks up a change without a restart. Each
  installation generates its own id; the inherited upstream UUID and
  the baked-in CONSUMPTION_API_* build fields are gone.
- Live telemetry restored from before ea8032a (TelemetryPayload,
  UploadCadence, UploadSettings, GPS) and sent in batches to
  POST /v1/telemetry instead of ABRP; the server forwards to ABRP. Adds
  ext_temp, voltage and current. Unsent samples queue in memory (about
  8 h) while offline.
- Upload tab: the live-telemetry switch and cadence controls work again;
  the dead service and autostart switches are removed.
- Manifest: location permissions and foreground service types.
- Unit tests compile again: 114 (stable) / 136 (unstable) pass. Tests
  for the deleted AbrpApi and HeadUnitWeather removed; new tests for
  ServerConfig and TelemetryQueue. Lint passes.

Not yet tried on the car.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 14:23:04 +02:00
nilsandClaude Opus 5.5 d4fb4ba3af Plan the car server (InfluxDB 2, ABRP forwarder, k8s manifests) in SPECS.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:51:07 +02:00
nilsandClaude Opus 5.5 de2428786a Journal diagnostics and upstream ABRP removal in SPECS.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:38:47 +02:00
nilsandClaude Opus 5.5 10029623e3 Remove on-screen diagnostics from the Logs tab
They served their purpose: vehicle values show on the car. This reverts
commit b2a5b32.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:38:36 +02:00
nilsandClaude Opus 5.5 b2a5b32b08 Add on-screen diagnostics to the Logs tab
Without adb there was no way to see why vehicle values stay blank:
refreshVehicle() swallowed every exception. The Logs tab now shows the
package, version, UID (and whether it is the system UID), signer
SHA-256, firmware, car permission grants, the last snapshot and read
error, and the newest 200 entries of the vehicle library's AppLogger.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:26:39 +02:00
nilsandClaude Opus 5.5 a707b590f7 Rename package and APKs to NilsMG4, credit Fatih, add SPECS.md
- 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>
2026-10-17 13:08:09 +02:00