Inspiration

We were drawn to the CHRP track because it sits at the intersection of two things we care about: resilient communication and tight constraints. In a world that assumes constant connectivity, the idea of turning any iPhone into an off-grid mesh radio felt immediately useful—whether for festivals, disasters, or places where cell service simply doesn’t exist. The technical challenge was equally compelling: how do you carry text, voice, and video over a radio designed for tiny text messages, where each packet is only ~230 bytes and links drop to 1 kbps with frequent loss? We wanted to see how far software could go when the physics of the radio were the real limiting factor.

What it does

Team Water is a software simulation of an off-grid LoRa mesh that runs entirely locally. It lets you send text, voice notes, and compressed images/video across a network of virtual nodes with realistic data rates, packet loss, and multi-hop routing.

  • Mesh simulation: 5+ virtual nodes on a map that relay packets with distance-based connectivity, airtime modeling, and configurable packet loss.
  • Aggressive compression: Text is sent as-is; voice is encoded with Opus (first ~5 seconds); images are heavily compressed; video is reduced to a short, silent summary.
  • Reliability layer: Messages are split into ~230-byte chunks with sequence numbers, ACKs/NACKs, retransmission of missing pieces, and reassembly so a message can arrive whole even with 20% loss across multiple hops.
  • Honest delivery status: The UI shows exactly what has arrived, what’s still in transit, the route taken, progress, and ETA. It never marks something “delivered” until the receiver has verified the full content.
  • Local demo: A voice note and an image can be sent across the simulated mesh while the system recovers from loss in real time.

Everything runs on your machine, no external services required.

How we built it

We started with a pure Python mesh simulation (MeshBackend) that modeled nodes, distance based connectivity, packet loss, and multi-hop flooding with deduplication. On top of that we built a reliability layer that chunks payloads, tracks ACKs, and retransmits missing pieces.

Media handling lives in a separate module that aggressively compresses voice (Opus), images, and short video summaries before they hit the radio. A local FastAPI service exposes these capabilities over HTTP and WebSocket so the frontend can send messages and receive live state updates.

For the frontend we built:

  • A browser console (apps/console) that shows two phones and a mesh inspector
  • An Expo mobile app (apps/mobile) for iOS/Android
  • Shared packages for transport, state, and the phone UI

Shared types are generated from an OpenAPI spec so the Python backend and TypeScript frontend stay in sync. The whole system is structured so the mesh simulation can be imported and used independently of the HTTP service.

Challenges we ran into

The hardest part was staying honest under extreme constraints. A one-second voice clip can take a minute to arrive, and packets are lost at every hop. We had to:

  • Design a chunking and retransmission scheme that could recover from 20%+ loss across 3 hops without the UI lying about progress.
  • Keep the delivery status truthful, never saying “delivered” until the receiver had actually verified the full content.
  • Compress media aggressively enough to fit the radio while still being recognizable on the other end.
  • Model airtime and multi-hop latency realistically so the ETA and progress indicators felt grounded rather than optimistic.
  • Keep the simulation deterministic enough for demos while still feeling like a lossy radio network.

Separating the pure backend from the service layer also took iteration so the simulation could be reused without pulling in the HTTP server.

Accomplishments that we're proud of

  • A working end-to-end local demo that sends a voice note and an image across a 5+ node mesh with packet loss, and recovers.
  • Delivery status that is genuinely honest: the UI shows route, progress, missing chunks, and only marks a message delivered after verification.
  • A clean separation between the mesh simulation and the service layer, plus generated shared types from OpenAPI.
  • Reasonable media efficiency given the ~230-byte packet limit.
  • A self-contained system that runs entirely on a single machine with no external dependencies.

What we learned

We learned how unforgiving low-bandwidth, lossy links really are. Most of the work wasn’t in the happy path, it was in recovery, status honesty, and making the user experience reflect the actual radio rather than hide it. We also got a clearer sense of where software can help (compression, retransmission, clear status) and where the radio itself is the hard limit. Working with generated types and a strict OpenAPI source of truth made collaboration between backend and frontend much smoother.

What's next for Team Water

  • Tighter integration with real LoRa hardware (or more accurate radio models).
  • Better media strategies: AI-generated descriptions as a fallback, more efficient keyframe approaches, and adaptive quality based on measured link conditions.
  • Persistent message history and multi-device identity.
  • Stronger error correction and opportunistic routing.
  • A polished mobile experience that works fully offline against the local mesh simulation.
Share this project:

Updates

Submission history