Off-Grid Backhaul¶
For sensors out of WiFi range, compact serial lines ride a LoRa mesh to the
base. Two stacks are supported today; the sensor firmware is identical for
both (OUTPUT_SERIAL 1, plain text lines).
Meshtastic¶
- Sensor: build the sketch with
OUTPUT_SERIAL 1; it prints one compact line per event to its UART. -
Field mesh node: wire the ESP32's TX to the node's RX (shared ground) and enable the Serial module in text mode:
-
Base mesh node: a Meshtastic node on USB to the Pi receives the messages.
- Bridge:
python -m mqtt.serial_bridge --serial-port /dev/ttyUSB0 [--sensor-map config/sensor_nodes.json]expands each line and republishes full JSON to the broker. The same bridge also ingests Detection Sensor module packets (contact sensors) and flags mesh-node presence.
MeshCore¶
Build the sensor sketches with SERIAL_MESHCORE 1; each line is framed in
MeshCore's companion serial protocol as a channel message, prefixed
NODE_ID: (MeshCore channel messages carry no sender id), for a wired
MeshCore companion node such as a Heltec V3. At the base:
The bridge listens on a companion radio sharing the same channel and maps the
prefixed lines to the standard MQTT payloads. Sensor and base radios must
share the channel key; MESHCORE_CHANNEL in the sketch picks the channel
index.
LXMF / Reticulum¶
Sensors reach a Reticulum network through a small relay host (a Pi Zero W with an RNode works) instead of a wired mesh node:
The base side prints its LXMF destination hash on startup:
The field side reads the unmodified sensor's serial lines and sends each as an LXMF message, prefixed with the node name:
pip install rns lxmf pyserial
python -m sensors.rns_field_relay --serial-port /dev/ttyACM0 \
--dest <hash printed by rns_bridge> --node-name gate
Reticulum interfaces (RNode, TCP tunnels, ...) come from each host's own RNS
config (~/.reticulum).
Cellular (LTE-M / NB-IoT)¶
Where a site has cell coverage but no WiFi and no mesh, a LilyGO T-SIM7080G-S3 (ESP32-S3 + SIM7080G) carries events or alerts over LTE. Two roles, both pure firmware, no base-station changes:
- Solo tripwire (
firmware/piezo_vibration,BACKHAUL_CELL 1): one box, no Pi. The sensor classifies on-device as usual and SMSes the event straight over LTE. What you give up is everything the Pi does — cross-sensor correlation, arming schedules, whitelist, history, the dashboard, the durable outbox — in exchange for zero infrastructure. The same cellular block copies into any other sensor sketch. - Alert bridge (
firmware/sim7080_alert_bridge): keeps the full Pi base station. The board joins the base LAN over WiFi, subscribes to the alert topic (EnableMqtt = true,MqttAlertTopic), and pushes each finished alert out over LTE. The cellular counterpart to the RelayFabric LoRa path below.
Egress is SMS by default — native to the modem, no data plan, texts land on
the configured phone. Setting CELL_WEBHOOK 1 also POSTs each alert over LTE
data to a URL you control; point that at a signal-cli / ntfy / Telegram relay
to reach those services. (Signal can't originate on the modem itself — there is
no embedded Signal client — so the relay does the actual delivery.) TLS on the
modem is the one part that needs on-hardware tuning.
Config lives in the sketch's cell block: APN, SMS number, and the T-SIM7080G-S3
modem pins (verify against your board revision — the comment notes the
wiki/repo discrepancy on PWRKEY). Install TinyGSM
(arduino-cli lib install TinyGSM) before building.
Off-grid alerts (RelayFabric)¶
ntfy, webhook, Twilio, and SMTP all need the Internet, the opposite of the
remote sites this is built for. Set EnableMqtt = true in [Notifications]
and the monitor publishes each alert as JSON to MqttAlertTopic on the same
broker. RelayFabric subscribes
there and relays alerts over a LoRa mesh (Meshtastic, MeshCore, or
LXMF/Reticulum), so they reach you with no cellular. See RelayFabric's
meshtripwire plugin (formatted alerts) or its examples/meshtripwire.yaml
(generic mqtt plugin, no extra code).