Moon-Companion
Android app that pairs once with your Flipper and gives every FAP access to GPS, time, and HTTP — all over BLE GATT.
Why have a phone at all?
The Flipper has no Wi-Fi, no cellular, and no real-time clock that
survives a battery pull. Every FAP that wants live data has
historically needed an ESP32 dev-board plugged into the GPIO
header. Moon-Companion takes the phone you already carry and
turns it into that dev-board, over BLE — one pairing flow, one
battery-aware service, usable by any FAP that links against
moon_companion.
The on-device services the phone provides:
- GPS — current fix (lat, lon, accuracy, timestamp), pushed on change.
- Time — wall clock + timezone; used to set the Flipper RTC on connect.
- HTTP(S) proxy — arbitrary request/response over BLE, chunked for large payloads.
- Notifications — push toasts from FAP back to phone (future).
Encrypted pairing, once
First time you connect, Android pops its standard pair-accept dialog. Behind the scenes we run SMP with encryption (LE Secure Connections where the chip supports it) and exchange long-term keys. Moon-Companion persists the bond via EncryptedSharedPreferences, and the firmware side stores LTKs in BlueNRG's NVM. From that point on, reconnects happen silently: no prompt, no re-pair, no ritual.
Every RPC characteristic (RPC_TX,
RPC_RX) is marked
PERMISSION_READ_ENCRYPTED /
PERMISSION_WRITE_ENCRYPTED at the GATT server, so an
attacker who sniffs the advertisement can't just connect and start
issuing HTTP calls — the link has to be encrypted with the bonded
keys before the firmware will serve those characteristics.
HTTP proxy with chunked framing
BLE's per-notification payload is tiny — 244 bytes in the best case, often less after headers. A real HTTP response body doesn't fit. The proxy wraps every RPC message in a chunk frame so the firmware can reassemble up to 8 KB payloads without re-negotiating MTU every call.
Chunk frame
Messages are nanopb protobufs — MoonPhoneMessage on
the wire, which wraps either an HttpRequest or
HttpResponse. We widened the PB_BIND
width to 4 bytes on those types so the body field
can carry up to 4 KB without length-prefix overflow.
Request flow
- FAP builds an
HttpRequest(method, URL, headers, optional body). moon_companionservice serializes it, chunks it, writes to RPC_RX.- Phone reassembles, dispatches to OkHttp, streams the response back.
- Phone chunks the response, sends each chunk as a GATT notification on RPC_TX.
- Firmware reassembles, hands the
HttpResponseback to the FAP.
Where to find it
Source on GitHub: KaraZajac/Moon-Companion. Minimum Android 9 (API 28). Play Store listing is pending; for alpha users the APK is attached to each GitHub release.