Skip to content

official-mesh/remote

Repository files navigation

Meshbot Remote

Android foreground-service app that acts as a remote peer for meshbot. The phone dials meshbot over TCP (typically across WireGuard), then exposes three capabilities over that one link: remote control of meshbot's hooks, a remote view of meshbot's console, and optionally bridging a locally-attached Meshtastic radio (USB OTG or BLE) into meshbot as an "attached device" interface. On the wire the app identifies itself as meshbot-remote.

Project home: officialmesh.org · github.com/official-mesh
Maintainer: The Official Mesh Admin
License: GNU Affero General Public License v3.0-only — see LICENSE

Companion to meshbot, which targets Meshtastic mesh radios. "Meshtastic" is referenced nominatively. This project is not affiliated with, endorsed by, licensed from, or authorized by Meshtastic LLC or its maintainers.

Related projects

This app ships alongside five companion repos under the official-mesh org:

Repo Purpose
official-mesh/firmware Meshtastic firmware fork — adds privacy modules
official-mesh/android Android client for the firmware fork
official-mesh/python Python CLI for the firmware fork
official-mesh/meshbot LLM-powered mesh radio bot; hosts the org's CLA and Code of Conduct
official-mesh/dualboot Boot selector for ESP32-S3 devices (Official Mesh firmware ↔ MeshCore)
Meshtastic radio (optional)
  ↕  USB OTG serial  OR  BLE GATT
Android phone (Meshbot Remote)
  ↕  outbound TCP (default port 4404) / WireGuard
meshbot on the server  ←→  inference / LLM backend

Requirements

  • Android 8.0+ (API 26), compileSdk / targetSdk 35
  • Reachability from the phone to meshbot's peer-link port (typically over WireGuard)
  • A shared-secret token configured on both sides
  • Optional (for device bridging):
    • USB OTG cable + Meshtastic radio with a serial adapter (FTDI, CH340, CP210x, CDC-ACM), or
    • A Meshtastic radio advertising the Meshtastic BLE service UUID

Usage

  1. Build and install the APK (instructions below).
  2. Open the app. There are three tabs: Connect, Hooks, Console.
  3. On Connect, tap the endpoint row and set host / port / shared-secret token. Port defaults to 4404.
  4. Tap CONNECT. The phone dials meshbot and sends a hello containing the token; meshbot replies with a welcome (optionally carrying a theme colour, which tints the UI).
  5. The foreground notification stays up for as long as the service is alive. The link auto-reconnects with exponential backoff (1 s → 30 s cap) if the TCP session drops.
  6. (Optional) Pick a USB or BLE radio from the device-management card to bridge a local radio into meshbot as an attached interface.

On the meshbot side, see meshbot's own docs for the corresponding peer-link configuration (shared-secret token and listen port).

Architecture

File Purpose
MainActivity.kt Hosts the three-tab ViewPager2, binds to ProxyService, fans out callbacks to the fragments.
ConnectFragment.kt Endpoint config dialog (host/port/token), CONNECT/DISCONNECT, optional device-management card (USB / BLE picker).
HooksFragment.kt + HooksMgr.kt "Hooks" tab — list / enable / disable / fire hooks on the remote meshbot.
ConsoleFragment.kt + ConsoleMgr.kt "Console" tab — subscribe to remote console events, send console input, browse commands.
ProxyService.kt Foreground service. Owns the single MeshbotLink and (if a device is attached) one AttachedDevicePump. Multiplexes inbound control frames to listeners (hooks + console) via CopyOnWriteArrayList.
MeshbotLink.kt Outbound TCP client: connect, hello/welcome handshake, read-loop, write-loop, reconnect-with-backoff.
AttachedDevicePump.kt Bridges an attached radio's serial-framed FromRadio/ToRadio stream to/from the peer-link data plane (portnum 359). Also parses enough of the config dump to populate the device-info UI.
DeviceConnection.kt Common suspend interface (read, write, close, awaitReady) implemented by both transports.
UsbSerialConnection.kt USB serial at 921600 baud — pure serial-framing passthrough.
BleConnection.kt BLE GATT client — MTU 512, FROMNUM notifications, operations serialised through a single gate semaphore.
ProtoReader.kt Hand-rolled protobuf helpers plus the peer-frame parser — no protobuf library dependency.

Peer-link framing

Every message on the TCP link is:

0x94  0xC3  <uint16-be length>  <ToRadio protobuf>

Inside the ToRadio is a MeshPacket carrying a Data payload on one of two portnums:

  • 357 (control plane): JSON ops. Both directions speak the same op vocabulary:
    • client→meshbot: hello, dev_connected, dev_disconnected, list, enable, disable, fire, status_req, set_primary, primary_req, console_subscribe, console_unsubscribe, console_input, commands_req
    • meshbot→client: welcome, hook, list_end, ack, err, status, primary, console_event, commands
  • 359 (data plane): raw FromRadio / ToRadio protobuf bytes used only when a local radio is attached. The outer peer-frame already provides framing, so the AttachedDevicePump strips/adds the 0x94 0xC3 header as it crosses the serial boundary.

Auth

One-shot token check on connect. The hello carries {"op":"hello","remote_id":…,"version":"1.0","token":…}. remote_id is a UUID generated and persisted on first run. Meshbot must respond with an op-welcome before the client will accept any further frames — any other first frame kills the session and triggers reconnect backoff.

Device bridging (optional)

When a user picks a USB or BLE device on the Connect tab, ProxyService.attachDevice creates an AttachedDevicePump:

  1. Issues WANT_CONFIG to the radio so it re-emits its config dump.
  2. Parses incoming frames through DeviceInfoParser to extract node number + user identity, then emits a dev_connected control op so meshbot can install a matching attached-device interface.
  3. From then on, every FromRadio frame is forwarded as a data-plane (portnum 359) peer-frame to meshbot, and every inbound data-plane frame from meshbot is wrapped in serial framing and written to the device.

A "Use this device as primary" toggle surfaces in the UI whenever meshbot's current primary matches this remote's attached interface; tapping it sends set_primary.

BLE protocol notes

  • MTU negotiation happens before service discovery; the nRF52 firmware negotiates to 247 bytes.
  • FROMNUM notifications are gated — the firmware only emits them after the config handshake reaches STATE_SEND_PACKETS. During the initial config dump (often 50+ frames) the client polls FROMRADIO after every TORADIO write; the app handles this automatically.
  • BLE ops are strictly serialised — Android silently drops any op issued while another is in flight. A single-token channel semaphore (bleGate) enforces this.

BLE UUIDs

Verified against firmware/src/BluetoothCommon.h:

Characteristic UUID
Service 6ba1b218-15a8-461f-9fa8-5dcae273eafd
TORADIO f75c76d2-129e-4dad-a1dd-7866124401e7
FROMRADIO 2c55e69e-4993-11ed-b878-0242ac120002
FROMNUM ed9da18c-a800-4f66-a670-aa7547e34453

Build

./gradlew assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apk

local.properties must point at an Android SDK, e.g.:

sdk.dir=/opt/homebrew/share/android-commandlinetools

Limitations

  • One meshbot endpoint per app install (single host/port/token in SharedPreferences).
  • BLE and USB transports cannot both be active at once — only one DeviceConnection attached at a time.
  • If the attached radio link drops (BLE disconnect, USB unplug), detach and re-attach from the UI; the pump does not auto-reattach the radio itself (it does auto-reconnect the peer link to meshbot).

Verifying releases

Signed git tags and release APKs are signed by:

The Official Mesh Admin <officialmeshadmin@proton.me>
GPG fingerprint: 9A18 814D 74A6 3138 9F95  6EA0 5F8D 7A5E ED20 3343

The public key is in KEYS at the repo root, or fetch it from a keyserver:

gpg --keyserver hkps://keys.openpgp.org --recv-keys 9A18814D74A631389F956EA05F8D7A5EED203343

Always verify the fingerprint matches the value above before importing.

gpg --verify meshbot-remote-1.0.apk.asc meshbot-remote-1.0.apk   # release APK
git verify-tag v1.0                                               # signed git tag

(Note: this GPG signature is independent of Android's APK signing scheme. The APK signing key proves the binary came from the same Play-store-style identity over time; the GPG signature here ties releases to the maintainer's long-term identity used across the meshbot family of repos.)

License

Copyright (C) 2026 The Official Mesh Admin

This program is free software: you can redistribute it and/or modify it under the terms of version 3 of the GNU Affero General Public License as published by the Free Software Foundation. See LICENSE for the full text.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

About

Official Meshbot Remote. The recommended Android remote-control surface for Official Meshbot. Outbound TCP; can bridge a USB-OTG or BLE radio.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages