README: current tabs, updating, emulator; screenshots of all tabs from 2.18.1

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
This commit is contained in:
2026-10-18 23:42:16 +02:00
co-authored by Claude Opus 5.5
parent 496fb821c3
commit 31ea4e7d78
15 changed files with 52 additions and 19 deletions
+2 -2
View File
@@ -10,7 +10,7 @@ build-car ─▶ publish-car ─▶ forge pre-release (private repo, git.stinnes
car server /v1/app/releases, /v1/app/assets/… car server /v1/app/releases, /v1/app/assets/…
│ the car's own paired token │ the car's own paired token
▼ ▼
app: refresh button → check → SHA-256 → install app: Settings → Check for updates → SHA-256 → install
``` ```
The repository stays private and the forge token stays on the server: the car asks its own The repository stays private and the forge token stays on the server: the car asks its own
@@ -51,7 +51,7 @@ The version comes from the **asset file name**, not the tag.
## Installing ## Installing
Press the refresh button in the app's top bar. The app checks, downloads the APK into Press **Check for updates** on the Settings tab. The app checks, downloads the APK into
**Downloads** (with progress), verifies its SHA-256, and hands it to a `PackageInstaller` **Downloads** (with progress), verifies its SHA-256, and hands it to a `PackageInstaller`
session. As the system user it may install without asking; if the platform wants a session. As the system user it may install without asking; if the platform wants a
confirmation, the confirmation screen opens. When a session cannot start at all, the file confirmation, the confirmation screen opens. When a session cannot start at all, the file
+46 -17
View File
@@ -25,7 +25,7 @@ APIs.
## Contents ## Contents
- [Screenshot](#screenshot) - [Screenshots](#screenshots)
- [How it fits together](#how-it-fits-together) - [How it fits together](#how-it-fits-together)
- [The app](#the-app) - [The app](#the-app)
- [Install on the car](#install-on-the-car) - [Install on the car](#install-on-the-car)
@@ -36,15 +36,31 @@ APIs.
- [Project documents](#project-documents) - [Project documents](#project-documents)
- [Credits](#credits) - [Credits](#credits)
## Screenshot ## Screenshots
Version 2.8.2 at the head unit's 1920x720 pixels and 160 dpi, in full screen (Android 9 emulator; no Version 2.18.1 in the car's app window (1778×640 dp next to the MG4's own sidebar), full screen,
vehicle there, so every value shows as a dash). on the Android 9 emulator. There is no vehicle there, so every value shows as a dash. Every tab
fits the window without scrolling.
<p align="center"> <p align="center">
<img src="screenshots/nilsmg4-2.8.2-overview.png" width="900" alt="Overview tab: battery, range, range estimates, power and speed tiles above the energy and tyre-pressure cards"> <img src="screenshots/nilsmg4-2.18.1-overview.png" width="900" alt="Overview tab: battery, range, power and speed tiles with since-start and 5-minute averages, vehicle info and tyre pressures">
</p> </p>
<table>
<tr>
<td><img src="screenshots/nilsmg4-2.18.1-consumption.png" width="440" alt="Consumption tab: period totals beside the daily log"></td>
<td><img src="screenshots/nilsmg4-2.18.1-charging.png" width="440" alt="Charging tab: live charging values beside the SOC/power curve"></td>
</tr>
<tr>
<td><img src="screenshots/nilsmg4-2.18.1-live-data.png" width="440" alt="Live data tab: on/off, ABRP credentials, upload frequency"></td>
<td><img src="screenshots/nilsmg4-2.18.1-server.png" width="440" alt="Server tab: URL, pairing, ingest token, installation ID"></td>
</tr>
<tr>
<td><img src="screenshots/nilsmg4-2.18.1-settings.png" width="440" alt="Settings tab: display, battery, charging price, phone entry, app updates"></td>
<td><img src="screenshots/nilsmg4-2.18.1-logs.png" width="440" alt="Logs tab: recent uploads"></td>
</tr>
</table>
## How it fits together ## How it fits together
``` ```
@@ -63,12 +79,12 @@ with the server using a token of its own, obtained by pairing with a phone (belo
| Tab | What it shows | | Tab | What it shows |
|---|---| |---|---|
| **Overview** | Battery, range, range since start and at the 5-minute average with their usage, energy since start, power and speed with their 5-minute averages; odometer, climate setpoint and tyre pressures | | **Overview** | Battery, range, power and speed; range, usage and energy since start; 5-minute averages of range, usage, power and speed; vehicle info (odometer, climate setpoint) and tyre pressures. Read every half second |
| **Consumption** | Daily and period consumption, efficiency | | **Consumption** | Lifetime, last 7 and 30 days, Trip A and B (distance, energy, average consumption and speed, SOC change), and a daily log of the last four months |
| **Charging** | Charging sessions and curves, cost in euro | | **Charging** | The current session (SOC, voltage, current, power, energy into the battery and from the grid, time, cost) and its SOC/power curve |
| **Live data** | Live data on/off, ABRP credentials for sending directly from the car, upload frequency | | **Live data** | Live data on/off, ABRP credentials for sending directly from the car, upload frequency |
| **Server** | Server URL, pairing by QR code, ingest token, installation ID, config import | | **Server** | Server URL, pairing by QR code, ingest token, installation ID, config import |
| **Settings** | Full screen, voice key, tyre pressure unit, accent colour, battery (usable capacity, manual SoH), charging price, version, update check, About | | **Settings** | Full screen, voice key, tyre pressure unit, accent colour, battery (manual SoH, usable capacity), charging price, entry on the phone, version, update check, install from USB stick, About |
| **Logs** | Upload log | | **Logs** | Upload log |
- **Opening the app:** the MG4 launcher does not list third-party apps. **Double-press the - **Opening the app:** the MG4 launcher does not list third-party apps. **Double-press the
@@ -107,9 +123,15 @@ adb shell "pm install -r -f -d -t /data/local/tmp/update.apk"
> ⚠️ Do this **parked**, and only with an APK you trust. See [DISCLAIMER.md](DISCLAIMER.md). > ⚠️ Do this **parked**, and only with an APK you trust. See [DISCLAIMER.md](DISCLAIMER.md).
After that first install, the app updates itself: publish a build with `publish-car`, then After that first install, the app updates itself, two ways (details in [`OTA.md`](OTA.md)):
press the refresh button in the app's top bar (`OTA.md`). The car fetches it through your car
server, so the repository stays private. - **Over the air:** publish a build with `publish-car`, then press **Check for updates** on the
Settings tab. The car fetches it through your car server, which relays the forge's release, so
the car never holds a forge credential.
- **From a USB stick:** copy `NilsMG4-unstable-<version>.apk` and its `.sha256` from `build/car/`
to the stick's top folder and press **Install from USB stick** on the Settings tab.
Either way the app checks the SHA-256, the package and the signature before installing.
## Setup ## Setup
@@ -122,7 +144,7 @@ server, so the repository stays private.
### On your phone ### On your phone
Once the car is paired, **Enter on phone** (Live data tab, and Settings → Charging price) shows a Once the car is paired, **Enter on phone** (Live data tab, and Settings → On your phone) shows a
QR code. It opens a form on your server where you type the ABRP API key and user token, the QR code. It opens a form on your server where you type the ABRP API key and user token, the
charging price and the usable capacity, and send them with the approval password. The car charging price and the usable capacity, and send them with the approval password. The car
collects them within a few seconds and saves them through the same checks as the fields on collects them within a few seconds and saves them through the same checks as the fields on
@@ -186,13 +208,19 @@ Tests and lint:
./gradlew testStableDebugUnitTest testUnstableDebugUnitTest lintStableDebug ./gradlew testStableDebugUnitTest testUnstableDebugUnitTest lintStableDebug
``` ```
A head-unit emulator for checking layouts and installs: `nix run .#car-emulator` (add
`-no-window` for headless) starts Android 9 at 1920×720 and 160 dpi. It is signed with the same
platform key as the car, so the car build installs there as the system user;
`adb shell wm size 1778x640` gives the car's app window. It has no vehicle, so values stay "—".
[`mise`](https://mise.jdx.dev) tasks from upstream (`mise run check`, `mise run build`) still [`mise`](https://mise.jdx.dev) tasks from upstream (`mise run check`, `mise run build`) still
work for the plain Gradle builds. work for the plain Gradle builds.
## Server and dashboards ## Server and dashboards
- **Server** ([`server/`](server/README.md)): Go, API only. Live telemetry, daily consumption - **Server** ([`server/`](server/README.md)): Go, API only. Live telemetry, daily consumption
chunks, charging sessions, pairing. Image at chunks, charging sessions, pairing, settings entered on a phone, and the release relay for the
in-app updater. Image at
`git.stinnesbeck.com/nils/mg4-server`. `git.stinnesbeck.com/nils/mg4-server`.
- **Kubernetes** ([`k8s/`](k8s/README.md)): plain manifests for the server, InfluxDB 2 and - **Kubernetes** ([`k8s/`](k8s/README.md)): plain manifests for the server, InfluxDB 2 and
Grafana, applied by hand with `kubectl apply -k k8s/`. Secrets go in the gitignored Grafana, applied by hand with `kubectl apply -k k8s/`. Secrets go in the gitignored
@@ -205,13 +233,13 @@ work for the plain Gradle builds.
``` ```
app/src/main app: upload service, server client, pairing, UI app/src/main app: upload service, server client, pairing, UI
app/src/stable no-op update hook (no updater in the APK) app/src/stable no-op update hook (no updater in the APK)
app/src/unstable car build: system UID, updater (currently pointed nowhere) app/src/unstable car build: system UID, updater (via the car server) and USB install
app/src/debug VHAL probe tools, absent from release builds app/src/debug VHAL probe tools, absent from release builds
app/src/test JVM unit tests app/src/test JVM unit tests
EVHardware shared vehicle reads per firmware generation EVHardware shared vehicle reads per firmware generation
server/ Go server server/ Go server
k8s/ Kubernetes manifests and Grafana provisioning k8s/ Kubernetes manifests and Grafana provisioning
flake.nix dev shell and build-car flake.nix dev shell, build-car, publish-car, car-emulator
``` ```
## Project documents ## Project documents
@@ -219,8 +247,9 @@ flake.nix dev shell and build-car
| Document | What it covers | | Document | What it covers |
|---|---| |---|---|
| [SPECS.md](SPECS.md) | Journal of this fork: architecture, status, to-dos, done log | | [SPECS.md](SPECS.md) | Journal of this fork: architecture, status, to-dos, done log |
| [OTA.md](OTA.md) | Publishing releases, the updater's checks, USB install |
| [FIRMWARE.md](FIRMWARE.md) | MG4 firmware generations and how the app reads each | | [FIRMWARE.md](FIRMWARE.md) | MG4 firmware generations and how the app reads each |
| [AGENTS.md](AGENTS.md) | Context for AI agents working in this repository | | [AGENTS.md](AGENTS.md) | Overview of the repository for AI agents and new contributors |
| [DESIGN.md](DESIGN.md) | The EVSuite design system (the app overrides its palette) | | [DESIGN.md](DESIGN.md) | The EVSuite design system (the app overrides its palette) |
| [SECURITY.md](SECURITY.md) | Threat model | | [SECURITY.md](SECURITY.md) | Threat model |
| [DISCLAIMER.md](DISCLAIMER.md) | Vehicle-safety disclaimer; read before installing | | [DISCLAIMER.md](DISCLAIMER.md) | Vehicle-safety disclaimer; read before installing |
+4
View File
@@ -118,6 +118,10 @@ tyre pressures, GPS (lat, lon, elevation, heading) and the is_* flags. It does *
confirmed car facts, app structure, UI conventions, build/test/ship, documents. It replaces confirmed car facts, app structure, UI conventions, build/test/ship, documents. It replaces
upstream's EVABRPUploader text. The test emulator is now in the flake: `nix run .#car-emulator` upstream's EVABRPUploader text. The test emulator is now in the flake: `nix run .#car-emulator`
(Android 9 AOSP at 1920×720, 160 dpi; the car build installs as the system user — checked). (Android 9 AOSP at 1920×720, 160 dpi; the car build installs as the system user — checked).
- 2026-10-18 — README brought up to date: screenshots of all seven tabs from 2.18.1 at the car's
1778×640 window (the upstream and 2.8.2 screenshots are gone), tab descriptions, updating over
the air and from a USB stick, the emulator, the release relay. OTA.md: updates are checked from
Settings, no longer from a top-bar button.
- 2026-10-18 — App 2.18.1: every tab fits the car's window (1778×640 dp) without scrolling — checked - 2026-10-18 — App 2.18.1: every tab fits the car's window (1778×640 dp) without scrolling — checked
on the emulator by swiping each page and comparing screenshots. Charging and Consumption get wide on the emulator by swiping each page and comparing screenshots. Charging and Consumption get wide
layouts with two columns (values | curve; period totals | daily log and storage note); the curve layouts with two columns (values | curve; period totals | daily log and storage note); the curve
Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB