ESP32 + LoRa: Meshtastic, the off-grid mesh firmware
Flash Meshtastic on an ESP32 + LoRa board and you have an off-grid text messaging device with mesh routing, encryption, and battery-friendly operation. No SIM card, no monthly bill, no account.
Meshtastic is the open-source firmware you flash on an ESP32 + LoRa board to get a text-messaging device with mesh networking. It handles the parts you would reinvent badly if you wrote your own LoRa code: encryption, message deduplication, mesh routing between nodes, and the over-the-air protocol that lets your message hop from board to board until it reaches the one you sent it to. You would build all of that yourself in about three months of evenings, then Meshtastic would still be better.
This is the tutorial for the person who wants to send a text from one cabin to another, or from a hike to a base camp, or from a sensor in the back field to a phone at the farmhouse. With no cell signal and no Wi-Fi.
What you need
- An ESP32 + LoRa board that Meshtastic supports. The common ones:
- TTGO T-Beam (the most popular, has GPS and a battery connector built in; about $35)
- Heltec LoRa 32 (smaller, no GPS; about $20)
- LilyGo T-Echo (the new one with e-ink display and BME280; about $50)
- A USB cable to flash it
- A phone with the Meshtastic app (Android or iOS)
- (Optional) a second Meshtastic board if you want to test mesh between two nodes
The TTGO T-Beam is the right pick for a first board. It has the GPS, the battery connector, the OLED screen, and the LoRa antenna all on one PCB. The Heltec is smaller but you’ll add GPS later if you want it.
Wiring
There is no wiring. Meshtastic boards are single-board solutions: the ESP32, the LoRa chip (SX1276 or SX1262), the antenna connector, and (sometimes) the GPS and battery management are all on the same board. You flash it, attach an antenna, optionally add a battery, and turn it on.
The one thing you MUST do is attach the antenna before transmitting. The SX1276 will burn out if you transmit into no load. Most boards come with a small U.FL antenna; plug it in before you power up.
Flashing Meshtastic
You have three options:
-
Web flasher (easiest): go to https://flasher.meshtastic.org in a Chrome browser that supports WebSerial. Pick your board, the latest stable firmware, and click “Flash.” The board reboots into Meshtastic.
-
CLI / pip:
pip install meshtastic-flasher(or use themeshtastic-flasherGUI), pick the firmware file for your board, flash it. The CLI is better when you have many boards to flash or want reproducible builds. -
esptool.py directly: download the firmware UF2 or bin file from https://github.com/meshtastic/firmware/releases, then use esptool.py to write it. The most flexible option, but you need to know which offset and chip to target.
For most people, the web flasher is right. Open it, plug in the board while holding BOOT (so it shows up as a serial port), click Flash, wait ~30 seconds.
The first time you boot Meshtastic, it does not have a region set. You must set the LoRa region to match your country: US, EU_433, EU_868, CN, etc. The Meshtastic app does this through Bluetooth: connect, open the app, go to Settings >> Device >> LoRa, pick your region. After the region is set, the board reboots and starts transmitting on the right frequencies.
The phone app
Download the Meshtastic app (Android or iOS). The Android version is typically more current because Meshtastic’s primary developer uses Android; the iOS version is good but sometimes a release behind.
Power on the board. Open the app. It scans for Bluetooth devices and finds your board (by name, which defaults to “Meshtastic XXXX” where XXXX is a chip ID). Connect. The app shows the node’s current channel, the people who have sent messages, and a text field at the bottom.
Send a message from one phone. If you have a second Meshtastic board nearby (in Bluetooth range of the first phone, or just powered on nearby), the message appears on the second board too. That’s the basic flow.
Mesh routing
The interesting part: send a message from one board to another board that is out of Bluetooth range. If a third board is in between, the message hops:
Board A -> Board B -> Board C
Each board retransmits the message until it reaches the destination. The mesh routing is automatic. You do not configure routes.
There are limits: Meshtastic uses LoRa, which is slow (~250 bytes per message at the default settings) and has limited bandwidth per channel. The mesh can route messages several hops, but each hop adds latency. For real-time chat, keep the hops to 3-4.
The default hop limit is 3. If you need more, set the hop limit in the app or via the CLI. Higher hops mean more retransmissions and more battery use per message.
What you should see
When two boards are powered on and connected to Meshtastic:
- Each board’s screen shows its node name, the number of nodes in the mesh, and the most recent messages.
- Sending a message from phone A (connected to board A) makes the message appear on board B within a few seconds, if board B is in range.
- If board B has no phone connected, it still receives and re-broadcasts the message. When board C comes online, it gets the queued messages.
When a board is out of range of any phone, it still routes messages for the mesh. This is the “off-grid sensor network” use case: a sensor node in the field with no phone, just LoRa, retransmitting sensor readings to other nodes that have phones.
When something breaks
“My board shows up as a serial port but the web flasher says ‘wrong chip’.” The board is in BOOT mode but the chip ID doesn’t match. Try a different USB cable (some cables are power-only and don’t pass data).
“Meshtastic says ‘region not set’ on every boot.” The region is stored in flash; if the firmware update wiped it, you have to set it again. Set it once, save the settings (the app does this), and it sticks.
“Messages get to one hop but not two.” The default transmit power is 20 dBm (100 mW). For longer range, increase the transmit power in the app (Settings >> Device >> LoRa >> TX Power, set to 30 dBm / 1 W where legal). Be aware: 1 W into a small antenna can cause the antenna to melt or the board to overheat. Use a real outdoor antenna.
“Battery drains in a day.” The default Meshtastic settings are for convenience (Bluetooth always on, screen always on). For battery operation:
- Turn off Bluetooth when you don’t need the phone to be connected (Settings >> Device >> Bluetooth >> Enabled: false)
- Reduce screen timeout (Settings >> Display >> Screen On Duration: 60 seconds)
- Reduce transmit power to the minimum that works for your range
A TTGO T-Beam with these settings lasts about 5-7 days on an 18650 cell.
“I can’t see the board in the Meshtastic app.” Bluetooth pairing on iOS has a quirk: the device name must be ≤ 8 characters, start with “BLE” or “Blue”, or be otherwise recognized by iOS. If you set a custom name like “My Meshtastic Node”, iOS may not show it. Rename to something short (“TBEAM01”) and try again.
What to build next
The most useful next project is a sensor node: an ESP32 + LoRa + BME280 that reads temperature/humidity/pressure and broadcasts it over Meshtastic every 5 minutes. The other Meshtastic boards in range will receive and display the sensor data on their screens. No MQTT broker, no Wi-Fi, no cloud. Just LoRa.
The Meshtastic firmware has a built-in “Environment Monitoring” module that does exactly this. You enable it in the app (Settings >> Modules >> Telemetry >> Environment Telemetry: on) and configure the pin numbers for your I2C BME280.
For longer range: an outdoor antenna on each board. A 868 MHz / 915 MHz whip antenna on a window or roofline adds 3-5 dB to your link budget, which is the difference between 1 km range and 5 km range.
For real off-grid communication: pair Meshtastic with a phone hotspot or a small solar panel + 18650. The TTGO T-Beam runs for a week on a single 18650 with the power optimizations above.
Why this is not just “LoRa peer-to-peer”
You can write your own LoRa peer-to-peer code (the esp32-lora-peer-to-peer
tutorial on this site does). But:
- Your protocol has no encryption by default (anyone with a LoRa board hears your packets).
- Your protocol has no mesh routing (point-to-point only).
- Your protocol has no message deduplication (the same packet retransmitted 10 times shows up 10 times on the receiver).
- Your protocol has no phone app integration.
Meshtastic is what you’d you use if you actually wanted to send a message, not just demonstrate that LoRa works. For hobby tinkering, your own protocol is fine. For “I want to text my friend from the backcountry,” Meshtastic is the answer.
—Brian