Native Android app for sunnyconf: configure a
sunnypilot/openpilot device and browse its drives over local WiFi — no internet, no accounts.
It discovers the comma via mDNS (_sunnyconf._tcp), fetches /schema + /values from the on-device
daemon and renders the settings UI from them, so it hardcodes no parameter list — a new toggle in
your fork becomes a new row in the app by itself, no APK update needed.
- Settings: every sunnypilot settings panel (Toggles, Models, Steering, Cruise, …), rendered from the device's own schema; pairing-code auth; offroad-only settings lock while driving.
- Drives: route list with the connect-style engagement bar, per-segment video playback, OSM route map, camera switching, clip creation and sharing.
- Runs everywhere from Android 4.4.2 (API 19) up. The primary target is a GEN5W car head unit (KitKat) — with OEM-look styling on its 1920×720 screen — and the same APK installs on any phone.
| Home | Drives | Drive | Models | Vehicle |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
Grab sunnyconf-vX.Y.Z.apk from Releases and
adb install -r it (phones: just open the APK). The device side must be installed first — follow
Falseclock/sunnyconf, then set a pairing code on the comma
(Settings → Device → Sunnyconf Pairing Code) and enter it in the app when prompted.
KitKat (API 19) + dual-target forces a deliberately minimal stack:
- Framework Views only — no AndroidX, no Compose (API 21+). AndroidX + the apksigner META-INF quirk
make the APK fail to install on KitKat (
INCONSISTENT_CERTIFICATES). java.net.HttpURLConnection+org.json(built in) — no OkHttp/Retrofit. TLS 1.2 is enabled by hand on API 19 (net/Tls12.java) for OSM tile servers.NsdManagerfor mDNS (API 16+). TXT records need API 21+, so on KitKat the device is identified by service name (e.g.comma3x-1c5bce9a).- The one dependency: osmdroid (pure framework Java, Apache-2.0) for the route map.
minSdk 19,targetSdk 30— installs on Android 14+, still runs on KitKat.- All sizes/styles live in
res/with three device buckets:values/(phone portrait),values-land/(phone landscape),values-w1280dp-long/(the 1280×420dp head-unit window only).
Toolchain: AGP 7.4.2 / Gradle 7.5 / JDK 17 / compileSdk 30 / build-tools 30.0.3 (JDK 21 breaks D8 —
see gradle.properties).
bash build.sh # picks up JAVA_HOME/ANDROID_HOME, falls back to common locations
# → files/sunnyconf.apk (debug-signed)Or open the project in Android Studio (set Gradle JDK to 17) and Run.
With the phone (or head unit) on USB and ADB enabled:
adb logcat -d -b crash # app crashes (java tracebacks), most recent last
adb logcat -d | grep -i sunnyconf | tail -100 # runtime log linesWhen opening an issue, include the crash buffer output, what you tapped, the app version and the
Daemon version (both in the status-pill popover), and — for connection problems — whether
http://<device-ip>:8765/health opens from the phone's browser. Device-side log collection is
described in the daemon README.
- Bump
versionCodeandversionNameinapp/build.gradle. git tag v<versionName> && git push --tags.- CI (release.yml) builds, signs and attaches the APK to a GitHub
Release. Signing material lives in Actions secrets (
KEYSTORE_B64,KEYSTORE_PASSWORD,KEY_ALIAS,KEY_PASSWORD) — the keystore is never committed; keep an offline backup, a lost key means every user has to uninstall/reinstall.
MIT — see LICENSE.




