PLAN.md
⎇
Raw

upApp: upXlink as an Android app

Kotlin Android app that talks to the media unit of a VW e-up! (and Citigo e iV / Mii electric). It reimplements two Python projects:

  • MIBBridge: tunnel protocol over Bluetooth RFCOMM channel 5.
  • upXlink: registration, TLS-PSK session, REST (VIWI) access, entity parsing.

How the original works

  1. Phone opens RFCOMM channel 5 to the car.
  2. MIBBridge protocol multiplexes virtual TCP connections over that socket. Segment header: port u16le | type u8 | .... Types: TRANSMIT 0 (len u16le + data), OPEN 1 (dst u16le), CLOSE 2, HEARTBEAT 3 (echo it).
  3. GET http://car:80/car/info/vin (plain HTTP) returns the VIN.
  4. No stored credentials for that VIN: POST http://car:80/auth/registration returns 303 with content-location. GET https://car:443<location> with TLS 1.2, ECDHE-RSA-AES128-GCM-SHA256, no cert check, legacy renegotiation allowed. The user confirms a PIN on the car display. The body is username,password.
  5. All further requests use TLS 1.2 with PSK-AES128-CBC-SHA256 (identity = username, key = password).
  6. REST endpoints: /car/batteries, /car/info, /car/ranges, /chargingmanager/{providers,profiles,timers}. The first profile is the default profile. Departure times are UTC.

Key technical decisions

  • TLS: BouncyCastle low-level API (bctls). Android's Conscrypt (BoringSSL) has no TLS_PSK_WITH_AES_128_CBC_SHA256. BC's PSKTlsClient supports it. BC also lets us skip cert checks and allow legacy renegotiation for registration.
  • No localhost TCP bridge. MIBBridge listens on local ports so that requests can connect. On Android we run TLS directly on the in-process tunnel streams. This removes ports, threads and the proxy layer.
  • Minimal HTTP/1.1 client over the TLS stream (request line, headers, Content-Length or chunked body). OkHttp cannot use a BC TLS-PSK stream.
  • JSON: org.json (part of Android). No serialization library.
  • Credentials: app-private SharedPreferences keyed by VIN. allowBackup=false.
  • Bluetooth: pick from bonded devices, no scanning. Permission BLUETOOTH_CONNECT (API 31+). Connect by the SDP service UUID from maps+more. See docs/maps-and-more.md.
  • UI: Jetpack Compose, Material 3, single activity, coroutines on Dispatchers.IO.
  • License: AGPL-3.0-or-later (EUPL-compatible). Attribution to upXlink and MIBBridge in the README.

Files (target)

app/src/main/java/.../
  Tunnel.kt        MIBBridge segment codec, reader loop, heartbeat, virtual connection streams
  Tls.kt           BC TLS clients: registration (ECDHE-RSA) and session (PSK)
  Http.kt          minimal HTTP/1.1 request/response
  Car.kt           connect flow: VIN, credentials, registration, get/post
  Model.kt         Battery, Info, Range, ChargingManager parsing
  MainActivity.kt  Compose UI: device picker, dashboard, charging manager, raw GET/POST console
app/src/test/...   codec test, parser tests (ported from upXlink fixtures)

Phases

  1. Setup. Android SDK, Gradle project, JDK 21.
  2. Transport. Tunnel, TLS, HTTP, registration, raw GET/POST console. First car session: register and read /.
  3. Read parity. Battery, range, info, charging manager. Unit tests with the upXlink fixtures.
  4. Roadmap items (see below). Each needs car sessions.
  5. Docs. README with protocol notes and the endpoint list we discover.

Roadmap items from upXlink

Item Status Needs
Charging manager write Done Tested in the car: timer edits, off-peak days, location create and delete. Location and options edits untested.
WebSocket events Done Tested in the car.
Cert check at registration Done Tested in the car.
PIN calculation Done Tested in the car.
Documentation Done README and docs/maps-and-more.md.
MediaControl Open Explore / and /media/* on the car. Scope depends on what the car exposes.
Infotainment keys Open Events arrive and are logged. Map keys to screens, like maps+more.
Missing location fields Open Temperature, min. level, more operations in the location editor.
Car clock sync Open maps+more sets the car date and time from the phone.
Release build Open R8, signing, Play listing. Debug logging of raw responses still on.

Debugging in the car

  • Laptop to phone over USB or wireless adb: install, logcat, run the raw console.
  • API exploration needs no new code: run upXlink on the laptop over the laptop's own Bluetooth.
  • Optional: Bluetooth HCI snoop log of maps+more. Payloads are TLS encrypted, so value is limited.