Commit Graph
30 Commits
Author SHA1 Message Date
nilsandClaude Opus 5.5 ce2ebd7f58 App 2.33.0: set the drive mode from Settings, only in P at a standstill
The owner lifted the read-only rule for the drive mode alone. Settings
has Eco, Normal, Sport, Snow and Custom; the lit button is what the car
reports. A tap reads gear and speed fresh and writes only in P at 0 km/h
(DriveModeWrite, unit-tested; unreadable is a refusal), through a CPM-only
write behind EVHardware's standstill gate, then reads the mode back and
says what the car reports. The wide layout's charging price joined the
battery card so the page still fits. Not tried on the car.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-25 20:02:53 +01:00
nilsandClaude Opus 5.5 4cd5f7a7ba App 2.31.0: full screen from the navigation, swipe in from the left to return
The Overview's full-screen button moved from the page's corner into the
navigation, beside the MG4 logo. A swipe in from the left edge (EdgeSwipe,
unit-tested) brings the navigation back; a faint handle marks the edge.
Sideways swipes no longer change the page: only the navigation does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-25 08:53:41 +01:00
nilsandClaude Opus 5.5 4a1f178b5c App 2.30.0: a chibi fox as the third Mascot
FoxFigure draws a sitting fox with a scarf in the accent colour whose
ears and tail act the mood with the face: wagging, stiff, drooping,
laid back. The chibi's shared parts (frame, eyes, mouths, limbs by
mood, effects) moved into ChibiBase, which both figures extend.
Settings → Mascot: Classic / Chibi / Fox.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-24 23:28:16 +02:00
nilsandClaude Opus 5.5 7df1930edd App 2.29.0: a chibi Mascot, chosen in Settings beside the tyre unit
ChibiFigure draws a small, full-figure co-pilot in a hoodie whose whole
body acts the mood (waving, arms up and hopping, fist, hands on cheeks,
nose bubble, pointing back, leaning into the wind). Settings → Mascot
(Classic / Chibi, MascotCharacter) shows only for the Mascot style; the
chibi has lines of her own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-24 23:17:21 +02:00
nilsandClaude Opus 5.5 57cabfa0e1 App 2.28.0: Overview style Mascot, an anime co-pilot who reacts to the drive
MascotView draws her head and shoulders beside speed, gear, battery,
power, usage and trip. MascotMood picks her expression from the reading
(waiting, reverse, worried, asleep, cheering, determined, fast, content)
and holds a new mood for 1.5 s so values at a threshold do not make her
flicker. A speech bubble carries a line per mood.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-24 23:07:50 +02:00
nilsandClaude Opus 5.5 1c85fd2d9f App 2.27.2: Terminal in the accent colour; Original as a colour choice
Retro and Terminal are one entry each; the accent colour drop-down
offers "Original" first for them, remembered per style. The old
"Retro (accent colour)" entry is folded in and its stored value
migrated. Emulator only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-24 21:38:01 +02:00
nilsandClaude Opus 5.5 4ef386a8d9 App 2.27.0: full-width Overview, a button hides the navigation
A small button in the Overview's top-right corner hides the app's
sidebar (or bottom bar) and brings it back; only on the Overview,
remembered, swiping still works. Emulator only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-24 21:21:53 +02:00
nilsandClaude Opus 5.5 7902d8f941 App 2.26.0: Overview styles Minimal, Terminal, Aviation, Nixie, Chronograph
Five more styles that differ in arrangement as well as look: the speed
alone with hairlines; a green text terminal with ASCII bars; a flight
display with tapes and a horizon that pitches with power; nixie tubes on
walnut and brass; a watch face with sub-dials. They share a new base,
ClusterCanvasView. Emulator only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-24 20:47:43 +02:00
nilsandClaude Opus 5.5 1af5b0efe7 App 2.25.0: Overview style MG, octagonal dials
After the classic MG dashboards: three octagonal dials with chrome
bezels, cream scales and accent-coloured needles for speed, battery and
power, and a cream line of odometer, trip, usage, climate and clock.
No MG logo. Emulator only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-24 20:31:47 +02:00
nilsandClaude Opus 5.5 5fb367d7cd App 2.24.0: Overview styles Sci-fi, Cartoon and Blueprint
Sci-fi: a starship console with elbow frames, pill labels and block
graphs, red alert below 20 %. Cartoon: comic panels, a battery with a
face, a springy speedometer and sound words for power. Blueprint: a
top-view drawing with the battery hatched to the charge, tyre pressures
on leader lines, power as a force arrow and a title block. Styles are
now mapped to panes in a table. Emulator only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-24 20:08:24 +02:00
nilsandClaude Opus 5.5 2879c43e26 App 2.23.1: Retro style also in the accent colour
"Retro (accent colour)" draws the display in the chosen paint colour
and the labels in its light shade; regeneration stays green, a low
battery turns amber. Listed under Retro. Emulator only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-24 19:51:08 +02:00
nilsandClaude Opus 5.5 d9f6e368cf App 2.23.0: Overview styles Retro and Futuristic; read every 0.2 s
Retro: an 80s vacuum fluorescent cluster with seven-segment digits,
bar graphs and a lit P R N D selector. Futuristic: a hairline HUD with
an animated energy flow between battery and wheel, a turning speed ring
and a power arc. Both show unread values as dashes. The Overview now
reads the car five times a second. Emulator only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-24 19:32:07 +02:00
nilsandClaude Opus 5.5 71aceaa626 App 2.19.9: remove the Foreground apps card from the Logs tab
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-23 22:20:18 +02:00
nilsandClaude Opus 5.5 e6f8258203 App 2.19.6: remove the CarPlay full-screen switch and the export button
CarPlay's 1920x640 is fixed in Allgo's system app. On start the car
build removes the CarPlay entry from policy_control if the switch was
left on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-23 22:02:15 +02:00
nilsandClaude Opus 5.5 50217aef74 App 2.19.2: Full screen for CarPlay (experiment)
Adds com.allgo.carplay.service to immersive.full in Android 9's
policy_control setting when switched on, removes only that entry when
off. Car build (system user) only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
2026-10-23 20:50:35 +02:00
nilsandClaude Opus 5.5 31ea4e7d78 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
2026-10-18 23:42:16 +02:00
nilsandClaude Opus 5.5 851a4a34d4 App 2.17.1: tidier Settings and Logs
- Settings: the Wi-Fi and saved-networks cards are gone, and the rest
  sits in three columns (display and steering wheel | battery |
  charging price and app) instead of one tall column. The background
  Wi-Fi auto-connect stays on, without a switch.
- Logs: only the upload log. The steering-key reports, the car-colour
  probe and the screen line answered their questions and are removed,
  with their code (CarColorProbe, the key-report log) and strings.
- README lists the current tabs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 20:32:01 +02:00
nilsandClaude Opus 5.5 bfa33d51bd App 2.16.2: show the car's screen size; display figures documented
The MG4's display is given as 1920x720 (this project), 1280x480
(EVProfile's README) and a 1778x720 app window (upstream). 1280x480 is
exactly 1920x720 px at 240 dpi expressed in dp, so the figures may
describe one panel at different densities, which this platform lets be
changed per app.

The Logs tab's new SCREEN line shows the panel's pixels and density and
the app window in px and dp, to settle it from the car. FIRMWARE.md
lists the three figures and what the emulator shows at 240 dpi;
mise.toml, README and SPECS.md no longer state 160 dpi as fact for the
car.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 19:50:24 +02:00
nilsandClaude Opus 5.5 a293a0fa94 Licence: the original is MIT; EVHardware is noncommercial
Leon Kernan's ABRP_Uploader has carried the MIT Licence since
2026-07-29 (lkernan/ABRP_Uploader commit 75d8f2bc), so the inherited
"no licence upstream, status unresolved" notes no longer hold.

- LICENSE: MIT, now naming every copyright holder in the fork chain
  (Leon Kernan, EVABRPUploader contributors, FatihsMG4 contributors,
  Nils Stinnesbeck).
- LICENSE.md: rewritten. The repository is MIT except EVHardware/,
  which is PolyForm Noncommercial 1.0.0; the app links it into the APK,
  so the built app is non-commercial. EVHardware's own caveat about
  EVProfile stays with it.
- README, AGENTS.md, CONTRIBUTING.md and SPECS.md say the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 19:38:21 +02:00
nilsandClaude Opus 5.5 e5549dddb0 App 2.16.0, server 2.6.0: over-the-air updates from our own repository
The car updates itself again, from this fork's own releases, while the
repository stays private:

- publish-car (flake) creates the pre-release car-<version> on the
  forge and attaches the APK and its .sha256. It needs a forge token
  that may write releases, from ~/.config/nilsmg4/forge-token or
  $FORGE_TOKEN; it is sent in a header and never printed.
- The server relays releases and attachments (/v1/app/releases,
  /v1/app/assets/...), read with a read-only FORGE_TOKEN from its
  Secret, GitHub-shaped with download URLs back at itself. Redirects
  away from the forge are not followed; off (404) without a token.
- The app asks its server with its own paired token, allows exactly
  the server's host, downloads the APK itself instead of through the
  DownloadManager (so the token stays in the app), verifies SHA-256 and
  package name, and tries a PackageInstaller session (it may install
  silently as the system user) before falling back to Downloads.

OTA.md is rewritten for this flow; the k8s and server READMEs explain
the new token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 18:08:08 +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 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 4b858e3c35 README for Nils' MG4
Rewritten for this fork: the car server, InfluxDB and Grafana setup,
pairing by QR code, the app's tabs, voice-key opening and full screen,
installing the platform-signed car build, the config file under the new
package ID, building with Nix, and credits. Adds a current screenshot
(2.8.2 at 1920x720, emulator).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
2026-10-18 00:08:14 +02:00
TCFDONMEZ 9a6c121d09 Rename app and persist all-time consumption to MongoDB 2026-10-08 13:23:00 +03:00
TCFDONMEZ 511c166436 feat: add ota and ui changes 2026-09-29 14:32:25 +03:00
TCFDONMEZandClaude Opus 5 322ebcc4c0 feat: give window closing its own Pencereler tab
The window switch sat on the Upload Service page, which implied a relationship
that does not exist: closing windows needs no ABRP token, no GPS, no upload
interval, and runs in its own service whether or not uploading is on. It is now
a sixth page of the pager, between Araç and Wi-Fi.

Splitting it in two while it moved, because the new page has room the card did
not: the switch and status stay together, and the event log gets its own card,
monospaced and no longer capped at four lines.

setOffscreenPageLimit switches from a hardcoded 4 to panes.length - 1. It was
already one short of the page count and would have gone stale again here.
refreshWindowClose runs on the two-second tick and dereferences views on a page
that may not be on screen, so the pager must not be free to detach them.

Six tabs share the bar where five did. Widget.EV.NavTab already autosizes down
to a 12sp floor, so the labels shrink rather than truncate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-25 14:01:57 +03:00
TCFDONMEZandClaude Opus 5 444732438d feat: close all windows when parked and a door opens
Ports WinClose's SWI69 window control as an opt-in foreground service that is
independent of ABRP: no token, no GPS, no upload cadence. The driver opening a
door while the car is in P at a readable 0 km/h pulses UP at all four areas for
five seconds, then STOP.

Only the parts that serve that one behaviour are taken. WinClose's speed and
time arming, configurable delay, warning beep, per-window modes and position
reads are all absent — the target car is a Comfort trim whose motors carry no
position sensor, so a close can be neither verified nor cancelled.

The pulse, the door edge detector and the eligibility policy are pure classes
with unit tests. STOP is attempted from a finally block on every exit, including
an interrupted sleep, a refused write and a sender that throws, because a pulse
that stops arriving leaves the motors wherever they were.

Guards worth naming, several of them learned from reading WinClose rather than
from the port itself:

- A wake lock spans the pulse. This fires as the driver leaves, which is exactly
  when the head unit suspends; without it the glass can stop halfway with no
  STOP sent.
- A fresh listener registration replays the door's current state. That replay
  seeds the edge detector instead of triggering it, or a binder reconnect while
  the door stands open would close the windows on someone halfway out.
- WinClose's 60-second cooldown, so reaching back into the car does not run a
  second pulse.
- The service stops itself on a non-SWI69 generation, and the switch is disabled
  unless the process holds system uid — only the unstable flavor declares
  android.uid.system, so a stable build could otherwise offer a toggle whose
  every command would fail.

This is the project's first write to the vehicle. README, SECURITY, AGENTS,
CONTRIBUTING and DISCLAIMER all claimed the app never writes; that claim is
retracted and scoped rather than quietly left standing.

Untested on a car. The feature is off by default.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-25 14:00:10 +03:00
TCFDONMEZandClaude 2fd7b2dde1 Fatih'sMG4 — ABRP telemetry for an MG4 EH32 on SWI69
A fork of malys/EVABRPUploader (itself a fork of Leon Kernan's ABRP_Uploader)
carrying the changes that make it work on this car. History starts here: the
tree is what matters, and the upstream projects are where the earlier work
belongs.

EVHardware is vendored rather than tracked as a submodule, so one clone
builds.

Telemetry. SOC, battery power and range read as unavailable on SWI69 because
the vendor fallbacks were gated to SWI68 alone, while the property ids they
use are the ones this car publishes — the gates now admit SWI69. Tyre
pressure, the odometer and charge status come from the vendor block too,
since the generic properties for all three are declared here and never
publish. Tyre pressure is confirmed on the vehicle; the other two are not
yet.

Vehicle page. Every signal the car answers, in a table. One that it does not
publish shows a dash: an unimplemented VHAL property returns zero, and
"0 °C" would read as a measurement.

Wi-Fi page. Joins a network the unit already has saved, so a phone hotspot
does not need a trip into Settings on every drive. Tried on the upload tick
and from a button, skipped while already associated. This leans on the unit
being API 28 and the build being platform-signed — getConfiguredNetworks and
enableNetwork are closed to ordinary apps from API 29 — and fails quietly
where that does not hold.

The OTA updater points at this repository. An APK from upstream is signed
with a different key, which Android will not install over a platform-signed
build.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-22 10:45:00 +03:00