- Kotlin 99.6%
- Python 0.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The location foreground service runs without POST_NOTIFICATIONS; the permission only controls whether the session notification shows. Only location now gates the app, and notifications are offered once, non-blockingly, before the background location offer. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> |
||
| app | ||
| gradle | ||
| plugins | ||
| .gitignore | ||
| app-logo.png | ||
| build.gradle.kts | ||
| Columba_RPC_Setup.md | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| LICENSE | ||
| README.md | ||
| settings.gradle.kts | ||
RNS Wardrive
An Android wardriving app for Reticulum (RNS). It tracks your GPS position while you drive or walk, measures the radio link in both directions (uplink and downlink RSSI/SNR), and maps the result — either on a collector bot over RNS, or entirely on your phone using an RNode running the wardrive responder firmware.
What it does
- Runs a persistent foreground service that tracks your GPS position and reaches RNS through a shared instance (Sideband or Columba) on the same device
- Four operating modes: Announce, Packet, Probe (bot-based) and Firmware responder (no bot, everything stays on the phone) — see Operating Modes
- Measures uplink (how well the responder/bot heard you) and downlink (how well you heard the reply) RSSI/SNR. Downlink needs the Sideband phystats plugin
- Live interactive MapLibre map with a local signal heatmap (Uplink, Downlink or Both) — tap a cell to see its numbers
- Uplink and Downlink signal meters on the status card and in the Log, with per-entry reply status
- Local Data: import and export your measurements as CSV, GeoJSON or GPX, with no server involved — the exports open directly on a wardrive map
- Offline maps: download an area and keep mapping with no internet
- Session controls: Start, Pause/Resume, Stop, "Send now", plus pre-start checks
- Smart Updates: skip transmissions if you haven't moved more than a configurable distance
Requirements
- Android 10+ (API 29)
- An RNS shared instance accessible from the device — provided by an app such as Sideband or Columba running on the same device
- For downlink (phy) measurements: Sideband plus the
phystatsplugin. The plugin is still required for any bidirectional measurement — see Downlink (phy stats). Without it the app still works, but samples carry uplink only. - For Announce / Packet / Probe:
rns-wardrive-toolsrunning server-side — it provides the collector bot that receives your beacons. The app discovers reachable bots from their RNS announces. - For Firmware responder: an RNode running RNode_Firmware 1.86.1111 or newer, the minimum version that includes the wardrive responder. No bot is needed.
Download & Install
Download the latest APK from the releases page and install it on your device. Releases are currently debug-signed pre-releases.
Prefer to build it yourself? See Building at the bottom.
Setup
-
Install and open the app. Grant location permissions when prompted (including "Allow all the time" for background tracking).
-
Start your RNS shared instance (Sideband or Columba) on the device. The app connects to it on port
37428by default. -
Install the phystats plugin (for downlink). In Sideband, install
phystats_plugin.py— details in Downlink (phy stats). -
Pick your measurement source.
- Firmware responder: nothing else to set up beyond an RNode running RNode_Firmware 1.86.1111 or newer.
- Announce / Packet / Probe: install and run
rns-wardrive-toolsand note the bot's RNS destination hash (or pick it from the discovered bots).
-
Open Settings and configure:
- Operating mode — Announce, Packet, Probe or Firmware responder
- Bot hash(es) — destination hash of your collector bot (bot-based modes)
- Probe interval — seconds between probes in Firmware responder mode (default 10, minimum 2)
- Beacon interval / ping and path timeouts — timings for the bot-based modes
- Smart updates — minimum distance (meters) you must move before a new beacon or probe is sent
- Shared instance port / RPC port / RPC Key — for non-default ports and for downlink (see below)
- Map style and Offline maps
-
Tap Start Session on the map screen and confirm.
Operating Modes
| Mode | Description |
|---|---|
| Announce | Broadcasts your position as an RNS announce. Works without a path to the bot. Lowest latency, no delivery confirmation. |
| Packet | Sends a direct encrypted packet to the collector bot. Falls back to Announce if no path is known yet. |
| Probe | Bi-directional. Like Packet, but each beacon carries the downlink RSSI/SNR measured from the bot's previous reply, and the bot echoes back the uplink RSSI/SNR it measured for your packet. Useful for two-way RF link quality surveys. Real downlink values need the phystats plugin and RPC key. |
| Firmware responder | No bot and no server. The app probes an RNode running the wardrive responder (RNode_Firmware 1.86.1111 or newer) once per probe interval (default 10 s, about 3% airtime at SF8). Each reply gives the responder's uplink RSSI/SNR, and — with the phystats plugin — your downlink RSSI/SNR. Every probe, answered or not, is stored on the phone and drawn on the local heatmap; unanswered probes appear as cold spots. |
Downlink (phy stats) and the Sideband plugin
Downlink is the signal quality of the reply as heard by your own device's radio. A shared-instance client such as this app cannot see that directly. Reticulum caches each received packet's RSSI/SNR, and serves it over the instance's authenticated RPC port, but only for interfaces that set reports_phy_stats. Sideband's Android RNode interface never sets it (neither does Columba's), so by default there is nothing to read.
The phystats Sideband service plugin fixes that, and it is still required for bidirectional work (Probe mode and Firmware responder downlink):
- Get
plugins/phystats_plugin.pyfrom this repository and copy it to a directory on the phone. - In Sideband open Plugins, enable service plugins, choose that directory, and restart Sideband (plugins load at startup).
- In Sideband Connectivity tap Copy RPC Config To Clipboard, then paste it into this app's Settings → RPC Key. Leave RPC port at
37429. Use Test RPC Connection to verify.
Nothing in Sideband is patched; disabling the plugin and restarting Sideband puts everything back. Without the plugin or the RPC key, measurements still work and are stored with uplink only.
Columba doesn't expose its RPC key in the UI (it must be derived from its transport identity file and needs root — see Columba RPC key setup), and the plugin is Sideband-only, so downlink is not available through Columba.
Using the app
Session controls
- Start / Stop Session ask for confirmation. Before starting, the app checks Flight mode, Bluetooth and the RNode; the button turns yellow, and the dialog says what to fix. Turning Flight mode on during a session stops it immediately.
- Pause / Resume (button above Stop, and a notification action) stops new probes while GPS and the shared-instance connection stay up.
- Send now forces a probe immediately (also while paused), but still refuses a missing, stale or inaccurate position.
Status card and Log
- The status card shows the shared-instance state, counters, the last reply (responder and round-trip time) and Uplink and Downlink RSSI/SNR bars. Captions are coloured like the RNode LEDs: TX blue, RX green. The downlink reading is held until the next one arrives.
- The Log lists each probe with coordinates, signal bars, and the reply (or a red No reply), and has a draggable scrollbar.
Heatmap
- Overlay choices are Uplink, Downlink or Both (uplink heatmap plus downlink dots). Cells are about 10 m, coloured by mean RSSI.
- Tap a cell for its uplink/downlink RSSI/SNR.
Local Data
The Local Data menu on the map screen offers:
- Import CSV, GeoJSON or GPX; duplicates are skipped, the overlay turns on and the map flies to the imported area
- Export as GeoJSON, CSV or GPX (unanswered probes are included as
replied = false) - Clear Local Data (greyed out when there is nothing to clear)
Viewing exports on the wardrive map
Exports do not need a bot or any server-side collector. The map from rns-wardrive-tools can show them directly: open the map page, press Open file (or drop one or more files on the page) and pick the GeoJSON, CSV or GPX file you exported. The file is read in your browser and nothing is uploaded.
- Answered probes appear on the Uplink heatmap, and on the Downlink heatmap when the sample has downlink values
- Unanswered probes (
replied = false) appear as red dots: the coverage holes - Close file returns the map to its live data. A map without a bot database works as a pure file viewer
Maps
- Map style: OpenFreeMap Liberty, rns.moscow Light / Dark (follow the app theme) / Green / Voyager / OSM, or a Custom MapLibre style URL.
- Offline maps (Settings → Maps): choose a centre and radius, a zoom range and see the exact tile count and size before downloading. Downloads can be paused, resumed and deleted, and the space used is shown. When there is no internet, the saved style is used and the status card shows an "Offline map" row.
Permissions
| Permission | Reason |
|---|---|
ACCESS_FINE_LOCATION / ACCESS_COARSE_LOCATION |
GPS position |
ACCESS_BACKGROUND_LOCATION |
Continue tracking when the screen is off |
FOREGROUND_SERVICE / FOREGROUND_SERVICE_LOCATION |
Persistent service |
INTERNET / ACCESS_NETWORK_STATE |
RNS TCP transport, map tiles, offline detection |
POST_NOTIFICATIONS |
Foreground service notification |
WAKE_LOCK |
Prevent CPU sleep during active tracking |
Architecture
ui/
map/ MapScreen + MapViewModel — live map, heatmap, status card, session controls
log/ LogScreen + LogViewModel — measurement log
bots/ discovered collector bots
offline/ offline map download and management
settings/ SettingsScreen + SettingsViewModel, map style picker
permissions/ permission gate shown before the app starts
plugins/ phystats Sideband service plugin (installed on the phone, not part of the APK)
rns/
WardriveRnsManager — RNS lifecycle, beacon sending, probe/ping logic
FirmwareResponderManager — probes the RNode firmware responder
WardriveLxmfManager — LXMF messaging (bot responses)
SharedInstanceRpcClient — RPC client for downlink lookup (MiniMsgPack, AuthMath)
probe/ ProbeEngine, protocol and responder session
heatmap/ local heatmap aggregation and tap hit-testing
export/ GeoJSON / CSV / GPX export and import
offline/ offline map regions, tiles and local style server
session/ pre-start checks (Flight mode, Bluetooth, RNode)
location/ GPS / LocationManager tracking
service/
WardriveForegroundService — location loop, wakelock, notification
data/
SettingsRepository — DataStore-backed settings persistence
local/ — Room database of wardrive samples
model/ — WardriveSettings, LocationPoint, LogEntry
The app uses Hilt for DI, Jetpack Compose + Material3 for UI, Room for local samples, and Kotlin coroutines/Flow throughout.
Building
Prerequisites
- Android Studio Meerkat or later
- JDK 17
- Gradle 8.x (managed by the wrapper — no separate install needed)
The app depends on reticulum-kt and LXMF-kt, published to JitPack. No additional setup is needed — Gradle resolves them automatically.
Clone and build
git clone https://git.rns.moscow/deuxyeux/rns-wardrive-app.git
cd rns-wardrive-app
./gradlew assembleDebug
The APK will be at app/build/outputs/apk/debug/app-debug.apk.
For a release build:
./gradlew assembleRelease
You will need to configure a signing keystore in app/build.gradle.kts or via Android Studio before a release build will install on a device.
Install via ADB
adb install app/build/outputs/apk/debug/app-debug.apk
License
Released under the MIT License. See LICENSE.