01 What Is Meshtastic?

Meshtastic is an open-source, long-range, low-power mesh networking platform built on LoRa (Long Range) radio hardware. Every device is simultaneously a node, a router, and a relay — no single point of failure, no infrastructure dependency.

PropertyValue
ProtocolLoRa (chirp spread spectrum radio)
Range per hop5–30 km line-of-sight; multi-hop extends to 100+ km
PowerRuns weeks on battery; solar-sustainable
Cost per node$15–$40 USD
EncryptionAES-256 per channel, on by default
LicenseApache 2.0 — fully open source
Bandwidth~1–10 kbps (text + telemetry, not video)
Key insight: Meshtastic occupies the gap between SMS (requires cell towers) and satellite comms (expensive). It is the cheapest, most deployable off-grid communication layer available today.

02 Why It Exists

ProblemMeshtastic Answer
Disaster communicationWorks when cell and internet are down
Remote field operationsNo SIM card, no monthly subscription
PrivacyEncrypted by default, no central server
Cost$25 node vs. $300+ satellite communicator
IoT telemetry over distanceSensor data over km ranges with µA sleep current
Community resilienceMesh grows as nodes are added — no re-configuration
Communications stack showing Meshtastic in context alongside Briar, Reticulum, JS8CALL and other off-grid layers
Meshtastic sits at the LOCAL layer (0–100 km). It escalates to Reticulum → JS8CALL as range requirements increase.

03 How LoRa Works

LoRa uses chirp spread spectrum (CSS) — the signal sweeps up or down in frequency, making it extraordinarily resistant to noise and interference. The trade-off: low data rate (1–10 kbps). You send text and telemetry, not video.

diagram
[Node A] ──LoRa RF──► [Node B] ──LoRa RF──► [Node C] ──LoRa RF──► [Node D]
           5 km               8 km               6 km

Each node stores → re-transmits → decrements hop count

Key RF Parameters

ParameterRangeEffect
Spreading Factor (SF)SF7 → SF12SF7 = fast/short range. SF12 = slow/max range. Each step ~doubles range, halves speed.
Bandwidth (BW)125/250/500 kHzWider BW = faster but shorter range
Coding Rate (CR)4/5 → 4/8Higher CR = more error correction, slower
TX Power2–30 dBmEach +3 dB doubles effective radiated power

Modem Presets — pick one for the whole network

PresetSpeedRangeUse Case
SHORT_TURBO21 kbps<1 kmDense urban, short range
SHORT_FAST10 kbps1–3 kmCampus/event
LONG_FAST1.07 kbps5–15 kmRecommended start
LONG_MODERATE0.34 kbps10–20 kmRural mesh
LONG_SLOW0.18 kbps15–30 kmSparse nodes
VERY_LONG_SLOW0.09 kbps20–40 kmExtreme range, very patient
All nodes in a mesh must use the same region + modem preset to hear each other. This is the #1 cause of "my nodes can't see each other" problems.

04 Hardware

Recommended Boards (2024–2025)

Heltec V3 board
Heltec V3
ESP32-S3 + SX1262
Built-in OLED display, USB-C, compact
Best for Beginners
LILYGO T-Beam board
LILYGO T-Beam v1.2
ESP32 + SX1262 + GPS
Onboard GPS, 18650 battery holder, best for mobile
Best Mobile Node
LILYGO T-Deck
LILYGO T-Deck
ESP32-S3 + SX1262
Built-in keyboard + screen, standalone device
Standalone Communicator
📡
RAK4631
nRF52840 + SX1262
Best power efficiency, Bluetooth LE, WisBlock modular
Lowest Power

Frequency Bands

RegionBandNotes
USA915 MHzISM band, no license
EU / Pakistan / most of South Asia868 MHzUse EU_868 region in firmware
Asia-Pacific433 MHzLonger range, more interference
China470 MHzCN region
Pakistan / NTRA: No dedicated Meshtastic region defined. Use EU_868 (868 MHz) which is legal in most of South Asia for low-power ISM use. Verify current NTRA regulations before deployment.

Minimal Node BOM

Heltec V3 board~$18
18650 battery + holder~$5
Small solar panel (5V/1W)~$8
Weatherproof enclosure~$3
Antenna (3 dBi rubber duck)~$2
Total per node~$36

05 Firmware Installation

Method 1 — Web Flasher (easiest, no tools needed)

  1. Visit flasher.meshtastic.org in Chrome or Edge
  2. Plug board via USB — allow serial port access
  3. Select your device type from the dropdown
  4. Click Flash — done in ~60 seconds

Method 2 — Python CLI

bash
pip install meshtastic esptool

# Erase and flash (replace /dev/ttyUSB0 with your port)
esptool.py --port /dev/ttyUSB0 erase_flash
meshtastic --port /dev/ttyUSB0 --flash

Method 3 — PlatformIO (for firmware development)

bash
git clone https://github.com/meshtastic/firmware
cd firmware
cp platformio_override.example.ini platformio_override.ini
# edit platformio_override.ini to select your board target
pio run -e heltec-v3 --target upload
Windows users: Install CH340/CP2102 USB serial drivers if the device isn't recognized. Heltec V3 uses CP2102.

06 Basic Configuration

After flashing, configure via the Meshtastic app (Android/iOS) over Bluetooth, or via the Python CLI.

Essential settings via CLI

bash
pip install meshtastic

# Set region (determines legal frequency)
meshtastic --set lora.region EU_868

# Set modem preset (all nodes must match)
meshtastic --set lora.modem_preset LONG_FAST

# Set node role
meshtastic --set device.role ROUTER

# Set node name (shown in app + mesh)
meshtastic --set owner "WaterNode-01"
meshtastic --set owner_short "WN01"

# Confirm settings
meshtastic --info

Region Codes

RegionCodeFrequency
United StatesUS915 MHz
Europe / South AsiaEU_868868 MHz
Europe (433)EU_433433 MHz
Australia/NZANZ915 MHz
IndiaIN865 MHz
ChinaCN470 MHz

07 Node Roles

Role determines how a node behaves in the mesh. Choosing the right role is critical for network performance and battery life.

RoleBehaviourUse When
CLIENTConnects to phone/app, relays messagesDefault for end users
CLIENT_MUTEReceives but does NOT relayDense area, reduce congestion
ROUTERRelays only, no user messagesFixed infrastructure node (rooftop, hill)
ROUTER_CLIENTRouter that also accepts user connectionsBase station with attached laptop
TRACKERGPS position reporting, optimised packet formatAsset tracking, person tracking
SENSORTelemetry-optimised, minimal overheadEnvironmental monitoring, IoT
REPEATERPure RF repeater, minimal stateDumb relay at RF-strategic location
TAKTactical Awareness Kit integrationSAR, emergency services
Infrastructure design rule: Place ROUTER nodes at high points (rooftops, hillsides) on solar power. End users carry CLIENT nodes. This maximises coverage with minimal congestion.

08 Mesh Topology Design

diagram
         [ROUTER — hilltop, solar]
        /                \
[CLIENT]              [ROUTER — building rooftop]
 (phone)             /           \
                [CLIENT]       [CLIENT]
                (phone)         (sensor)

Hop Limit

Every packet carries a hop count. Each relay node decrements it. When it reaches 0, the packet is dropped. Default is 3 hops. For large networks:

bash
meshtastic --set lora.hop_limit 5   # increase for large area networks

Flooding Algorithm

Meshtastic uses managed flood routing — each node re-broadcasts packets it hasn't seen before (tracked by packet ID + source). This is simple and robust, with no routing tables to maintain. Downside: busy networks can see airtime congestion with many nodes.

Network SizeRecommendation
1–10 nodesDefault settings, any role mix
10–50 nodesDesignate explicit ROUTERs, set others CLIENT_MUTE where possible
50+ nodesReduce hop_limit to 3, use managed channels, monitor channel utilisation

09 Channels & Encryption

Meshtastic supports 8 simultaneous channels per node. Each channel has its own PSK (Pre-Shared Key) providing AES-256 encryption. Only nodes with the same channel name + PSK can read each other's messages.

Configure a private channel via CLI

bash
# Create a private channel on slot 1 with a random PSK
meshtastic --ch-set name "WaterTeam" \
           --ch-set psk random \
           --ch-index 1

# Enable uplink to MQTT broker on this channel
meshtastic --ch-set uplink_enabled true --ch-index 1

# Show channel QR code (share with team)
meshtastic --qr

Share channels

Channel config (name + PSK) is encoded in a URL or QR code. Share the URL and any Meshtastic app can import it in one tap.

text
# Example channel URL format
https://meshtastic.org/e/#CgUYAyIBAQ==

# Scan in app → instantly joins channel with correct PSK
Default channel: Channel 0 is the PRIMARY channel, using the default PSK (known to all nodes). For community mesh, create a secondary channel with a private PSK for operational messages, keeping Channel 0 public for discovery.

10 Python Library — Core Usage

bash
pip install meshtastic

Connect and send

python
import meshtastic
import meshtastic.serial_interface

# Connect over USB serial
iface = meshtastic.serial_interface.SerialInterface("/dev/ttyUSB0")

# Broadcast to all nodes on primary channel
iface.sendText("Hello mesh!")

# Send to specific node by ID
iface.sendText("Hello!", destinationId="!abc12345")

# List all visible nodes
for node_id, node in iface.nodes.items():
    user = node.get('user', {})
    print(f"{node_id}: {user.get('longName', 'unknown')}")
    pos = node.get('position', {})
    if pos:
        lat = pos.get('latitudeI', 0) / 1e7
        lon = pos.get('longitudeI', 0) / 1e7
        print(f"  position: {lat:.5f}, {lon:.5f}")

iface.close()

Receive messages with callbacks

python
import meshtastic
import meshtastic.serial_interface
from pubsub import pub
import time

def on_receive(packet, interface):
    if 'decoded' not in packet:
        return
    msg = packet['decoded']
    if msg.get('portnum') == 'TEXT_MESSAGE_APP':
        text = msg['payload'].decode('utf-8')
        print(f"[{packet['fromId']}] {text}")
        print(f"  SNR: {packet.get('rxSnr')} dB  RSSI: {packet.get('rxRssi')} dBm")

def on_connection(interface, topic=pub.AUTO_TOPIC):
    print(f"Connected to node: {interface.myInfo}")

pub.subscribe(on_receive, "meshtastic.receive")
pub.subscribe(on_connection, "meshtastic.connection.established")

iface = meshtastic.serial_interface.SerialInterface("/dev/ttyUSB0")

try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    iface.close()

Connect via TCP (WiFi-enabled boards)

python
import meshtastic.tcp_interface

# Heltec V3 and other ESP32 boards support TCP when on WiFi
iface = meshtastic.tcp_interface.TCPInterface("192.168.1.100")
iface.sendText("Hello over TCP!")
iface.close()

11 Telemetry & Sensors

Meshtastic has built-in support for environment sensors via the Telemetry Module. Sensors attach via I2C or SPI.

Supported sensor ICs

SensorMeasuresRelevance
BME280 / BME680Temp, humidity, pressure, air qualityEnvironmental monitoring
INA219 / INA260Current + voltageSolar / battery monitoring
MCP9808Precision temperatureWater temperature
LPS22HBBarometric pressureAltitude, weather
SHTC3Temperature + humidityGeneral environmental

Enable environment telemetry

bash
meshtastic --set telemetry.environment_measurement_enabled true
meshtastic --set telemetry.environment_update_interval 300   # every 5 min
meshtastic --set telemetry.environment_screen_enabled true   # show on display

Custom telemetry on a private port

python import struct # Encode custom sensor reading (e.g., water level float + temp float) water_level_cm = 142.5 temp_c = 24.3 payload = struct.pack('ff', water_level_cm, temp_c) # Ports 256–511 are reserved for private/application use iface.sendData( payload, portNum=256, # your private port destinationId="^all" # broadcast ) # Receive and decode on another node def on_receive(packet, interface): if packet['decoded'].get('portnum') == 256: data = packet['decoded']['payload'] level, temp = struct.unpack('ff', data) print(f"Water level: {level:.1f} cm, Temp: {temp:.1f}°C")
For PSKL water monitoring: Attach INA219 to monitor solar panel current, BME280 for site conditions, and use port 256 for custom water level readings. All telemetry propagates automatically through the mesh.

12 Protobuf — The Wire Format

All Meshtastic packets use Protocol Buffers (protobuf) for encoding. Understanding this lets you decode raw packets and build deep integrations.

bash
pip install meshtastic protobuf
# Proto definitions: github.com/meshtastic/protobufs
python
from meshtastic import mesh_pb2, telemetry_pb2, portnums_pb2

# Decode a telemetry packet's raw payload
def decode_telemetry(raw_bytes):
    tel = telemetry_pb2.Telemetry()
    tel.ParseFromString(raw_bytes)

    dm = tel.device_metrics
    if dm.battery_level:
        print(f"Battery:     {dm.battery_level}%")
        print(f"Voltage:     {dm.voltage:.2f} V")
        print(f"Ch util:     {dm.channel_utilization:.1f}%")
        print(f"Air util TX: {dm.air_util_tx:.1f}%")

    env = tel.environment_metrics
    if env.temperature:
        print(f"Temperature: {env.temperature:.1f}°C")
        print(f"Humidity:    {env.relative_humidity:.0f}%")
        print(f"Pressure:    {env.barometric_pressure:.0f} hPa")

Key protobuf message types

MessageFileContains
MeshPacketmesh.protoEnvelope for all packets
Datamesh.protoPayload + portnum
Telemetrytelemetry.protoDevice + environment metrics
Positionmesh.protoGPS coordinates
Usermesh.protoNode identity + hardware model

13 MQTT Bridge

Nodes with WiFi (ESP32 boards) can bridge the mesh to an MQTT broker, connecting your off-grid nodes to the internet when any gateway node is online.

Enable MQTT on a gateway node

bash
meshtastic --set mqtt.enabled true
meshtastic --set mqtt.address "your-broker.com"
meshtastic --set mqtt.port 1883
meshtastic --set mqtt.username "user"
meshtastic --set mqtt.password "pass"
meshtastic --set mqtt.root "msh/PK"          # topic prefix
meshtastic --set mqtt.json_enabled true       # also publish decoded JSON
meshtastic --set mqtt.encryption_enabled true # keep packets encrypted on broker

MQTT topic structure

text
msh/PK/2/e/LongFast/!abcd1234       # encrypted protobuf
msh/PK/2/json/LongFast/!abcd1234    # decoded JSON (if json_enabled)
msh/PK/2/stat/!abcd1234             # node status

Subscribe to JSON packets in Python

python
import paho.mqtt.client as mqtt
import json

def on_connect(client, userdata, flags, rc):
    print(f"Connected, rc={rc}")
    client.subscribe("msh/PK/2/json/#")

def on_message(client, userdata, msg):
    try:
        data = json.loads(msg.payload)
        node_id = data.get('from')
        payload = data.get('payload', {})
        portnum = data.get('type')
        print(f"Node {node_id} [{portnum}]: {payload}")
    except json.JSONDecodeError:
        pass  # encrypted packet, skip

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("your-broker.com", 1883)
client.loop_forever()

Community MQTT broker (testing)

text
Host:  mqtt.meshtastic.org
Port:  1883  (plain)  /  8883  (TLS)
Topic: msh/world/#
Architecture tip: In a sparse community mesh, one or two nodes with WiFi/4G serve as MQTT gateways. All other field nodes remain RF-only. Telemetry from every node flows through the mesh to the gateway, then to a dashboard — without each sensor needing internet access.

14 Node-RED Integration

Node-RED is the easiest way to route Meshtastic MQTT data into databases and dashboards.

text
Flow example:

[MQTT in node]  →  [JSON parse]  →  [Switch on type]
                                    ├── telemetry  →  [InfluxDB write]
                                    ├── position   →  [Map widget]
                                    └── text       →  [Dashboard text]

Node-RED MQTT node config

text Topic: msh/PK/2/json/# QoS: 0 Broker: your-broker.com:1883

The msg.payload will be a JSON object with keys: from, to, type, payload, channel, rxSnr, rxRssi, hopLimit.

You can run Node-RED and a local MQTT broker (Mosquitto) entirely on a NAS or Raspberry Pi — keeping the entire telemetry pipeline local. No cloud required.

15 JavaScript / TypeScript Library

bash
npm install @meshtastic/js
javascript
import { Client } from "@meshtastic/js";

const client = new Client();

// Serial connection (Node.js or browser via Web Serial API)
const connection = client.createSerialConnection();
await connection.connect({
  port: "/dev/ttyUSB0",
  baudRate: 115200,
  concurrentLogOutput: false
});

// Send a text message
await connection.sendText("Hello from JS!");

// Listen for text messages
connection.events.onTextPacketReceived.subscribe((packet) => {
  console.log(`From ${packet.from}: ${packet.message}`);
  console.log(`SNR: ${packet.rxSnr}, RSSI: ${packet.rxRssi}`);
});

// Listen for position updates
connection.events.onPositionPacketReceived.subscribe((packet) => {
  const { latitudeI, longitudeI, altitude } = packet.data;
  console.log(`Position: ${latitudeI/1e7}, ${longitudeI/1e7}, ${altitude}m`);
});

The JS library supports Serial, TCP, and BLE transports — enabling browser-based dashboards via the Web Serial API or WebBluetooth.

16 Bluetooth (BLE) from Python

bash
# Scan for nearby Meshtastic nodes over BLE
meshtastic --ble-scan
python
import meshtastic.ble_interface
import asyncio

async def main():
    # Use MAC address from ble-scan output
    iface = meshtastic.ble_interface.BLEInterface("AA:BB:CC:DD:EE:FF")
    iface.sendText("Hello over BLE!")

    # Get node info
    print(iface.myInfo)

    await asyncio.sleep(5)
    iface.close()

asyncio.run(main())

BLE is useful when nodes are nearby and USB is unavailable — e.g., configuring a sealed weatherproof enclosure through a smartphone app, or a Raspberry Pi talking to an adjacent LoRa node wirelessly.

17 Building a Tracker

Configure the node as TRACKER

bash meshtastic --set device.role TRACKER meshtastic --set position.position_broadcast_secs 30 # broadcast every 30s meshtastic --set position.gps_enabled true meshtastic --set position.gps_update_interval 10 # GPS fix every 10s

Receive and log positions in Python

python
from pubsub import pub
import meshtastic.serial_interface
import sqlite3, time

DB = sqlite3.connect("positions.db")
DB.execute("""CREATE TABLE IF NOT EXISTS pos
    (ts INTEGER, node TEXT, lat REAL, lon REAL, alt INTEGER)""")
DB.commit()

def on_receive(packet, interface):
    if 'decoded' not in packet:
        return
    decoded = packet['decoded']
    if decoded.get('portnum') != 'POSITION_APP':
        return
    pos = decoded.get('position', {})
    lat = pos.get('latitudeI', 0) / 1e7
    lon = pos.get('longitudeI', 0) / 1e7
    alt = pos.get('altitude', 0)
    node = packet['fromId']
    DB.execute("INSERT INTO pos VALUES (?,?,?,?,?)",
               (int(time.time()), node, lat, lon, alt))
    DB.commit()
    print(f"[{node}] {lat:.5f}, {lon:.5f}  alt={alt}m")

pub.subscribe(on_receive, "meshtastic.receive")
iface = meshtastic.serial_interface.SerialInterface()

while True:
    time.sleep(1)

18 Range Testing & Optimization

Signal metrics decoded

MetricRangeInterpretation
RSSI−140 to 0 dBmSignal strength. Usable above −120 dBm. Closer to 0 = better.
SNR−20 to +10 dBSignal vs noise. LoRa decodes even at −20 dB SNR. Positive = strong link.
python
def on_receive(packet, interface):
    rssi = packet.get('rxRssi', 'n/a')
    snr  = packet.get('rxSnr',  'n/a')
    hops = packet.get('hopStart', 3) - packet.get('hopLimit', 3)
    print(f"RSSI: {rssi} dBm  SNR: {snr} dB  Hops: {hops}")

Built-in Range Test module

bash
# On the sending node:
meshtastic --set range_test.enabled true
meshtastic --set range_test.sender 60    # send ping every 60 seconds
meshtastic --set range_test.save true    # save results CSV to SD card

What improves range most?

ChangeRange GainNotes
Antenna height (+1 floor)+20–40%Cheapest improvement
3 dBi → 6 dBi antenna+3 dB = 2×Better than more TX power
Reduce modem preset (LONG_FAST → LONG_SLOW)+50–100%Slower throughput trade-off
Increase TX power (+3 dBm)+40%Check legal limits; wastes battery
Clear line-of-sight5–10×Terrain matters more than hardware

19 Power Optimization

Typical current consumption

StateCurrentNotes
Active TX (30 dBm)~200 mABrief bursts only
Active RX / listening~15 mAMost of awake time
Light sleep~2 mABetween receive windows
Deep sleep (ESP32)~10–100 µABoard-dependent

A 3000 mAh battery with hourly transmit + mostly-sleep → several weeks per charge.

Power-saving configuration

bash meshtastic --set power.is_power_saving true meshtastic --set power.ls_secs 300 # light sleep interval (seconds) meshtastic --set lora.tx_power 17 # reduce if nodes are close meshtastic --set display.screen_on_secs 10 # turn screen off quickly meshtastic --set position.position_broadcast_secs 3600 # hourly GPS

Solar sizing (per node)

text Daily energy budget (ROUTER role, 5 min awake / 55 min sleep): Awake: 15 mA × 5 min × 12 h sun = 15 mAh Sleep: 2 mA × 55 min × 24 h = 176 mAh Total: ~200 mAh/day 1W panel (200 mA @ 5V) provides ~800 mAh on a sunny day → 4× buffer → 1W panel + 3000 mAh battery = indefinite solar operation

20 Remote Admin

You can configure remote nodes over the mesh — no physical access required. This is essential for managing deployed infrastructure nodes.

bash # Send config change to a remote node by its ID meshtastic --dest "!abcd1234" --set lora.tx_power 20 # Request fresh telemetry from a specific remote node meshtastic --dest "!abcd1234" --request-telemetry # Request node info meshtastic --dest "!abcd1234" --request-nodeinfo

Remote admin requires your local node's key to be authorised as admin on the target node. Set this via security.admin_key during initial deployment.

Security note: Admin messages are encrypted with the channel PSK. Anyone with the PSK can send admin commands to nodes on that channel. Use a private admin channel with a strong PSK for infrastructure nodes.

21 Store & Forward

Store & Forward allows a router node to buffer messages for nodes that are temporarily offline, then deliver them when connectivity is re-established. Essential for sparse or intermittent mesh networks.

bash # Enable on a ROUTER node that serves as the buffer meshtastic --set store_forward.enabled true meshtastic --set store_forward.records 100 # messages to buffer meshtastic --set store_forward.history_return_max 25 # max messages to replay meshtastic --set store_forward.history_return_window 7200 # replay window (secs)

When a CLIENT node comes online, it sends a history request to the nearest Store & Forward router, which replays queued messages. This is asynchronous messaging without internet.

Use case: A water sensor in a remote valley is out of direct range. A solar-powered ROUTER node on a ridge buffers its telemetry. When a field worker passes through with a phone, they receive the buffered readings automatically.

22 Map Integration — ATAK / TAK

Meshtastic integrates with the Tactical Awareness Kit (ATAK/iTAK) standard used by SAR teams and emergency responders.

text
Meshtastic node ──BLE──► Phone running ATAK / WinTAK
                                    ↓
                          TAK server (local or cloud)
                                    ↓
                          Shared Situation Awareness Map

Set node role to TAK — the firmware emits Cursor-on-Target (CoT) formatted position packets that ATAK can ingest directly.

Web map options (no ATAK required)

  • Meshtastic Mapmeshtastic.liamcottle.net — public nodes worldwide via MQTT
  • MeshSee — connect to your MQTT broker, OpenStreetMap overlay
  • Node-RED Dashboard — WorldMap node renders node positions on a local map, offline-capable

23 Community Mesh — Deployment Tips

Practical guidance for building a shared community mesh (e.g., for a village, NGO operation, or water monitoring network).

  1. Place ROUTER nodes at high points — rooftops, hilltops, water towers. Solar-powered. Weatherproof enclosures.
  2. Agree on region + modem preset before ordering hardware — changing later requires touching every node.
  3. Naming convention — e.g., PK-W-R01 (Pakistan-Water-Router-01) aids at-a-glance identification.
  4. Two channels minimum — Channel 0 (public, default PSK) for broad community messages; Channel 1 (private PSK) for operations team.
  5. One or two MQTT gateway nodes with internet/4G uplink — feeds dashboard and allows remote monitoring.
  6. Document each node's physical location in a shared spreadsheet (node ID → GPS + description).
  7. Carry a spare pre-flashed node — if a field node fails, replacement takes minutes.
  8. Test the mesh before deployment by walking the coverage area with a phone and logging RSSI per location.
Role in NetworkHardwarePowerQty (per 5 km²)
Backbone ROUTERHeltec V3 + 6 dBi antenna1W solar + 3000 mAh2–4
MQTT GatewayT-Beam v1.2 (has GPS)Mains / large solar1
Sensor SENSOR nodeHeltec V3 + INA219/BME2800.5W solar + 2000 mAhAs needed
Field CLIENTT-Beam or phone appPhone batteryPer person

24 Common Pitfalls

SymptomCauseFix
Nodes not seeing each otherDifferent region or modem presetmeshtastic --info on both nodes, confirm match
Range much worse than expectedLoose SMA antenna connectorFinger-tighten all SMA connections
GPS never locksFirst boot indoors / no sky viewTake outside for 5 min, clear sky
Too many nodes, congestionEvery node relayingSet non-infrastructure nodes to CLIENT_MUTE
Phone won't connect over BLEStale BLE pairingForget device in phone BT settings, re-pair
Packet collisions / lost messagesHop limit too highLower lora.hop_limit to 3
Battery drains fastScreen always on / TX power at maxSet display.screen_on_secs 10, reduce TX power
Python library not finding deviceWrong serial portRun meshtastic --port /dev/ttyUSB0 --info (try USB1 etc.)
MQTT packets not appearingWrong topic subscriptionSubscribe to msh/# first, then narrow down

25 Resources & Quickstart Path

Key Resources

Official Docs
meshtastic.org/docs
Firmware (GitHub)
github.com/meshtastic/firmware
Python Library
github.com/meshtastic/python
JS / TS Library
github.com/meshtastic/js
Protobufs
github.com/meshtastic/protobufs
Web Flasher
flasher.meshtastic.org
Community Forum
meshtastic.discourse.group
Public Node Map
meshtastic.liamcottle.net

Quickstart Path: Novice → Expert

1
Week 1 — First Mesh
Buy 2× Heltec V3 → flash via web flasher → pair with phone app → send first message → confirm RSSI/SNR on receive
2
Week 2 — GPS + Mapping
Add T-Beam as TRACKER node → see positions in app → log to positions.db with Python script
3
Week 3 — Python Integration
Write a receive loop → log all packets to SQLite → decode telemetry protobuf → add a BME280 sensor
4
Week 4 — MQTT + Dashboard
Enable MQTT bridge on gateway node → Node-RED flow → InfluxDB storage → Grafana dashboard → enclose in solar weatherproof box
5
Month 2 — Community Deployment
Deploy ROUTER nodes at strategic high points → set community channels → remote admin → Store & Forward → monitor channel utilisation
6
Expert — Custom Firmware & Sensors
Fork firmware repo → custom telemetry ports → INA219 solar monitoring → integrate with Reticulum for regional backbone → ATAK integration for field ops