Read-only energy dashboard and local trip analyser for the SAIC MG4. The workspace
AGENTS.md and normative workspace DESIGN.md apply; this file adds only ChargePilot's
product boundary and commands.
Commit author: malys.training@gmail.com.
License exception: EVChargePilot's own sources use PolyForm Noncommercial 1.0.0, not the workspace MIT default. EVHardware remains separately licensed.
- EVChargePilot reads vehicle state and writes its bounded trip/export files in app-private storage. A diagnostic report may additionally be written only after an explicit parked-user choice to a removable USB volume; it is bounded, atomic and never targets internal AAOS storage as a fallback.
- It never changes a vehicle setting, controls charging, exposes a remote command surface, draws an overlay, or silently opens another application.
- Vehicle property ids, service descriptors, transaction codes and firmware routing belong in standalone EVHardware. This app consumes typed EVHardware APIs only.
- Missing telemetry remains
nullthrough acquisition, calculation and presentation. The UI renders an em dash and explains the unavailable source; it never substitutes zero. - Measured, derived and estimated values must be visibly named. A model may not be labelled as a vehicle measurement.
- The live dashboard is passive while moving. Trip start/stop controls are enabled only when a readable speed is at or below 0.1 km/h.
- No driver-facing overlay is permitted.
- Preserve the asymmetric instrument + rail layout: SOC is the single display-sized value; secondary measurements must not compete with it.
- Follow the workspace
DESIGN.mdexactly. Resources synchronized fromtools/tokens/are generated copies and must not be edited locally.
EnergyTelemetryReader, snapshots, trip integration and persistence are owned by EVHardware and must remain JVM-tested there; do not fork them into this app.- Integrate only adjacent samples no more than five seconds apart. A larger gap represents unknown motion/energy and must not be filled by extrapolation.
- Energy and consumption remain null until at least one valid power interval exists.
- Climate telemetry is passive state, not energy consumption. Keep every climate field nullable, evidence-gate battery temperature per firmware, and never derive HVAC power from an on/off state or fan setting.
- The app owns only sampling cadence, lifecycle and presentation.
- The stable manifest has no overlay, install or boot capability.
INTERNETandACCESS_FINE/COARSE_LOCATIONare declared for route planning only, under CP-043 (analysis/CP-043_network_and_location.md): one HTTP entry point (RoutingTransport),httpsplus a single-host allowlist on the initial URL and every redirect hop, the key in a header and never a query string, no key in the APK, and no telemetry, trip or identifier on the wire. Any second socket or any widening of that payload is a security review, not a patch. - USB diagnostic export adds no storage permission: offer every mounted volume the app can already list except primary emulated storage, and fall back only to this app's directory on the same volume. Never require positive proof that a volume is removable — this head unit cannot give it, and demanding it is why exports found nothing.
- The unstable channel checks GitHub's rolling
unstablepre-release only after the driver double-taps the version on the Energy dashboard, then downloads a newer APK (app/src/unstable/.../update/). It is the second HTTP entry point and stays inside the same rules:httpsplus an exact-match host allowlist on the initial URL and every redirect hop, a size ceiling on the declared and the transferred length, and the archive only reaches shared storage after its signing certificate is proven identical to the running app's. It installs nothing — noREQUEST_INSTALL_PACKAGES, nopm install, no system UID — and the verified APK is written to the head unit'sDownloadfolder. That write is the one reason this app declaresWRITE_EXTERNAL_STORAGE, in the unstable manifest only, capped atmaxSdkVersion=28and requested at runtime from the dashboard; a refusal falls back to this app's ownDownloaddirectory on the same volume, the same shape the USB export uses, and the dialog names whichever path was used. Stable declares neither the permission nor any of that code. The USB diagnostic export still adds no storage permission and must not start. - Any new permission requires an allowlist change and a security review in the same commit.
- Signing configuration comes only from environment variables or local Gradle properties.
Run mise run test, mise run lint, or mise run build. mise run emulator-setup creates
the complementary emulator-car (Automotive API 33) and emulator-screen (API 28,
1920×1080 panel with a 1920×720 app viewport) profiles; mise run run installs and
launches the debug APK. JDK 17 and Android
SDK 36 are used for compilation; the deployed minimum remains API 28. Emulator checks do
not replace a vehicle pass on each supported firmware generation.
- The implemented baseline is the passive dashboard, nullable shared energy snapshot,
automatic foreground trip detection/recording with parked-only manual controls, bounded
atomic trip history, crash diagnostics, stable/unstable variants, CI gates and the two
emulator profiles documented in
README.md. - Arrival-SOC prediction, charger routing and energy attribution are not implemented. Treat each as a separately scoped milestone with explicit evidence for every input; do not fill missing vehicle signals with inferred measurements.
- Start app work by checking
git statusand the EVHardware submodule branch. Any shared telemetry model, property, unit, fallback or integration change starts in the standalone../EVHardwarerepository, is tested and pushed there, then reaches this app through a submodule pointer update. Never develop library changes inside the nested checkout. - Before handing off a change, run
mise run checkandmise run build. For UI/lifecycle work, also run the API 28 screen emulator on its 1920×1080 panel with the target 1920×720 app viewport; for vehicle interfaces, record the remaining on-vehicle validation requirement rather than claiming emulator coverage.