MeshCore · community fork · espnow-ip-bridge

Trifecta Repeater — setup & config

Assumes you've already decided this makes sense for your repeater. If you're still deciding, see the Trifecta overview first.

Real-LoRa repeaters this runs on today: Heltec V3 (Heltec_v3_repeater_bridge_espnow_ip), Heltec V4 (heltec_v4_repeater_bridge_espnow_ip), and Xiao S3 WIO (Xiao_S3_WIO_repeater_bridge_espnow_ip) — each also has an _debug variant with full bridge/routing logging on, for pairing with watch_boards.py below. Getting the right environment onto your board (PlatformIO, a web flasher, whatever you normally use) isn't covered here — this page picks up once you're already running it.

1

Configure whichever legs you need

ESP-NOW bridge (for Sidecars to attach to)

set bridge.channel <selected wifi channel>
set bridge.secret <your key>

Whatever you set here is exactly what a Sidecar board needs configured to match — see the Sidecar setup page.

IP bridge (to link to another Trifecta repeater)

set wifi.ssid <your ssid>
set wifi.pwd <your password>
set ip.host <peer host or IP>   # set = dial out; empty = listen instead
set ip.port <port>
set ip.secret <key>              # TLS-PSK, must match the peer exactly
WiFi and ESP‑NOW share one radio. bridge.channel must exactly match whichever channel your WiFi access point actually operates on — it doesn't get synced automatically. Make sure that AP is locked to a fixed channel rather than left on auto-select; many routers pick a new channel on reboot or via automatic interference avoidance, which would silently break this until you update bridge.channel to match again.

Multiple IP peers on one repeater (listening side only)

Leaving ip.host empty makes this board a listener, and a listener can accept more than one peer at once — a remote repeater over the internet and a local no‑LoRa gateway, say — each with its own revocable credential instead of everyone sharing one ip.secret:

set ip.peer.add <8‑hex‑char id> <secret only this peer knows>
get ip.peer.list
set ip.peer.remove <id>

The id is the first 4 bytes of the connecting peer's public key (its get public.key, or shown in ip.status once connected). Matching is case‑insensitive. Each connecting peer still presents its own identity via its own ip.secret on its side — this only changes how the listener resolves and authenticates them.

A peer registered here doesn't have to be another repeater — a direct-IP companion connects the same way, presenting its own identity and secret exactly like any other peer.

2

Verify it's actually working

Don't just assume — these cover every hop:

get wifi.status
get bridge.channel
get ip.status
neighbors.all

wifi.status confirms the board actually associated (connected, IP, RSSI). bridge.channel shows the configured ESP‑NOW channel next to the radio's actual live channel and flags it explicitly if they've drifted apart. ip.status reports whether the TCP+TLS‑PSK tunnel to the peer is currently up. neighbors.all merges RF-heard and bridge-heard neighbours into one list with a via column.

3

Watch multiple boards at once

$ python3 watch_boards.py

Auto-detects every connected board, connects to all of them, and streams debug output live in one terminal. Press n to dump neighbors.all, b for bridge status, c to toggle watching companion boards, from every connected board at once.