Kotlin code for talking to a MeshCore companion radio, shared by the Colorado Mesh Android apps:
- MeshCore TAK Bridge, which presents the mesh to ATAK on a phone.
- WearMesh, MeshCore messaging on a Wear OS watch with no phone.
| Module | Package | What it holds |
|---|---|---|
protocol |
org.coloradomesh.meshcore.protocol |
The companion protocol in pure Kotlin, with no Android dependencies: the frame codec (Companion.kt), the command queue that runs a session with a radio (CompanionClient.kt), telemetry (CayenneLpp.kt), battery estimates (RadioBattery.kt), @[Name] replies (ChannelReplies.kt) and MECP emergency messages (Mecp.kt). Unit tests run on the JVM. |
ble |
org.coloradomesh.meshcore.ble |
The Bluetooth LE side, as an Android library: GattLink (one connection, every step queued and time-limited, retries, PIN pairing), RadioScanner, and RadioSession, which joins a link to a protocol client. |
The code only reads from a radio, sends text, and asks tracked nodes for their position. Nothing in it changes a radio's settings, channels, paths or keys. There are two exceptions, each used only when an app asks for it:
- The radio's clock, which an app can ask to have set from its own when it is off by more than a given number of seconds (
CompanionClient.StartUp.clockTolerance, off by default). - Saving a contact (
CompanionClient.saveContact, protocol command 9, decided 1 November 2026): adding a contact back to the radio's list, or updating one, typically to set its favourite flag. An app calls it only when its user has turned that on: WearMesh does so behind its "Keep contacts on radio" setting, off by default, to put back the people its user messages when a full radio drops them. MeshCore TAK Bridge never calls it. A save keeps the contact's route as the radio gave it, or sends none. An app also passessavesAllowed(toCompanionClientorRadioSession), asked just before each save is sent, so that turning the choice off drops saves already queued.
Each app includes this repository as a git submodule at its root and builds it from source:
git submodule add https://github.com/Colorado-Mesh/meshcore-kotlin.git meshcore-kotlinIn the app's settings.gradle.kts:
includeBuild("meshcore-kotlin")And in the module that uses it:
dependencies {
implementation("org.coloradomesh.meshcore:ble") // brings in protocol too
// or, for the protocol alone:
implementation("org.coloradomesh.meshcore:protocol")
}Gradle builds the modules here as part of the app's build, so a change in the submodule shows up in the app straight away. Keep this build's Android Gradle Plugin and Kotlin versions (gradle/libs.versions.toml) the same as the apps'.
To move an app to a newer version of this code: git -C meshcore-kotlin pull origin main, then commit the submodule change in the app. After cloning an app, run git submodule update --init, or clone with --recurse-submodules.
./gradlew :protocol:test :ble:assembleDebugNeeds JDK 17 and the Android SDK (compile SDK 34).
A change here reaches both apps, so test it in both before merging: point each app's submodule at the branch, build, and try it on a device when Bluetooth or protocol behaviour changes. Anything learned about a radio or a phone or watch goes in the code comments, where the next person will see it.
The code began in MeshCore TAK Bridge (protocol/ and app/.../ble/, up to commit 33baf18) and moved here in October 2026, when WearMesh needed it too. One change came with the move: CompanionClient takes the name the app gives the radio (appName).
GPL-3.0, the same as both apps. See LICENSE.