Blog

  • Building the MeshRoute clients: iOS companion and Heltec V3

    A radio protocol becomes a useful product only when a person can operate it without living in a serial console. MeshRoute is therefore growing two complementary client interfaces: a native iPhone companion for full conversations and configuration, and a compact onboard interface for the Heltec WiFi LoRa 32 V3.

    They solve different problems. The phone has space for contacts, message history, maps, and detailed network state. The Heltec has a 128×64 display and one button, but it is always attached to the radio and can remain useful when taking out a phone is inconvenient. The design is not trying to force both devices into the same shape.

    The iPhone companion: the full human interface

    The MeshRoute companion is a native SwiftUI application. It does not turn the iPhone itself into a LoRa radio. Instead, it connects over Bluetooth Low Energy to a nearby MeshRoute node, which handles all radio communication.

    The connection uses a Nordic UART Service-compatible Bluetooth transport. Commands travel from the app to the node as compact text lines, while the node returns newline-delimited JSON events. This deliberately simple boundary is shared with the firmware’s console command layer, while the app keeps the user-facing details—names, contacts, conversations, and local history—on the phone.

    The current app is organized around four areas:

    • Messages for direct-message threads and channel conversations.
    • Contacts for the human-readable identity book and QR-based contact exchange.
    • Mesh for network and team information, including team sharing and joining flows.
    • Device for connection state, identity, routes, airtime limits, configuration, and diagnostics.

    The message model is designed for an intermittent connection. Outgoing messages can wait in a local outbox and drain when the phone reconnects. The app keeps its own durable archive, de-duplicates messages pulled from the node, tracks delivery state, and can notify the user about a new direct message received while the app is not in the foreground.

    Contact QR codes help two people exchange public identities in person. Team QR codes are a more sensitive operation because they can contain the material needed to join an encrypted team; the interface therefore places sharing behind an explicit reveal and warns that the QR is private.

    The Bluetooth boundary today

    The real Bluetooth companion transport currently runs on the XIAO nRF52840 target. It requires a paired, encrypted link before the command channel can be used. The app has already exchanged direct messages and channel posts with real test hardware, and it also has a mock-node mode for developing screens without a radio.

    The Heltec V3 build does not currently expose this phone-facing Bluetooth transport. Its ESP32-side BLE implementation is intentionally an inert stub for now. That makes the Heltec interface described below a separate client surface, not a second way for the iPhone app to connect.

    Heltec V3: a field interface on the radio

    The Heltec WiFi LoRa 32 V3 combines an ESP32-S3, an SX1262 LoRa radio, a small SSD1306 OLED, and a user button. MeshRoute now has a board-specific display driver plus a board-independent interface model built for those constraints.

    The onboard interface provides status, team, inbox, and send screens. It can show the node and team identity, recent direct-message and channel activity, a bounded teammate list, and compact delivery outcomes. A short press moves through screens or list rows. A double press activates the selected item. Because there is no keyboard, direct replies and team-channel posts use a small, deliberate set of canned messages.

    A long press is reserved for the emergency flow. The interface arms before it fires, can be cancelled before commitment, and uses bounded retries. Outcomes such as “picked up,” “not heard,” or “reply” are tied to evidence from the specific transmission instead of any unrelated network activity. This is careful engineering around a high-consequence interaction, but it is still under test and must not yet be treated as a certified safety feature.

    Keeping the display from disturbing the radio

    The screen is not allowed to become the most demanding part of the node. The OLED is painted in small page-buffered chunks rather than as one large blocking transfer. Rendering waits for an idle point in the radio work, visible updates are throttled, and the display blanks after inactivity. The separation between the pure interface model and the Heltec-specific drawing code also makes gesture and state behavior testable without the board attached.

    What is still unfinished

    Both clients are active development work. The iOS app still needs release preparation and remaining lifecycle work such as a more complete long-lived Bluetooth session; firmware update support is also planned rather than finished.

    On the Heltec V3, the current battery reader is deliberately unavailable, so the display shows “–” instead of inventing a plausible voltage. The durable inbox storage backend for the Heltec is also still pending. The interface code can render inbox rows, but the hardware cannot yet promise a persistent message history across restarts.

    That honesty is part of the development process. A visible placeholder is better than a confident but false value, and a clearly described limitation is better than presenting a prototype as a finished product.

    One network, two ways to use it

    The long-term role of the iPhone companion is depth: full text entry, contact management, history, configuration, and a clear view of the surrounding mesh. The role of the Heltec interface is immediacy: glance at status, see who is present, inspect recent activity, and perform a few important actions directly on the radio.

    Neither client is the network. MeshRoute continues to carry traffic without a phone, cloud service, or central account. These interfaces simply make that network accessible in two different field situations. I will keep documenting both as they move through hardware validation toward the first public release.

    Follow the project status or inspect the current source on GitHub.

  • Heltec Mobile: turning MeshRoute into a standalone field terminal

    Over the last several days, the Heltec Mobile build has moved well beyond “MeshRoute firmware running on a development board.” It is becoming a self-contained field terminal: a roaming LoRa endpoint with its own display, one-button controls, team messaging, local settings, battery readout, and a deliberately cautious emergency flow.

    The hardware is the Heltec WiFi LoRa 32 V3: an ESP32-S3, an SX1262 LoRa radio, a 128×64 OLED, and one user button. The interesting work is not simply drawing text on that screen. It is making a tiny interface tell the truth about a changing radio network while staying out of the radio’s way.

    Hand holding a transparent-cased Heltec V3 MeshRoute device with its OLED screen lit; a second radio is visible behind it.
    A Heltec V3 running the MeshRoute mobile interface during a two-device test.

    A mobile is a distinct network role

    The heltec_mobile firmware profile is built for a personal endpoint rather than a fixed relay or gateway. It removes the remote-management subsystem from this physically portable and therefore more easily captured device. The mobile is expected to be managed locally, through its onboard interface today and through an appropriate companion transport in the future.

    A mobile keeps a stable cryptographic identity while the fixed network gives it a temporary local address. A fixed node that can currently hear the mobile becomes its home and performs the last hop for incoming traffic. The attachment may change as the person moves, but the identity does not.

    Making home attachment something the device can trust

    A major part of the recent work has been making that home relationship explicit and testable. Receiving an offer is not enough. Sending a claim is not enough either. The mobile now treats a new attachment as provisional until the selected home sends a roster that echoes the same cryptographic hash, assigned local ID, and registration epoch.

    That distinction closes an uncomfortable gap: previously, a mobile could report itself as registered even when its claim had never reached the home. The mobile and the app could believe in an attachment that the fixed node did not actually know about. Now the “registered” state has to be earned by confirmation from the other side.

    Once attached, the mobile checks the home periodically. Only a probe that the local transmitter actually accepted may count as an unanswered check. If the radio was too busy even to send the probe, the firmware does not blame the home for being silent. Lost claims use a bounded re-claim process; a genuinely lost home eventually tears down the stale attachment and returns the mobile to discovery.

    The firmware also keeps observations of alternative homes, including their freshness and link quality. The current roaming policy is intentionally conservative: a weak but consistently responding home is retained. A broader proactive search was measured to create too much roster traffic and additional collisions, so proactive switching before connectivity begins to fail is still being refined rather than presented as finished.

    A complete one-button interface

    The onboard interface now has five main screens: Status, Team, Inbox, Send, and Settings. A short press moves through screens or list rows. A double press activates the selected item. A long press is reserved for the emergency interaction, from any screen.

    The Team screen shows the teammates the mobile can currently route to, with a stable selection tied to the teammate’s identity rather than a row number. If the roster changes while somebody is selected, the interface refuses the action and asks the user to choose again instead of silently sending to whoever moved into that position.

    Without a keyboard, the mobile uses a deliberately small set of canned messages for direct replies and team-channel posts. It is not intended to replace the iPhone companion for long conversations. Its purpose is immediacy: see the state, check recent activity, acknowledge a message, and perform important actions without taking out another device.

    Emergency behavior that avoids false confidence

    The emergency gesture sends a fixed encrypted team-channel message—“I’m in danger”—and attaches location only when a position fix is actually available. A missing fix must never suppress the alarm itself.

    The flow arms before firing, can be cancelled before commitment, and uses a bounded budget of three accepted transmissions. The screen distinguishes blocked, failed, picked-up, not-heard, and reply outcomes. Most importantly, those outcomes are correlated with the specific send. An unrelated channel post must not be allowed to complete an emergency transaction or create a comforting but false success message.

    The latest transmission work goes one step further: a locally originated message remains QUEUED until the SX1262 reports that it actually aired, and only then may the interface say SENT. Delivery or relay confirmation remains a separate, later fact. This hardware-completion path is implemented in the current development tree and still needs its final real-radio bench confirmation.

    The inbox is now useful on the device

    The Heltec display can browse recent direct messages and channel posts, open a message into a paged detail view, and deliberately delete an individual entry. Direct messages and channel traffic receive separate space so a busy channel cannot evict every direct-message preview from the display.

    On ESP32 this inbox is currently a bounded RAM ring with 32 records per kind. It works during the running session and reports a new storage epoch after a reboot, but its history does not yet survive power loss. The durable flash backend remains future work, so the article does not call the Heltec inbox persistent.

    Settings without a serial console

    A new Settings screen makes several important choices available through the same button: default direct-message encryption, automatic key attachment during introductions, mobile auto-registration, and entry into provisioning. Values are edited in a RAM draft first. The user can save, discard, go back, or reload when another configuration writer has changed the underlying record.

    The interface exposes conflicts and reboot requirements instead of hiding them. Unsaved changes are marked, a conflicting external change produces a reload warning, and a saved value that takes effect only at boot leaves a visible “RESTART NEEDED” reminder.

    There is deliberately no Bluetooth setting on this Heltec screen today. The phone-facing companion transport is compiled for the nRF52840 target, not the ESP32-S3 Heltec build. Showing a control that cannot affect the device would be another false promise.

    Battery measurement without a permanent drain

    The battery field is no longer just a placeholder. The board layer now samples the Heltec battery circuit in an eight-reading burst, enables the voltage divider only while measuring, and parks it again immediately afterward. It probes the control-line polarity rather than assuming that every board sold as “V3” uses the same electrical revision.

    Readings outside a plausible one-cell LiPo range are reported as unavailable instead of displayed as a believable number. The remaining work is physical validation: the ADC scale and detected polarity still need comparison with a multimeter on the exact board revision in hand.

    The screen must not interfere with the radio

    The OLED is updated through a 128-byte page buffer instead of one large blocking frame. Painting proceeds in small pieces, waits for the radio state to permit it, throttles visible updates, and blanks the panel after inactivity. Gesture meaning, send attribution, inbox selection, and settings behavior live in board-independent code that can be exercised by native tests; the Heltec-specific layer only owns the display, button, power rail, and battery pins.

    What Heltec Mobile is—and is not—today

    Heltec Mobile is now recognizably a field device rather than a board that requires a laptop beside it. It can attach to a fixed MeshRoute network, participate in an encrypted team, show network and message state, send a small set of useful responses, edit key settings, and expose an emergency interaction directly on the radio.

    It is still pre-release engineering on test hardware. The inbox is volatile, the Heltec does not yet provide the iPhone companion’s Bluetooth transport, proactive roaming away from a weak-but-working home is incomplete, and several battery and transmission behaviors still require metal verification. The emergency interface is carefully designed and heavily tested in software, but it is not a certified safety device.

    That is the progress worth sharing: not just more features, but clearer boundaries between what the device requested, what the radio transmitted, what another node confirmed, and what remains unknown.

    Follow the project status or inspect the current source and development history on GitHub.

  • The MeshRoute concept: routing with scarce airtime

    LoRa makes long-range, low-power communication possible with small and affordable radios. It also imposes a hard discipline: airtime is scarce. Every transmission occupies a shared channel, and a design that works well with a handful of nodes can become noisy and inefficient as the network grows.

    MeshRoute starts from that constraint. It is a decentralized communication protocol and firmware project built to move useful messages without asking every radio to repeat everything it hears. The goal is not to promise instant delivery under every condition. The goal is to make careful, explainable decisions about how the network spends its limited radio budget.

    Why another approach to LoRa mesh?

    Flood-based routing is attractive because it is simple: a node receives a message, repeats it, and lets the message spread through the network. At small scale this can be robust and effective. In a dense network, however, those repetitions consume airtime, increase contention, create more opportunities for collisions, and push nodes toward regulatory duty-cycle limits.

    MeshRoute takes a different path. It builds routing knowledge and tries to send traffic along a deliberate route. That introduces a trade-off. Learning, refreshing, and repairing a route may add latency, especially when a node disappears or radio conditions change. In return, the network avoids turning every ordinary message into a network-wide event.

    Routes that adapt to radio conditions

    A LoRa link is not a fixed cable. Signal quality changes, links may be asymmetric, devices move, batteries run out, and nodes can appear long after the network has started. MeshRoute therefore maintains lightweight routing knowledge that is learned gradually and refreshed when it is useful.

    The protocol can respond to measured link quality, node disappearance, topology changes, duty-cycle pressure, and the choice of spreading factor. Control traffic and data traffic do not have to use exactly the same radio settings. The intention is to balance reach, airtime cost, and reliability instead of applying one configuration to every situation.

    Layers instead of one giant flood domain

    A MeshRoute network can be divided into local layers. A layer can contain roughly 250 nodes and maintains its own routing state and radio parameters. Inside a layer, short local identifiers keep ordinary traffic compact.

    Gateways can participate in two layers and forward traffic between them along an explicit layer path. This provides a route toward larger networks without forcing every local transmission through every participant. For cross-layer communication, the destination’s public identity travels with the defined gateway path, so the short local address does not have to pretend to be globally unique.

    Teams are encrypted networks inside the network

    MeshRoute is designed to become useful before a whole town adopts it. A small group can form a team: an encrypted overlay with its own identity space, direct messages, and shared channels. Four radios in the field can already be a complete network—there is no server, account provider, mobile tower, or central coordinator required for them to communicate.

    Team members discover one another and assign short team-local identities. Conflicts are resolved in a distributed way, including the awkward case where two members cannot hear each other directly but another teammate can hear both. Those team identities remain separate from the fixed-node identity space. That separation is important: a number that means “member 3” inside one team must never accidentally refer to “node 3” in the surrounding network.

    Messages within a team can be sent directly to one member or posted to a team channel. The content is protected end to end, while the routing layer still has enough information to move the packet. In other words, relay nodes can help carry a conversation without becoming participants in it.

    A person can move without becoming a new identity

    A team member may also be a roaming mobile node. The mobile keeps a stable cryptographic identity while the surrounding network tracks which fixed node currently acts as its home. If the person moves out of one anchor’s range and toward another, registration can follow the better link. Messages addressed to that person are then routed through the home that can currently reach them.

    This lets a team mix different roles: fixed infrastructure nodes, members attached through a home node, and radios operating entirely off-grid. The identity belongs to the person or device, not to the temporary attachment point.

    How the concept is being tested

    MeshRoute is already a working protocol and firmware, but it is still pre-release software. Development began with a deterministic LoRa simulator so routing decisions could be exercised against repeatable radio conditions. The project now combines simulation scenarios, native automated tests, board builds, and tests on real hardware.

    The difficult cases matter most: disappearing nodes, one-way links, rerouting, mobile registration, separated teams, and traffic that crosses layers. A simulation result is useful only if it exposes the assumptions behind the protocol, and a hardware result is useful only if it can be turned into a reproducible fix or a clearly documented limitation.

    The first public release is still ahead. Hardware validation, edge-case work, release packaging, and the iPhone companion are all in progress. Until that work is complete, MeshRoute should be treated as an engineering project on test hardware—not yet as a safety-critical emergency system.

    You can follow the current project status, read the source and development history on GitHub, or continue with the next development-log entry about the two client interfaces being built for MeshRoute.

  • Building MeshRoute in public

    MeshRoute is no longer just a protocol proposal. It is working firmware, a simulator, and a growing body of tests—and it is time to start showing the work while it is still being shaped.

    I have spent much of this year building quietly: implementing the protocol, creating deterministic simulation scenarios, putting firmware on real LoRa boards, and fixing the uncomfortable edge cases that appear when an elegant design meets timing, radio behavior, and constrained hardware. This blog is where that process becomes public.

    The problem I wanted to explore

    LoRa offers extraordinary range from small, inexpensive radios, but it does so with very little shared airtime. In Europe, deployments often operate inside duty-cycle limits that can be as low as one percent. That makes every transmission a resource decision.

    Flood-based mesh designs are attractive because they are simple and resilient in small networks: a node repeats what it hears and the message spreads. The difficulty appears as density grows. More neighbors produce more repetitions, more contention, and more pressure on the same narrow radio channel. The network consumes its scarce resource fastest when the topology becomes busiest.

    MeshRoute starts from the opposite conviction: airtime is precious, so a mesh should learn where traffic needs to go and send it along a deliberate path. That choice introduces its own costs. Routes must be learned, refreshed, and repaired. A routed network can accept more latency in exchange for fewer unnecessary transmissions. MeshRoute is an attempt to make that trade honestly and measure the result.

    A useful network can be small

    Scale matters, but I do not think usefulness should require a city-wide community of nodes. A hiking group, field crew, event team, or search group may have only a handful of radios. Four radios should already be a complete network.

    That is why MeshRoute treats teams and mobile identities as first-class protocol concepts. A team has its own identity space and encrypted communication. A roaming member keeps a stable cryptographic identity while the fixed network tracks which home node can currently reach it. When the member moves, the attachment point can change without forcing the person behind the radio to become a different identity.

    The same protocol also supports layered meshes connected through gateways. Local networks can use their own radio parameters and routing state instead of turning every participant into part of one enormous flood domain.

    The simulator came first

    MeshRoute began with a simulator because routing algorithms are easy to admire in a diagram and hard to trust on a radio. Real systems include asymmetric links, changing signal quality, radio turnaround time, channel contention, sleeping or failed nodes, and independent timing. If those effects are absent, a simulation can prove the behavior of a world that does not exist.

    The development process therefore uses deterministic simulation scenarios alongside native tests and hardware checks. Important scenarios act as regression gates: delivery behavior, failure handling, team separation, mobile registration, cross-layer traffic, and other protocol properties must remain measurable after a change. When the model becomes more realistic and exposes a defect, the right response is to fix the protocol or the test—not to hide the result.

    Where the project stands

    The core protocol and firmware are working and are approaching a first public release. Deliberate routing, team communication, mobile registration, and gateway mechanisms are implemented. Firmware is being exercised on test hardware, and a companion iPhone application is under development.

    It is also honestly pre-release. Interfaces and wire details can still change. Hardware validation is ongoing. Installation and onboarding are not yet ready for someone who simply wants to flash a board and trust the result. MeshRoute has not been deployed beyond test hardware and should not yet be treated as a safety-critical emergency system.

    What I will publish here

    The plan is to write about the parts of the project that can be checked rather than merely announced: the airtime mathematics behind routing instead of flooding, simulator realism that uncovered protocol bugs, one-way radio links, turnaround timing, roaming team identity, layered networks, cryptography under a small frame budget, and the testing discipline needed to change a mesh protocol without losing track of what changed.

    Some posts will describe successes. The more useful ones may describe an assumption that failed, the measurement that exposed it, and the change that survived afterward. Each technical article should carry a receipt: source, a repeatable simulation, or concrete numbers.

    The source and current documentation are already available on GitHub. The first release is still ahead; this blog will document the path to it in public.