convoy-mesh

Off-grid, phone-native mesh comms for a convoy of vehicles, using cheap ESP8266 boards as a pure transport backbone.

Born from a real problem: going off-roading with Jeeps where there's no cell coverage, and wanting free, real-time communication between cars — voice, position, and shared media — with no carrier, no internet, and no radio license.


The core idea

The phones are the computers. The ESPs are the ISP.

  • Phones own everything smart: GPS, accelerometer, cameras, microphone, speakers, storage, UI, and the audio/video codecs. All sensing, encoding, decoding and application logic live here.
  • ESP8266 boards do exactly one thing: move bytes between cars. They form a self-relaying wireless backbone and never touch audio or application logic.

You build the transport firmware once. After that, every feature is just a phone app talking over the bus — no firmware changes ever again. That decoupling is what makes this a platform rather than a single gadget.

 Phone A  <--WiFi-->  ESP A  <==mesh==>  ESP B  <==mesh==>  ESP C  <--WiFi-->  Phone C
 (sensors,            (dumb              (relay)            (dumb              (sensors,
  codecs, UI)          router)                               router)            codecs, UI)

Why the ESP8266 is the right transport (and where its limits really are)

Real numbers, not vibes:

  • ESP8266 usable throughput: ~1–5 Mbps (single 80/160 MHz core, modest Wi-Fi MAC).
  • It's a shared, half-duplex 2.4 GHz medium: the whole mesh shares airtime, and each relay hop roughly halves end-to-end throughput (one radio, store-and-forward).
  • No FPU → heavy codecs (Opus) are too slow on-chip. Solution: don't encode on the ESP. The phone encodes; the ESP relays already-compressed bytes.

The trick that makes voice trivial: keep audio DSP on the phone, let the ESP be a dumb, fast packet forwarder.


Transport design: a prioritized message bus

The ESP mesh is not a full IP network (that's the OpenWRT-router tier). It's an application-layer message fabric:

  • Each phone joins its own car's ESP soft-AP and opens one connection (a websocket — cnlohr's esp82xx framework is a natural fit — or a WebRTC datachannel for UDP-style delivery).
  • Phones send addressed messages: broadcast, or to: car3.
  • The mesh forwards hop-to-hop. For 3 cars, ESP-NOW broadcast is ideal: connectionless, ~1–2 ms/packet, one transmit reaches all peers in range; a middle car re-broadcasts when the ends can't hear each other. (painlessMesh is the alternative for larger, self-healing meshes.)

The one firmware feature that makes or breaks it: two priority lanes.

Lane Traffic Rule
Realtime voice frames, telemetry, control always sent first, never blocked
Best-effort photos, music files, logs fills spare airtime, yields to realtime

Without this, a photo transfer stalls a conversation. With it, everything coexists.


Feasibility by use case

Ceiling to keep in mind: ~1–5 Mbps shared, halving per hop.

Use case Cost Verdict on ESP8266 mesh
Voice (Opus ~24 kbps; Codec2 as low as ~3 kbps) ~24 kbps/talker ✅ Trivial, real-time
Live car data (GPS, accel, OBD-II) few kbps/car ✅ Basically free — the killer app
Shared map / who's-tilted / breadcrumbs few kbps ✅ Free
Synced music — control + timing few kbps ✅ Yes, and the smart way (see below)
Music as a live audio stream 128–320 kbps ⚠️ One stream OK; tight on multi-hop
Photo / snapshot sharing 50–200 KB bursts ✅ Best-effort lane
Live video — one low-res stream, one hop 0.5–1.5 Mbps ⚠️ Borderline, near ceiling
Live video — everyone to everyone several Mbps ❌ Exceeds ESP8266 → ESP32 / HaLow tier

Sweet spot: voice + telemetry + playback-sync + snapshots, comfortably up to ~6–8 cars before shared-channel contention bites.

Real-time voice latency budget (3 cars, phones do the DSP)

Target: under ~150 ms one-way feels like a phone call (ITU G.114).

Stage Latency
Mic capture + Opus frame (phone) ~20–40 ms
Phone → ESP (Wi-Fi, one hop) ~2–5 ms
ESP → ESP relay (ESP-NOW, 1–2 hops) ~2–8 ms
ESP → phone (Wi-Fi) ~2–5 ms
Jitter buffer (phone) ~40–60 ms
Decode + play ~10 ms
Total one-way ~80–130 ms ✅

With 3 voice streams at ~24 kbps = ~72 kbps, the channel sits ~95% idle. Bandwidth was never the problem; range and topology are.


The feature that falls out for free: time sync

Because it's a shared bus, run a lightweight clock sync over it (one car = time master, others discipline to it — crude PTP, few-ms accuracy). At near-zero bandwidth this unlocks:

  • Convoy-wide synchronized music — pre-share tracks over the best-effort lane while parked, then play track 7 at T+3.000s makes every car's speakers play in unison. The whole convoy becomes one sound system. This is the right way to do "shared playlist": sync the clock and control, not the audio bytes.
  • Same-moment multi-cam — synchronized snapshot from every phone on a countdown.
  • Coherent telemetry — everyone's GPS/accelerometer on one timeline; the shared map shows in real time who's climbing, stopped, or just took a hard hit.

Then the app grows forever on the same bus: Marco-Polo find-me ping, auto "I'm stuck + exact position + photo", tire-pressure/temp alerts, distributed dashcam (record locally, share clips later), a trip log stitched from everyone's GPS.


Honest limits

  • Aggregate ~1–5 Mbps, shared, halving per hop. Great up to ~6–8 cars for realtime+data+snapshots.
  • All-to-all live video is out — that's the genuine ceiling. Step to ESP32 (faster radio/CPU) or a Wi-Fi HaLow / OpenWRT router mesh if video-to-everyone is a must-have.
  • Range per hop is 2.4 GHz physics (~100–200 m line-of-sight per hop, less through terrain). An antenna problem, fought with external whips and a relaying middle car (~2× end-to-end via relay).
  • soft-AP + mesh must share one channel on the ESP8266 — the fiddly integration bit (cleaner on ESP32).
  • Moving vehicles fade / drop packets — inherent; Opus packet-loss concealment + a little FEC hide it. Push-to-talk (one talker) removes contention and masks loss.

Hardware notes (learned the hard way)

  • The NodeMCU v3 (LoLin, ESP-12E) has no antenna connector — the gold zig-zag trace on the module is a PCB antenna, permanently attached. Fine for bench prototyping.
  • For real range, use boards with a u.FL/IPEX or SMA connector (ESP-07S; or ESP32 boards that ship with an SMA whip). Modding a u.FL pigtail onto an ESP-12E is possible but delicate SMD rework.
  • Biggest range factor in a car: the metal cabin is a Faraday cage. Placement beats antenna type — get the radiating element outside the bodywork (windshield base, or a roof/hood whip).

Roadmap

  1. Two-board voice — ESP-NOW relay firmware + phone web app (Opus over WebRTC datachannel or esp82xx websocket). Prove <150 ms real-time voice between two cars.
  2. Add telemetry — GPS + accelerometer on the realtime lane; shared live map.
  3. Add clock sync + synced music — pre-shared tracks, unison playback.
  4. Add snapshots — best-effort photo lane with priority yielding.
  5. Scale + range — third car (relay path), external antennas, in-cabin mounting, PTT UX.
  6. If video-to-everyone is needed — migrate transport tier to ESP32 or HaLow/OpenWRT mesh.

Status

Concept + feasibility captured. Hardware on hand: 2× NodeMCU v3 (ESP8266, PCB-antenna only) — enough to prototype phases 1–4.

Inspiration: the cnlohr school of embedded — treat peripherals as raw timing engines and refuse to accept a datasheet limit before you've done the math.

S
Description
Off-grid phone-native mesh comms for a convoy: ESP8266 boards as a pure transport backbone (voice, telemetry, synced media). Concept + feasibility.
Readme
28 KiB