MeshTRX — User Guide
App 4.4.5 | Firmware 4.4.4 | Updated: 2026-08-31
Contents
- Overview
- Hardware
- First connection 3.1. Desktop client
- The main screen
- Voice (PTT)
- Listening modes
- Calls
- Text messages
- File transfer
- Map and radar
- Settings 11.1. Traffic encryption
- Repeater mode
- The button on the device
- Indicators
- Specifications
Overview
MeshTRX is a decentralised voice mesh network over LoRa and BLE. Two or more Heltec WiFi LoRa 32 devices talk to each other over LoRa at ranges of 5 km and beyond. Each device connects over Bluetooth LE either to an Android phone or to a computer running the desktop client.
[Phone A] <--BLE--> [Heltec A] <--LoRa 868 MHz--> [Heltec B] <--BLE--> [Computer B]
What you can do
- Voice in PTT or VOX mode
- Text messages (up to 84 characters)
- Photos and files (up to 100 KB)
- Stations on a map and on a tactical radar
- Broadcast, private and group calls
- Repeater mode with WiFi monitoring
- 23 channels in the 863–870 MHz band (5 channels at 433 MHz on 433 MHz V3 boards)
- Use it from a phone (Android) or a computer (Windows, Linux, macOS)
Hardware
Device: Heltec WiFi LoRa 32 (V3 or V4)
| Parameter | Value |
|---|---|
| MCU | ESP32-S3 (WiFi + BLE 5.0) |
| LoRa | Semtech SX1262 |
| Display | OLED 128x64 (I2C) |
| Band | 863–870 MHz (EU868); 433 MHz V3 — 433.075–434.79 MHz |
| Power | USB-C or LiPo battery |
| TX power | 1–22 dBm (configurable) |
Both board revisions are supported. Their firmware is different — take the file whose name matches yours:
| Board | What is inside | Firmware file |
|---|---|---|
| V3 | SX1262, no external amplifier | firmware-v3-<version>.bin |
| V3 433 MHz | same, 433 MHz version | firmware-v3-433-<version>.bin |
| V4 rev 4.2 | GC1109 amplifier | firmware-v4-<version>.bin |
| V4 rev 4.3 | KCT8103L amplifier | firmware-v4.3-<version>.bin |
The revision is printed in small type on the back of the board, next to the GPS connector, as “HTIT-WB32LAF V4.3” or similar. Firmware for the wrong revision will boot, but the amplifier will be driven from the wrong pin: the device will hear poorly or will not transmit at all.
433 MHz boards (since 4.4.34, beta). Heltec V3 also comes in a 433 MHz version, and it has its own firmware, firmware-v3-433. It uses the LPD band: 5 channels from 433.225 to 434.425 MHz, 300 kHz apart, at no more than 10 dBm (10 mW). The app asks the radio for its band and shows the matching channels. Radios on 433 and on 868 MHz cannot hear each other, so the whole group needs boards of the same band. Use a 433 MHz antenna.
What you need
- 2 or more Heltec WiFi LoRa 32 devices (V3 or V4)
- for each device — an Android phone (5.0+) or a computer with the desktop client
- a USB-C cable for flashing
- an antenna for the board's band (868 or 433 MHz), screwed on before power is applied: transmitting without an antenna destroys the output stage
- optionally, a 3.7 V Li-Po battery with a JST 1.25 mm connector and a case. The board is the same one Meshtastic uses, so Meshtastic cases fit. For V3 the H1 Case works well — the project author uses it
First connection
1. Flashing the device
The simplest way is to flash straight from the browser: open the flashing page in Chrome or Edge, connect the device over USB and pick your board revision. If the board used to run Meshtastic or MeshCore, tick “Erase the whole board”: their leftovers in memory break the Bluetooth connection — the phone connects and drops at once. If that has already happened, flash with full erase, then remove the board in the phone's Bluetooth settings and connect from the app. Ready-made files are on the download page if you prefer to flash with your own tools (see the revision table above). From source:
cd firmware
pio run -e heltec_wifi_lora_32_V3 --target upload --upload-port /dev/ttyUSB0 # V3
pio run -e heltec_wifi_lora_32_V4 --target upload --upload-port /dev/ttyUSB0 # V4 rev 4.2
pio run -e heltec_wifi_lora_32_V43 --target upload --upload-port /dev/ttyUSB0 # V4 rev 4.3
After updating the firmware, update the app as well: the two agree on a shared protocol, and the pair "new firmware + old app" may fail to find each other over Bluetooth.
Flashing by hand, with esptool. You will need this if the browser wizard does not suit you (no Chrome or Edge, flashing from another computer). The firmware file alone is not enough — after a full erase the board has neither a bootloader nor a partition table left, and it goes into an endless reboot loop. Four files are needed, each at its own address:
# esptool 5.x — the command and flags use dashes
esptool --chip esp32s3 --port COM3 --baud 921600 \
write-flash -z --flash-mode dio --flash-freq 80m --flash-size 16MB \
0x0 bootloader-v4.bin \
0x8000 partitions-v4.bin \
0xe000 boot_app0.bin \
0x10000 firmware-v4.3-<version>.bin
# esptool 4.x — the same thing with underscores
esptool.py --chip esp32s3 --port COM3 --baud 921600 \
write_flash -z --flash_mode dio --flash_freq 80m --flash_size 16MB \
0x0 bootloader-v4.bin \
0x8000 partitions-v4.bin \
0xe000 boot_app0.bin \
0x10000 firmware-v4.3-<version>.bin
esptool version tells you which one you have. In version 5 the commands and flags moved to dashes and the entry point became plain esptool; the old spelling is refused.
The two mistakes people make most often:
- On the ESP32-S3 the bootloader goes to
0x0, not0x1000.0x1000is the address for the older ESP32; with it the board powers up and immediately reboots, over and over. - The V4 has 16 MB of flash, hence
--flash_size 16MB. The V3 has 8 MB and its own bootloader and partition table:bootloader.binandpartitions.bin.
All four files sit on the download page, in the "Flashing a V4 by hand" block under the firmware buttons.
2. Installing the app
Download the APK from the download page and allow installation from unknown sources — Android will ask about this itself. Every release is signed with the same key, so an update installs over the previous one without uninstalling.
From source:
cd android/MeshTRX
./gradlew assembleDebug
adb install -r app/build/outputs/apk/site/debug/app-site-debug.apk
3. Connecting over BLE
- Open the MeshTRX app
- Go to the Settings tab
- Press Connect — scanning starts
- The device appears as MeshTRX-XXXX
- Press the button on the device (>1 s) — a PIN appears
- Enter the PIN in the app
- The status changes to ● Connected (green)
If the phone does not see the device in the Bluetooth list. Check that both the phone and the device are on recent versions: before 4.4.3 the device went on air without a name, so the phone did not show it in the list. Update both sides — updating one will not help. If that does not help, power-cycle the device: it releases an abandoned connection on its own, but not instantly.
Desktop client (Windows / Linux / macOS)
The computer gives you everything the phone does: voice, text and voice messages, calls, files, radar, map, air encryption, the free-channel finder, settings and the repeater, plus the Main and Khaki themes. There is also a diagnostics log the phone does not have. The computer connects to the radio over Bluetooth, so the phone must not be connected to that radio at the same time.
Installing. The download page has ready-made apps for Windows, macOS (Apple M and Intel) and Linux — no Python or libraries needed.
- Windows: on first launch SmartScreen warns about an unknown publisher — "More info" → "Run anyway".
- macOS: unzip, then right-click MeshTRX → Open → Open; allow Bluetooth and microphone access.
- Linux: unpack and run
MeshTRX; Bluetooth (BlueZ) must be on.
Numbers on the Voice and Messages tabs are missed calls and unread messages, as on the phone. A voice message records while you hold the microphone button; double-click a voice message to play it. The app reports a new version under Settings → Check for updates.
Running from source (for developers):
python3 -m venv .venv
.venv/bin/pip install -r desktop/requirements.txt
.venv/bin/python desktop/run.py
Run this way, the client needs the system Codec2 library (libcodec2 on Linux and macOS, codec2.dll next to the program on Windows); the ready-made apps have it built in.
To transmit, hold the button with the mouse or press the space bar — with the same ten-second limit and the same countdown as on the phone. Details and a walk-through of the program are in desktop/README.md.
The main screen
The screen is laid out around how a radio is actually used: you look at the top and press at the bottom. So from top to bottom it goes network summary, listening modes, recent calls, who you are talking to, status line — and only then the Talk button, right at the bottom, under your thumb. Real radios put the button on the side where it is pressed without looking; a phone has nothing like that, and the one thing that can be done is not making you reach for the middle of the screen.
Network summary
Two lines above everything else answer the question "who am I actually in touch with right now":
3 stations heard · repeater TX-C4C8 (-71 dBm)
last: ANDREY, 2 min ago · -88 dBm, SNR 7
- stations heard — those whose beacons or transmissions arrived within the peer lifetime from the settings (an hour by default). A station that went quiet long ago is not counted: it is no longer part of the network;
- repeater — on its own, with the signal level to it. That is the main thing worth knowing before you speak: if the repeater is audible, your voice will reach beyond your own coverage. A radio in repeater mode marks itself in its beacon, so nothing needs configuring in the app;
- last movement on air — who came on, how long ago, and at what level. The level tells you not just "heard" but "will the answer make it back": -60 dBm is margin, -110 dBm is the edge.
If you see ≥0 dBm instead of a number, that is not a failure and not a missing signal but the opposite: the station is so close that the scale ran out. The receiver computes the level as minus half an unsigned number, so it cannot go above zero — previously a bare zero was shown here, and people read it the other way round.
Call sign and channel are deliberately absent here — they sit one line above, in the app's header.
Voice (PTT)
Codec
Codec2 at 3200 bps — intelligible speech at minimal use of the radio channel.
| Parameter | Value |
|---|---|
| Bitrate | 3200 bps |
| Frame | 20 ms / 8 bytes |
| Packet | 4 frames = 32 bytes = 80 ms |
| LoRa packet | 39 bytes (7 header + 32 audio) |
| Time on air | ~53 ms |
The delay comes from several places. The first cannot be removed: until 80 ms of speech has accumulated there is nothing to send — that is the floor, set by the packet size. On top of it come the Bluetooth hop to the device (connection interval 30–50 ms), the packet's time on air, the Bluetooth hop back and the playback buffer. We have not measured the end-to-end delay on real hardware, so no figure is given here: a conversation goes the way it goes on a radio — speak, release, wait for the answer.
How long you may talk: the ten-second limit
A single transmission takes the whole channel. LoRa is half-duplex: while somebody is talking, the others can neither answer nor call for help — they simply are not heard. So speech is limited to ten seconds in every mode:
| Where | What happens at the tenth second |
|---|---|
| Holding the button (PTT) | transmission stops by itself, the button shows a countdown; to continue, release it and press again |
| Voice activation (VOX) | the same, with the same countdown; to continue, pause — transmission restarts with the new phrase |
| Voice message in chat | recording stops and the message is sent as it is |
| Addressed voice | the same: up to 10 seconds are recorded and sent as a file |
The limit is duplicated inside the device itself, not just in the app: if the phone freezes or the button sticks, the radio still falls silent at the tenth second and frees the channel. LIMIT 10s appears on the device screen.
To talk longer, simply press again. The pause between transmissions is useful in itself: it gives the other side time to answer and lets the network carry other people's messages and calls.
PTT mode (push-to-talk)
- Make sure the PTT/VOX switch is set to PTT
- Press and hold the large round button
- Speak — the status shows ● transmitting… N s left
- Release the button and transmission stops
- The other side hears a short two-tone end-of-transmission signal (it can be turned off in Settings, the "Audio" section)
If you do not release it, transmission ends by itself at the tenth second.
VOX mode (voice activation)
- Set the PTT/VOX switch to VOX
- Transmission starts automatically when speech is detected
- States:
...(attack) →>>> TX <<<(transmitting) →TX (pause)(hangtime)
VOX settings (Settings tab):
- VOX threshold (0–5000) — sensitivity; the lower the value, the more sensitive
- VOX delay (200–2000 ms) — the pause before transmission ends
Loudspeaker
The speaker button (top right of the PTT button):
- Green — speaker on (default)
- Grey — speaker off (sound through the earpiece)
Noise gate (PTT RMS)
The PTT RMS slider in the settings (0–1000):
- 0 — off (everything is transmitted, default)
- 50–300 — light filtering of background noise
- 300+ — aggressive filtering (loud speech only)
Receive volume
The Receive volume slider in the settings (50%–300%, 200% by default).
Listening modes
Two buttons at the top of the PTT screen:
| Mode | Description |
|---|---|
| All | You hear every transmission on the channel |
| Mine | You hear only calls addressed to you |
The active mode is highlighted in green.
Calls
Call types
| Type | Button | Description |
|---|---|---|
| Broadcast | BROADCAST (blue) | A call to everyone on the channel |
| Private | CALL (green) | A call to one particular station |
| Group | via the picker | A call to a group (up to 8 participants) |
How to call
- Broadcast call: press BROADCAST — everyone on the channel is notified
- Private call: press CALL → pick a station from the list → the call is sent
- Incoming call: an overlay appears with ACCEPT / DECLINE
Recent calls
At the bottom of the PTT screen there is a scrollable list of recent calls:
- Shows unique entries (duplicates replace each other)
- Direction: → outgoing, ← incoming
- Colour by type: blue (broadcast), green (private), yellow (group)
- Tap to call again
Tab counters
A red number on the PTT tab shows how many calls you missed: the call ended and you neither accepted nor declined it. The number on the Chat tab shows how many messages (text and voice) arrived while the chat was not open. The number goes away when you open the tab.
Text messages
Sending
- Go to the Chat tab
- Type your text (up to 84 characters)
- Press the send button (the green arrow)
- By default this is a broadcast to the channel
Addressed messages
- Press the @ button next to the input field
- Pick a recipient from the list
- To: [name] appears above the input field
- Only the addressee receives the message
An addressed message carries a mark next to its time:
| Mark | Meaning |
|---|---|
| ⏳ | waiting for the addressee's radio to answer |
| ✓ (green) | delivered: the message is on the addressee's phone |
| ✓ accepted by node | the addressee's radio took it, but their phone is not connected right now — the message waits on the radio and shows up once they connect |
| ↑ | sent over the air, no answer — the message may have arrived and the answer got lost |
| ✗ | did not even reach your own radio — tap the message to send it again |
If the phone was disconnected from the radio
The radio keeps incoming messages while no phone is connected and hands them over on connect, with the time they actually arrived. Space is limited: about two hundred ordinary messages on a V3, several thousand on a V4. When it runs out, the oldest are dropped first. The buffer lives in memory and is lost when the radio is switched off. Requires firmware 4.4.32.
Notifications
When the app is in the background, an incoming message raises a system notification. Direct and group messages are kept apart: a message addressed to you personally arrives with sound, one sent to everyone arrives quietly. Under Settings, "Message notifications", you can choose all messages, direct only, or switch them off.
While the app is open there are no notifications: the messages are already in the chat.
The split needs firmware 4.4.31 — before it the radio never told the phone whom a message was addressed to, so everything counts as a group message.
Clearing the history
The bin button in the filter row deletes the whole conversation from this phone. The app asks for confirmation.
Messages are stored on your phone only: your correspondents keep their copies, and deleted ones cannot be recovered.
Voice messages
The button with a microphone sits to the right of the input field. Hold it and speak, release it, and a recording of up to 10 seconds goes into the chat. It shows in the conversation with a ▶ button, and both you and the recipient can play it as many times as you like.
- To: All (since firmware 4.4.35) — every radio on the channel gets the recording. Nobody confirms it, so the radio sends a short recording twice. Radios with older firmware drop such a message, so update the whole group.
- To: [name] — only the addressee gets the recording, with a delivery mark, the same as for text.
Filtering
Use the filter drop-down to show messages from one particular station or from everyone.
File transfer
Sending a photo
- Go to the Files tab
- Press Photo — the gallery opens
- Pick a photo — the app scales it down to 320×426, re-encodes it as JPEG and strips the metadata; the result is usually 5–20 KB
- Confirm sending
- Progress is shown in the list
Sending files
- Press File — the file manager opens
- Pick a file (100 KB max)
- The transfer starts automatically
Transfer parameters
| Parameter | Value |
|---|---|
| Max size | 100 KB |
| Chunk size | 120 bytes |
| Interval | 100 ms |
| Throughput | ~1.2 KB/s |
| An 11 KB photo | ~10 seconds |
The hundred kilobytes is a ceiling for any file, not the size a photo is squeezed to: a photo prepared by the app takes 5–20 KB and goes out in about ten seconds. The ceiling exists for two reasons at once. First, the device's memory: an incoming file is held whole in the radio's RAM, and there is about a hundred kilobytes of it free, so a request for more is refused outright rather than dropped halfway. Second, the air: the channel is single and half-duplex, and for the whole transfer nobody else can talk or send a message. Hence the rule of thumb: the smaller the file, the less of the shared channel you take.
What you can do with a file
Tap a file in the list:
- Share — send it to another app
- Retry — send it again
- Delete — remove it from the history
Map and radar
Map (OpenStreetMap)
- Shows your position and every station found
- Markers with call signs and signal level
- Dashed lines to the stations (colour by age)
- Buttons:
- Me — centre on your position
- All — show every station
Radar (tactical)
- Black background with green range rings
- Compass orientation (true bearing)
- Stations are drawn relative to your position
- Zoom buttons +/− (100 m to 100 km)
- A contrast button (normal / bright for outdoors)
- Auto-zoom to the furthest station (5 km by default)
- Brightness by RSSI
- Call sign on the dot
GPS
Android LocationManager is used (works without Google services). Updates every 15 seconds. GPS status is shown on the map screen.
Settings
Connection
- Connect / Disconnect — control the BLE connection
- New device — forget the current one and find another
Call sign
- Up to 8 characters, shown in the header and in the beacon
Radio
- Channel (0–22) — the working frequency (863.15–869.75 MHz)
- Find a free channel — the radio walks through every channel, listens to the air and shows where it is quietest. The 868 MHz band is a crowded place in a city: door phones, weather stations, meters and alarms all live there, and a busy channel hits voice first — voice needs a dozen packets in a row, while text only needs one lucky gap. The scan takes a couple of seconds and reception pauses meanwhile
- Switch channel for everyone — moves the whole group to the selected channel at once: the radio broadcasts the command and everyone who hears it, the repeater included, switches together after 10 seconds. No need to walk up to each device — which is not always possible anyway, since some radios are in other people's pockets. A radio that misses the command stays where it was; a radio that switched but heard nobody on the new channel for two minutes returns to the old one on its own, so it is never left alone somewhere nobody followed it
- TX power (1–22 dBm) — transmission range
- Duty cycle EU868 — the 1% limit for EU compliance
Audio
- Receive volume (50–300%)
- PTT RMS (0–1000) — noise gate
- End-of-transmission tone — the short signal that ends someone else's speech. It can be turned off if it gets in the way; the setting is remembered (since version 4.4.5)
- VOX threshold (0–5000)
- VOX delay (200–2000 ms)
The timbre of the voice itself cannot be adjusted: it goes on air through Codec2 at a constant 3200 bps, and there is no separate "modulation" control. Intelligibility is changed with the receive volume and the PTT RMS threshold: the higher the threshold, the more quiet sound is cut off before transmission.
Since version 4.4.5 every setting in this section is remembered and survives an app restart. In earlier versions they were reset to factory values on every close — if a VOX threshold you had tuned "went back to 800 by itself", this was why.
Beacon
- Beacon interval (Never / 1–60 min / 1 hour)
Station list
- Timeout for removing inactive stations (15 min to 24 hours)
File history
- Retention (7 / 14 / 30 / 90 days / Unlimited)
Repeater
- See Repeater mode
Appearance
- Main (blue and yellow) / Khaki — the app redraws in the chosen colours right away
Language
- Russian / English — switches instantly
Apply and save
The button sends the radio settings to the device and stores them in NVS.
Updates
At the bottom of Settings the app shows what has been released: Check for updates. Once a day it asks the site on its own and, if a newer version exists, says "App 4.4.13 is out, you have 4.4.12" and offers a Download button. It opens the file on the site; the installation itself is still confirmed by you in Android — that cannot be bypassed.
The firmware version is visible in three places: on the radio's screen at power on, in the app's Settings (the "Device" line), and on the repeater page if the radio runs as a repeater.
The same place in Settings shows which firmware your radio runs and which one is out. The radio reports its own version on connect, starting with 4.4.22; on older firmware that line is simply absent — those versions did not know their own number.
Firmware is not updated by a button: it is still flashed from a computer. The app only warns that a newer one exists.
With no internet the check quietly does nothing: a radio is needed exactly where there is no network, and complaining about it on every launch is pointless.
By default the air is in the clear: anyone with the same radio on the same channel hears the whole conversation. To change that, set a group passphrase — Settings → Traffic encryption.
How it works:
- the radio itself derives a full key from the passphrase; the phrase is never transmitted and is not stored on the phone;
- the same phrase must be entered on every radio in the group, repeater included;
- a fingerprint appears below — four characters, identical on every device whose key matches, so the key can be verified out loud without saying it;
- deriving the key takes about three seconds; that delay is the protection against guessing;
- the phrase must be at least eight characters, and several words are better: a short one is cracked in an evening.
What is encrypted today: voice and text messages. Files and beacons still travel in the clear, which means call signs and coordinates are visible to an outsider. That is stated plainly so you do not count on more than there is.
If someone nearby uses a different key, the app says so: a line appears under the fingerprint — "someone nearby uses a different key". That is the main sign the phrases diverged, for instance because a keyboard added a trailing space. Compare the fingerprint on every radio: it matches only where the phrase matches.
Also hear unencrypted traffic. If you need both the open shared chat and encrypted conversations with your own group, switch this on next to the passphrase. Unencrypted messages become visible again and are marked with the words "unencrypted" in red so that protected and unprotected do not look alike. It is off by default, and here is why:
A radio with a key does not listen to unencrypted traffic. Once a passphrase is set, unencrypted voice and messages are dropped — including from your own people whose key is missing or whose firmware is older. Otherwise a single such radio is enough for the conversation to bypass encryption while everyone believes it is closed. So set the key on all radios at once and compare the fingerprint: it matches only where the phrase matches.
The repeater needs no key: it forwards packets without looking inside. Even somebody else's repeater will carry your conversation without hearing it.
What encryption does not give you. It does not protect against someone who already has the key: there is one key per group, and when a person leaves it must be changed everywhere. It does not protect against physical access to the board — the key lives in its memory. And it does not hide the fact of transmission at all: direction finding sees that someone came on air and for how long, without understanding a word. The full reasoning is in Encryption in 39 bytes.
Repeater mode
A device can work as a standalone repeater — it receives LoRa packets and forwards them, decrementing the TTL.
A running repeater marks itself in its beacon, so nearby stations see it on its own line in the main screen summary: "repeater TX-C4C8 (-71 dBm)". Nothing needs configuring, but the radios need firmware 4.4.18 or newer and app 4.4.11 or newer.
How much voice gets through a repeater
About half the voice packets make it through a repeater, and that is not a defect. It works in the same channel and the same half-duplex as everyone else: while it repeats one packet, it cannot hear the next. A voice packet occupies the air for about 53 ms and is sent every 80 ms — one talking station takes two thirds of the channel, repeating doubles the load, and it no longer fits.
For speech that is tolerable: an 80 ms gap sounds like a click, not a hole. For files it would be bad, which is why files travel with acknowledgements and re-requests for the missing pieces.
The practical conclusion: a repeater increases coverage, not the capacity of the air. Three repeaters that hear each other will not carry voice in one channel — such a network needs zones and a separate link between repeaters, and that is still on the roadmap.
What gets forwarded
| Packet type | Forwarded |
|---|---|
| Voice (0xA0) | Yes |
| Text (0xB0) | Yes |
| Files (0xC0, 0xC1, 0xC3) | Yes |
| Beacon (0xD0) | Yes |
| Calls (0xE0–0xE6) | Yes |
| File ACK (0xC2) | No |
Turning it on
- Go to Settings → the Repeater section
- Optionally enter a WiFi SSID and password to join a network
- Optionally enter a static IP
- Press ENABLE REPEATER
- Confirm in the dialog
- The device reboots into repeater mode
WiFi monitoring
Once enabled, the device brings up WiFi:
- Without an SSID: it creates the access point
MeshTRX-Repeater(password:meshtrx123) - With an SSID: it joins that network and shuts its own access point down — one transmitter next to the antenna is enough. Any network works, a phone hotspot included; the repeater only needs internet for the map tiles
- If the network stays gone for more than half a minute, the access point comes back on its own, so a phone next to the repeater can still reach the page. Right after a new network is saved the access point keeps running for three more minutes — otherwise you would be thrown off it exactly when the page shows you the new address
The web interface is available at:
- AP mode:
http://192.168.4.1 - STA mode: at the address you set or received
Web interface
The page refreshes every 5 seconds and shows:
- Uptime — how long it has been running
- Channel — the current one, with a drop-down to change it
- TX power
- Forwarded / Dropped — packet counters
- By type: audio, text, file, beacon
- RSSI range — minimum and maximum signal level
- IP address
Changing the channel
The channel can be changed:
- from the web interface: the drop-down with Set changes the repeater itself, Set all moves the whole network
- from the app (connect over BLE and change it in the settings)
Turning it off
- From the app: Settings → Disable repeater (BLE stays available in repeater mode)
- The device reboots into normal mode
Deduplication
- A cache of 64 entries, a 30-second window
- The TTL is decremented on every retransmission
- Packets with TTL=0 are not forwarded
- A random delay of 10–50 ms avoids collisions
The button on the device
In normal mode
| Press | Action |
|---|---|
| Short (<1 s) | Turn the screen on for 30 s |
| Medium (>1 s) | Show the PIN and the device name for 10 s |
| Long (>3 s) | Turn the device off |
In repeater mode
| Press | Action |
|---|---|
| Short | Turn the screen on |
| Medium (>1 s) | Reset the statistics |
| Long (>3 s) | Leave repeater mode |
| Very long (>8 s) | Turn the device off |
Turning the device off and on
There is no power switch on the board, so the button plays that role. Hold it for three seconds: SLEEP appears on the screen in large type and the device goes to sleep — radio, amplifier and display lose power, consumption drops to microamps, and a battery lasts for months of standby.
The same button turns it back on; a short press is enough. Waking from this sleep is a full start, exactly as after applying power, so the link and the settings come back on their own. In the log it shows as reason=DEEPSLEEP wake=BUTTON.
In repeater mode the threshold is longer — eight seconds: there the shorter holds are already taken by resetting the statistics and leaving the mode. While you hold the button a countdown runs on the screen, so you are not holding it blind.
Indicators
OLED display
Normal mode: channel, frequency, RSSI, SNR, TX power, BLE status, battery voltage (two decimals), VOX status.
Repeater mode: ** REPEATER **, channel, frequency, FWD/DRP counters, last RSSI/SNR, TTL.
The screen turns itself off after 30 seconds.
LED (GPIO35)
| Pattern | Meaning |
|---|---|
| Solid | Transmitting (TX) |
| Blinking ~300 ms | BLE waiting for a connection |
| Short flash every 5 s | BLE connected |
| Fast blinking | File transfer |
| Short pulse | Packet received (RX) |
App header
| Element | Position | Description |
|---|---|---|
| Call sign | Top left | Large white text |
| Device name | Bottom left | Small grey text |
| Status | Top right | ● Connected (green) / Disconnected (grey) |
| Channel + frequency | Bottom right | Green text, "CH 5 · 864.65 MHz" |
Bottom navigation
Five tabs: PTT, Chat, Files, Map, Settings. The active tab is highlighted in green.
Specifications
LoRa radio
| Parameter | Value |
|---|---|
| Band | 863.15–869.75 MHz |
| Channels | 23 (300 kHz apart) |
| Bandwidth | 250 kHz |
| Spreading factor | 7 |
| Coding rate | 4/5 |
| Sync word | 0x34 |
| Power | 1–22 dBm |
| Range | up to 5+ km line of sight; measured in a city — voice ~1 km, text ~2 km; in open country — voice up to 2 km, text beyond that |
Audio codec
| Parameter | Value |
|---|---|
| Codec | Codec2 3200 bps |
| Sample rate | 8000 Hz |
| Frame | 160 samples = 20 ms = 8 bytes |
| Packet | 4 frames = 32 bytes = 80 ms |
| LoRa packet | 39 bytes (7 header + 32 audio) |
BLE protocol
| Parameter | Value |
|---|---|
| Service | Nordic UART Service (NUS) |
| MTU | 128 bytes |
| Commands | 40+ (0x01–0x28) |
| Audio packet | 36 bytes (cmd + flags + sender + 32 payload) |
| Authorisation | a 4-digit PIN (derived from the MAC) |
LoRa packets
| Type | ID | Size |
|---|---|---|
| Voice | 0xA0 | 39 bytes |
| Text | 0xB0 | up to 91 bytes |
| File (header) | 0xC0 | 36 bytes |
| File (chunk) | 0xC1 | up to 128 bytes |
| File (end) | 0xC3 | 6 bytes |
| Beacon | 0xD0 | 36 bytes |
| Calls | 0xE0–0xE6 | 8–47 bytes |
Battery
| Parameter | Value |
|---|---|
| ADC | GPIO1 through a divider |
| Control | GPIO37 enable |
| Calibration | multiplier 5.55 |
| Averaging | 8 samples |
| Range | 3.0 V (0%) – 4.2 V (100%) |