The internet works because there is a path between every pair of endpoints. The internet fails because that path crosses corporate networks, regulated spectrum, and political borders. Every part of that fails on a regular basis. The 2025 outage of a single mobile operator in Austria knocked emergency lines offline for hours. Storms take fibre out for days. Power cuts take the ISP gear out as long as the cuts last.

A LoRa mesh is the small experiment in what stays up when none of that does. No tower. No ISP. No exchange. No permission. Two of these radios in line of sight can talk over a kilometre on a coin cell. Forty of them in a town form a self-routing network that does not need anything else to function.

This post is about MeshCore, the protocol I settled on for that experiment. The hardware. The budgets that determine what is actually possible. The encryption properties. And the projects it opens up beyond emergency comms: telemetry from sensors that live nowhere near WiFi, a side channel to my server from a distance, Home Assistant feeds from things the smart-home stack would never reach on its own.

Why MeshCore instead of Meshtastic#

Meshtastic is the well-known LoRa mesh project. It runs on the same hardware, has a large community, has phone apps, and is what most people start with. It is also a project with a specific opinion about what a mesh is for: chat, GPS positions, maybe telemetry. The protocol is tuned for that. The firmware is opinionated.

MeshCore is the alternative I settled on. It is smaller in scope, deliberately, and the smaller scope lets it be better at the parts I actually care about:

  • The packet format is lean. A text message is in the dozens of bytes, not hundreds. On a busy mesh that math compounds.
  • Routing is explicit, not flood-based. Nodes maintain a small neighbour table and route through the table. This is closer to what an off-grid mesh actually needs and far gentler on the airtime budget.
  • The firmware fits comfortably on a board with 8 MB of flash and 320 KB of RAM. There is room for application code without fighting for every kilobyte.
  • The phone app is minimal but works.
  • End-to-end encryption is the default for direct messages, not an opt-in.

The trade-off is a smaller user base. If you want to join the largest active LoRa mesh, that is Meshtastic. If you want to run a small private one and understand every byte that goes on the air, MeshCore is the choice.

The encryption and the range#

The two properties of LoRa that matter most for resilience: it goes far on very little, and the modulation is hard to jam casually. The two properties of MeshCore on top of that: messages between any two known peers are end-to-end encrypted, and the routing is not flood-based so a hostile node cannot easily spam the network.

Range in a clean radio environment is dramatic. Rooftop to rooftop with simple antennas, ten kilometres is realistic at SF12. With a relay or two in between, a small town is one hop apart. On a hill with line of sight to the next hill, hobbyists have logged hundreds of kilometres. Urban with concrete walls in between is the worst case: a few hundred metres if you are unlucky with floors. Still more than WiFi.

Encryption matters because the air is shared. Anyone in the band can listen. MeshCore uses Curve25519 keypairs per node. A direct message between two nodes is encrypted to the recipient's public key. Other nodes on the mesh forward the encrypted bytes without being able to read them. Group channels use a shared key, which is less defensible but still keeps content opaque to passive sniffers outside the group.

There is no anonymity in the air, only confidentiality. Anyone listening can see that node A sent a packet routed via node B to node C. The packet itself is opaque. That is the right balance for the threat model, which is "a corporate or state listener with a basic SDR who wants to know what people are saying", not "a state actor doing traffic analysis on a small mesh".

The hardware#

Two board families on my mesh.

Heltec WiFi LoRa v3 uses an ESP32-S3 plus a SX1262 radio plus an OLED. The v4 (newer) bumps the radio and the display brackets. They cost around 20 EUR each, have USB-C for flashing, and run MeshCore happily. The ESP32 part means they have WiFi and Bluetooth alongside LoRa, which is nice for bridging the mesh to a phone or a local network. The cost is current draw: an ESP32 is a hungry chip even at idle, and it dominates the power budget if you want the node to last on battery.

nRF52840 boards (an Adafruit Feather and a couple of Promicro-shaped ones) are the low-power half of the mesh. The nRF52840 is a Cortex-M4 with built-in BLE, a generous sleep mode, and a power profile that is dramatically better than the ESP32. With the radio off and the CPU asleep, the nRF52840 draws single-digit microamps. Wake it for a packet, send it, sleep it again, and a CR123 cell lasts months.

The two families mix on the same mesh because LoRa is LoRa. The packets travel over the same SX126x radios at the same data rate. The choice between an ESP32 board and an nRF52 board is mostly a power budget question.

The radio budget#

A LoRa link looks like magic until you remember the math. At 869 MHz in the EU SRD band, the legal duty cycle for the most common sub-band is 1%. That means in any sixty-minute window, you can transmit for at most thirty-six seconds. On the higher-power sub-band the duty cycle drops to 0.1%, three point six seconds per hour.

This is fine for a mesh of a few dozen nodes exchanging short text messages. It is not fine for a chatty firmware that broadcasts position every minute. The first time I instrumented airtime on a node I expected to find the limit at maybe 5%. I was over 12% in steady state because the firmware was being too helpful. Cutting unnecessary broadcasts was the first optimisation.

MeshCore lets you tune broadcast intervals down to multi-minute spans and skip them entirely on nodes that do not need position. Both helped. The neighbour-discovery cycle on a quiet mesh consumes almost nothing once it is established.

The battery and solar budget#

On the nRF52840 side the math works without trying hard. Sleep current around 3 to 8 microamps. Active current during a TX of around 25 to 80 mA depending on power setting, for the duration of the packet (200 to 600 ms). Receive at 5 to 12 mA when the radio is in receive mode. A node that is mostly sleeping, listening on a duty cycle (wake every 30 seconds, listen for 200 ms, send a packet every five minutes), averages around 100 microamps. A 2000 mAh battery lasts most of a year before recharge.

On the ESP32 side the math fights. Deep-sleep current can be a few tens of microamps if you do it right, but every WiFi or BLE wake costs more than a LoRa-only wake. The Heltec boards also have an LDO and a USB-serial chip that draw current you cannot turn off without modifying the board. Realistic average is closer to 5 to 10 milliamps, two orders of magnitude worse than the nRF52. A 2000 mAh battery lasts a couple of weeks instead of a year.

This is what determined the mesh shape: ESP32 nodes near power (or with bigger batteries), nRF52 nodes for the leaf positions that need to live on their own for months.

The solar part is the one I was naive about going in. The textbook calculation says pick a panel, multiply by sun-hours per day, get a daily energy budget. EU latitudes give 3 to 4 effective peak-sun-hours in summer, dropping to 0.5 to 1 in winter. A 1W panel produces 4 watt-hours on a good summer day, 0.5 watt-hours on a bad winter day. The problem is not the long-run average. It is consecutive overcast days at the winter solstice. Three of those in a row produce essentially zero charge.

Three lessons I had to learn:

  • Size the battery for the worst-case streak, not the average draw. Roughly four weeks of average draw for my latitude.
  • The charge controller matters more than the panel. A naive linear charger throws away most of the panel's output when the battery is not at the right voltage. A proper MPPT controller (TI BQ25570 for tiny systems) makes the same panel produce two to three times the usable energy.
  • The voltage drop across cabling and connectors is the silent killer. A 50 cm cheap cable between panel and controller can drop 0.3V at 100 mA. Ten percent of the available power on a 3.3V system, gone before the controller sees it.

The node I have running right now in solar mode is an nRF52840 with a 4000 mAh 18650, a 2W panel, a BQ25570 MPPT module, the whole thing in a waterproof enclosure on a south-facing fence. Eight months continuous, including one really bad week in February. The final state of charge that morning was 28%.

Off-grid because the grid is not always there#

The main thing the mesh is for. Not theatre. Concrete cases where the public network has failed and this one has not:

  • Mobile operator outage. Single-operator outages happen several times a year and locally affect everything that operator carries, including emergency lines. A LoRa mesh in your pocket does not care.
  • Storm-driven fibre damage. A wind event takes out the local exchange. ISPs do their best, repair times are measured in days. The mesh keeps relaying messages between everyone in radio reach.
  • Power cuts. Your home WiFi is gone. The cell tower's backup batteries hold for hours, maybe a day. A solar-charged LoRa node holds indefinitely.
  • Travel through coverage holes. Walking, biking, hiking, sailing. The mesh covers a corridor as long as there are nodes along it. With three hilltop relays a regional corridor is doable.

The point is not that the mesh replaces normal comms. The point is that when normal comms fail, the mesh does not. It is the radio equivalent of having a generator. Most of the time it just sits there. The day you need it, you are very glad you wired it up while things were quiet.

What it extends to#

Once the mesh exists as a transport, it is a small step to use it for more than messages.

Telemetry from places without WiFi. The nRF52 nodes are small enough and low-power enough to live on a fence post, in a shed at the back of the garden, on a hilltop relay. They report temperature, humidity, soil moisture, door states, water levels. The reports land on the mesh, get picked up by a gateway node, hop into MQTT, end up wherever I want them.

Home Assistant integration. This is the part that took the mesh from "interesting toy" to "thing I use daily". A Heltec node sits next to the Home Assistant server, paired over USB serial. A small bridge daemon reads packets off the serial, decodes them, posts them as MQTT messages on topics like mesh/node-04/temperature. Home Assistant subscribes via its MQTT integration. Now a sensor on a fence post 300 metres away with no WiFi anywhere near it shows up as a normal entity in the dashboard, in the history graphs, in the automations. A LoRa node is just a slower, longer-range Zigbee node, as far as Home Assistant cares.

Side channel to the server. This is the project I am working on now. The relay VPS that fronts archworks.co is publicly reachable, but only when DNS and IP routing work, which is exactly what fails during an outage. A side channel where a Heltec node in the mesh can ping a Heltec node co-located with my server, which has a serial bridge into a control daemon, gives me a way to send a command (reboot a VM, check service status, push a metric) when the normal path is down. Slow. Limited bandwidth. Reliable in conditions where nothing else is.

Remote-control of equipment I cannot run cables to. Garden irrigation valves. A weather station. A camera trigger. Anything that needs an occasional "do this thing now" command but is too far for WiFi and too remote for cellular to be worth the SIM card.

The unifying property: the mesh is a transport for small, infrequent, important messages over long distances on small power. Anything that fits that envelope becomes plausible to build once the mesh is up.

Where this is going#

I am running four nodes today. The plan is six by the end of the year, with at least three on solar. After that the projects pile on naturally:

  • A hilltop relay with a directional antenna to extend reach into the next valley.
  • A few more sensor leaves around the garden and the shed.
  • The Home Assistant gateway productionised properly (it is currently a Python script in a tmux session).
  • The server side channel finished and the command surface limited to things that are safe to do over a low-bandwidth one-way link.

None of this is theoretical. The radios are cheap. The firmware is open. The encryption is real. The math is small enough to hold in your head. The frustration is the same frustration any new RF project gives you, plus the battery and solar work, which is mostly a sizing problem dressed up.

Off-grid is not a doomer hobby. It is the only kind of comms that does not depend on a stack of corporate decisions and political weather to keep working. The day you need it, you will not be sorry that the cost of having it ready was six dev boards and a Sunday afternoon.