English · Português (Brasil)
A better everyday dashboard for the Geely EX2 / Geometry E.
Drive Assist is an app for the Geely EX2 / Geometry E. It installs on the car's own screen and gives you the things the factory software leaves out: controls that stay the way you set them, a clear record of driving and charging, and useful vehicle data on the car screen and in services you already use.
If you want to see the app before reading about installation or engineering, start with the illustrated Guide for Drivers.
Warning
Root ADB gives administrator access to the head unit and can expose location, credentials, cameras, vehicle data, and your home network. Read the plain-language root ADB safety notice before enabling it.
- The car forgets your settings. Pick Eco, Comfort or Sport and it goes back to default the next time you switch on. Drive Assist remembers your choice and puts it back for you every time.
- The climate controls are fiddly. Instead of juggling temperature, fan speed and the A/C button, there is a single slider that runs from cold to warm. Slide one way if you feel too hot, the other way if you feel too cold. The app works out the rest.
- Your car's data is locked away. Battery level, range, charging, and location can be sent to your own Home Assistant. Drive Assist sends data only to the services you configure, including Home Assistant and, when enabled, A Better Routeplanner.
- Charging costs disappear into memory. Every recharge becomes part of a history with energy, duration, battery change, and price. Earlier prices can be corrected later, and free charging is recorded properly.
- Daily driving deserves more than one number. See trips, parking intervals, recharges, energy use, regeneration, elevation change, and efficiency by speed range. Parked climate use does not distort driving efficiency.
- Long trips are a guessing game. Live battery and elevation data can be fed to A Better Routeplanner, so its charging stops are based on how your car is actually doing right now.
- OBD2 ready. You can connect the head unit directly to an OBD2 dongle for fresh battery-management data.
The main screen gives you a simple cooler-to-warmer comfort control, outdoor temperature, and large climate shortcuts that work at a glance.
The statistics screens keep a diary of your driving and charging: how far you went, where energy was spent or recovered, how much you climbed and descended, what every recharge delivered, and what it cost. There is also an optional dashcam that records with telemetry subtitles and can copy clips to a USB stick.
A connection to Home Assistant opens up a whole new world of automations. You can open your gate and send timely information from Home Assistant to the car. If someone rings your doorbell, for example, the dashboard can show the doorbell image.
Drive Assist only touches comfort and convenience: climate, drive mode, cabin lights, windows, charging. It has no ability to steer, brake, accelerate, lock or unlock your doors, or open the boot — those signals are read and displayed only, never commanded. The full, plain-language rundown of everything the app can see and do is in the Welcome & Transparency Guide.
Owners of a Geely EX2 / Geometry E who are comfortable installing an app on the car themselves. It is a spare-time project, not an official Geely product, and it comes with no warranty — please read the Vehicle Security & Sideloading Guide before you start.
Technical details, for those who want them: the head unit is an IHU629G running Android 9 (API 28, ECARX 250060) with a 1920x1080 screen at 160 dpi. Everything below this point is written for developers.
Captured directly from the physical vehicle head unit display via ADB (1920x1080 native resolution):
| Comfort View & Thermal Effort Ruler | Daily Statistics & Altimetry Feed |
|---|---|
![]() |
![]() |
| Charging history & energy balance | Drive mode and regeneration |
|---|---|
![]() |
![]() |
Getting Drive Assist running on your vehicle head unit:
-
Standalone USB Installer (
drive_assist_installer.apk, recommended): Copy the single installer APK to a FAT32 USB flash drive, insert it into the vehicle USB port, open the vehicle's File Manager, and tap to install. The installer bundles both packages, installs them with platform privileges, and self-uninstalls on completion. -
One-Shot Wireless Installation: If your laptop is on the same Wi-Fi network as the vehicle, run:
./install.sh <CAR_IP>
Provisions
modehelper.apk, installsdrive_assist.apk, and launches Drive Assist. It does not change Bluetooth settings or any file under/system.Bluetooth OBD2 pairing is optional. The separate, temporary PIN workaround is documented with its risks in the installation guide.
-
Interactive Configuration Wizard (
configure-car.sh): After ADB is available, configure MQTT broker credentials, mTLS certificates, ABRP tokens, and defaults from an interactive terminal:./tools/configure-car.sh
For detailed step-by-step instructions and troubleshooting, see the Post-Unlock Installation Guide.
Full architectural documentation and reverse-engineering guides are located in the docs/ directory:
- Guide for Drivers — An illustrated explanation of the app
- Welcome & Transparency Guide — What the app sees, does, controls, risks, and privacy safeguards
- Short Installation Guide — The one-file USB method for owners
- Technical Installation Guide — ADB setup, scripts, verification, and troubleshooting
- Home Assistant Guide — Connection, permissions, verification, and privacy
- A Better Routeplanner Guide — Live-data connection, location choice, and optional OBD2
- MQTT Technical Reference — Broker setup, mTLS security, topics, and automations
- ABRP & OBD2 Technical Reference — Payloads, generic tokens, and Bluetooth BMS
- Vehicle Security & Sideloading Guide — Sideloading risks, platform test keys, APK repackaging, and data exposure
- Release Readiness Matrix — Comprehensive Go/No-Go release audit and remediation roadmap
- Software Architecture & Vehicle Safety Audit — Multi-perspective audit of UID separation, Park invariants, and VHAL safety
- Open-source Head-unit Software Review — Prioritized maintainability, architecture, performance, safety, and community recommendations for rooted sideloaded deployment
- Code Quality & Test Coverage Report — JaCoCo test metrics (19.84% scoped instruction coverage / 325 tests), Lint tuning, Checkstyle, and SpotBugs catalog
- Contributing Guidelines — Branching rules (
dev/master), Conventional Commits, and pull request checklist - Changelog — Full version history, release notes, and unreleased enhancements
- License — GNU General Public License v3.0 terms
- Vehicle Data Catalog — Confirmed properties and function IDs
- Field Catalog — Exhaustive hardware signals, probes, and VHAL references
- Climate & Comfort Ruler — Thermal effort scale and HVAC state machine
- Cameras & EVS HAL — Extended View System architecture and binder interface
- Dashcam Subsystem — Continuous recording, telemetry subtitles, and streaming
- Status Bar Icons — System overlay mechanism and icon IDs
- ADB Setup Guide — Sideloading, networking, and root environment
- ModeHelper Companion App — Privileged system companion app (
android.uid.system) for mode persistence, silent OTA, dashcam, and ADB guard
- Drive Modes & Regeneration: Configures drive modes (Eco, Comfort, Sport) and regenerative braking levels (Low, Mid, High). On boot, mode reapplication is handled by the privileged helper app
com.geely.modehelper. - Comfort Ruler (Climate Control): The car hardware does not expose cabin temperature via VHAL (
HVAC_IN_OUT_TEMPisNOT_AVAILABLE). Climate is controlled using an absolute thermal effort scale (EffortTable/ComfortRuler, C5..0..W5) targeting setpoints the car holds. The scale steps over 0 (the mode boundary between cooling and heating) to avoid reversing the HVAC state machine at the neutral point. See COMFORT-TABLE.md. - Telemetry & MQTT: Publishes vehicle metrics (battery, odometer, range, speed, gear, climate, charging) to Home Assistant via MQTT with auto-discovery, and handles remote actions (smart gate trigger, climate commands, OTA updates).
The vehicle controls use functionIds from a Geely adaptation layer (VehicleModules.getAdaptValue), not direct VHAL property IDs. CarPropertyManager inside an installed APK (via Car.createCar) resolves and translates these IDs; standalone binder clients (app_process) fail to resolve them. Drive Assist is therefore built and installed as an APK.
Car permissions (CAR_POWERTRAIN, CAR_ENERGY) are signature|privileged. They are granted to debug-signed APKs on this head unit because ro.control_privapp_permissions is non-enforcing (empty).
A consolidated reference of confirmed vehicle properties and Geely adaptation layer function IDs on the IHU629G. All properties are accessed via CarPropertyManager inside the installed APK. For detailed probing methodologies, logs, and historical investigations, see field-catalog.md and DATA-CATALOG.md.
All vehicle I/O is centralized in CarActor, which manages a dedicated HandlerThread and a single CarAccess connection for the process lifecycle.
- Cached Reads:
CarActor.get(ctx).get(key)returns the latest cached property value synchronously without blocking on vehicle binder I/O. - Subscriptions:
EntityBus.subscribe(key, listener)notifies in-app consumers when property values change.EntityBus.publish()is restricted toCarActor. - Thread Safety: All car read/write calls must execute on
CarActor's thread.
- Always-On Keys: Registered at startup and polled continuously:
car.is_charging(2s): Derived fromcharge_a > 0.5Arather than the charge switch read-back.telemetry.outside_temp(15s): Outside ambient temperature.telemetry.ambient_color&telemetry.ambient_brightness(4s): Cabin strip state.car.carplay_connected(4s): Re-publishes OEMcom.njda.carplay.broadcaststate ontoEntityBus.
- Screen-Scoped Keys: Polled only while requested by an active UI:
telemetry.speed(1s): Active duringComfortActivityforeground lifecycle (onResume→onPause) to drive visualizer animations.
- Snapshot Cadence (
telemetry.tick): Published every 15 seconds unconditionally (not diffed) carrying the full vehicle snapshot. This un-diffed tick prevents heartbeat starvation for MQTT and ensures periodic sampling for internal listeners (ChargeSessionandOdoStats).
Stateful features requiring independent lifecycle management run dedicated listener interfaces seeded from EntityBus events: ChargeSession, TripSession, ParkSession, CarState, GateState, Obd2Reader, and AbrpUploader.
TelemetryService publishes vehicle metrics to Mosquitto with Home Assistant auto-discovery (homeassistant/<comp>/drivemem_<vin>/<key>/config), registering the vehicle device under Geely EX2 (<last 6 of VIN>) (deduced dynamically from sys.ecarx.vin, or Geely EX2 as fallback).
- Payload scaling: Values from the Geely adaptation layer (battery %, odometer km) are pre-scaled;
div=1is used across fields.ac_onis an adapted boolean. - Transports: Supports TCP LAN (
tcp://<host>:1883) or remote WebSocket (wss://<host>:<port>via Tailscale Funnel). - Validation:
helpers/mqtt_test.pyvalidates discovery and telemetry payloads from an external machine:python3 helpers/mqtt_test.py <broker-ip> <user> <pass>
Coordinates gate availability and triggers via Home Assistant over two MQTT topics:
drivemem/<vin>/gate/available HA -> app, retained, "online"/"offline"
drivemem/<vin>/gate/open app -> HA, QoS 1, NEVER retained
State & Network Invariants:
- HA computes proximity: The app does not evaluate GPS boundaries. HA evaluates the vehicle's
device_trackerlocation and publishesgate/available. - Availability lifecycle: Gate visibility requires
available && connected.connectionLostimmediately resetsavailableto false to prevent displaying a stale gate button during reconnection before HA pushes fresh state. - Replayed retained messages are ignored: On reconnect/resubscribe, the MQTT broker replays retained messages with the
RETAINflag set.MqttReporterdrops replayed retained"online"messages and waits for a live push to prevent triggering gate visibility from pre-trip state. - Immediate fix on reconnect:
subscribePanel()publishes an immediate GPS position upon reconnection so HA can evaluate proximity without waiting for the next telemetry interval. - Actuation delivery:
gate/openis published with QoS 1 andretained=false(retained actuation commands would re-trigger physical gates upon broker restarts or reconnects). UI taps are debounced for 3 seconds.
Testing gate topics manually:
mosquitto_pub -r -t drivemem/<vin>/gate/available -m online # Show gate button
mosquitto_pub -r -t drivemem/<vin>/gate/available -m offline # Hide gate button
mosquitto_sub -t 'drivemem/<vin>/gate/#' -v # Observe gate open commandsNote on LAN isolation: Access Point / Client Isolation on the local Wi-Fi router blocks TCP between the head unit and broker on port 1883.
ComfortActivity(LAUNCHER): Three-column dashboard:- Climate: Outside temperature display, comfort ruler (
ComfortRuler), and warmer/colder buttons. - Controls: Recirculation toggle and smart gate opener.
- Visualizer & Context: Full-bleed art view (
SkylineArtView) framing the Home Assistant WebView card (PanelCardView).
- Climate: Outside temperature display, comfort ruler (
TelemetryActivity: Settings screen for MQTT parameters, drive mode/regen defaults, status bar icons, and theme selection.HvacProbe/HvacSet: Diagnostic activities for HVAC reverse engineering and property testing.
- Native Resolution: 1920x1080 at density 1.00 (
1 dp = 1 px = 1 sp). Screen width is 1920 dp (~5x standard phone width), viewed at ~75 cm. - Layout Implications: Typography and touch targets must account for the 1.00 density and viewing distance. Gesture thresholds and touch boundaries must be defined as fractions of the view or screen dimensions, not fixed dp values (e.g. 44 dp represents only 44 pixels).
- Property Write Confirmation:
setIntPropertycan return success even if the ECU drops the write.setAmbientColorsweeps candidate area IDs{5, 0, 1}, reads the property back to confirm execution, and caches the working area. - Ambient Light Order of Operations: Brightness
0is the ECU's off state. Setting color while brightness is 0 causes the ECU to discard the color command. Brightness must always be set to non-zero before updating color. CarAccess.connect()Threading: Never invokeCarAccess.connect()on the Android main thread. It blocks waiting forServiceConnection, whose callbacks are dispatched on the main thread, resulting in a deadlock.
BootReceiver: Listens forBOOT_COMPLETED(handled viagoAsync()). Re-enables Wi-Fi and starts configured background services.- Head Unit Sleep Behavior: The head unit suspends to RAM rather than performing full shutdowns on short stops.
BOOT_COMPLETEDdoes not fire on resume from sleep, andSCREEN_ONis not delivered to manifest receivers. - Watchdog Timer: A 10-minute
ELAPSED_REALTIME_WAKEUPalarm counts suspended time and triggersensureAllupon wake-up to verify Wi-Fi connectivity and ensure services are running. - Package Updates & Process Kills: APK installation and force-stops cancel pending alarms.
BootReceiverlistens forMY_PACKAGE_REPLACED, andComfortActivity.onResumeinvokesscheduleWatchdog/ensureAllto restore watchdog alarms. - Drive Mode Persistence: Persistent drive mode and regen reapplication is executed by the privileged companion app
com.geely.modehelper(android.uid.system). Drive Assist broadcasts preference updates tomodehelper.
The build environment requires JDK 17, Android SDK (build-tools 34.0.0, platform-28), hand-crafted compilation stubs (car-stubs/car-stubs.jar), and debug.ks.
To run Gradle directly or run unit tests, execute from the repository root:
./gradlew :drivemem:assembleRelease # compile only from repo root
./gradlew test # run unit tests- Version Code:
versionCodeis computed from wall-clock minutes since the epoch and injected byaapt2to ensure monotonic increases, preventingpm install -rdowngrade errors. - OTA Publication:
build.shuploadsdrive_assist.apkto Home Assistant's/config/wwwdirectory and broadcasts the update notification ondrivemem/<vin>/update/set.
adb connect <CAR_IP>:5555
adb install -r drive_assist.apkInstead of typing MQTT credentials, mTLS certificates, ABRP tokens, and Spotify keys on the car touchscreen, use the interactive terminal wizard:
./tools/configure-car.sh- Interactive Prompts: Enter values or press
[Enter]to retain existing values. - Multi-Broker: Configures up to 3 MQTT URIs with automatic fallback.
- mTLS Integration: Automatically pushes
.p12client certificates and.crtCA certificates to the app's protected storage with correct Unix permissions (UID 10048). - Safety: Automatically creates timestamped XML backups in
../prefs-backup/and force-stops the app before writing to prevent Android's in-memory SharedPreferences cache from overwriting changes. - CLI Commands:
./tools/configure-car.sh --show # Display current active settings on vehicle ./tools/configure-car.sh --backup-only # Export current car settings to a timestamped file ./tools/configure-car.sh --restore <file> # Restore previous preferences XML backup
Do not run adb reboot (it restarts the audio amplifier and causes a loud speaker pop). Simulate boot broadcast instead:
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -n com.geely.drivemem/.BootReceiverDrive Assist welcomes contributions from automotive software developers and the Geely community!
- Contributing Guidelines: Review CONTRIBUTING.md for the public
next/ release-branch workflow, pre-push PII checks, Conventional Commits, local validation, and vehicle safety rules. - Release Readiness & Audits: See docs/RELEASE-READINESS-MATRIX.md for the objective release assessment matrix, docs/ARCHITECTURE-SAFETY-AUDIT.md for vehicle safety invariant analyses, and docs/CODE-QUALITY-REPORT.md for test coverage and static analysis findings.
- Changelog: See CHANGELOG.md for release notes across all versions and unreleased staging features.
- License: Drive Assist is licensed under the GNU General Public License v3.0. Any distributed modified version must also stay open source under GPLv3.



