Goal: field nodes have no internet. One node at home with WiFi acts as the MQTT gateway, hears everything over LoRa, and relays it to Home Assistant.
FIELD (no internet) HOME
+---------------------+ +-----------------------+ +------------------+
| Heltec V3 + XIAO | LoRa | Cardputer ADV | WiFi | Home Assistant |
| camera node |======> | (MQTT gateway: WiFi |=====>| Mosquitto broker |
| "MOTION at cam1" | <===== | + MQTT enabled) |<=====| + Meshtastic HACS|
+---------------------+ +-----------------------+ MQTT +------------------+
^ |
| "snap" downlink: HA publishes -> ADV transmits -> field V3 -> XIAO snaps
+----------------------------------------------------------+
Role split:
- Heltec V3 (field) — paired with the XIAO camera (see main README). Plain Meshtastic, battery/solar, just needs its channel set to uplink enabled.
- Cardputer ADV (home) — on house WiFi, MQTT enabled, pointed at HA's broker. It uplinks every packet it hears (including the field node's text) and forwards downlink commands back out over LoRa.
- Home Assistant — Mosquitto broker add-on + the official
meshtastic/home-assistantintegration (auto-discovers nodes) + the custom motion sensor / snap button below.
- Install the Mosquitto broker add-on (Settings → Add-ons), create an MQTT user/pass.
- Add MQTT integration if not present (it auto-detects Mosquitto).
- Install HACS, then add
meshtastic/home-assistantas a custom repository and install it. It subscribes to the broker and auto-creates a device per node with battery / SNR / position / telemetry sensors — no extra YAML needed for those.
Plug the ADV in over USB and run (CLI: pip install meshtastic):
# Join house WiFi
meshtastic --set network.wifi_enabled true \
--set network.wifi_ssid "YOUR_SSID" \
--set network.wifi_psk "YOUR_WIFI_PASSWORD"
# Point MQTT at the Home Assistant Mosquitto broker
meshtastic --set mqtt.enabled true \
--set mqtt.address "192.168.1.50" \
--set mqtt.username "mqtt_user" \
--set mqtt.password "mqtt_pass" \
--set mqtt.json_enabled true \
--set mqtt.encryption_enabled false
# Enable uplink (and downlink, for the "snap" command) on the primary channel
meshtastic --ch-index 0 --ch-set uplink_enabled true
meshtastic --ch-index 0 --ch-set downlink_enabled trueRegion must match on every node (e.g.
meshtastic --set lora.region US). The MQTT root topic then becomesmsh/US/.... ChangeUSbelow to your region.
On the field Heltec V3, just make sure its channel uplinks too:
meshtastic --ch-index 0 --ch-set uplink_enabled trueThe camera node publishes the text MOTION at cam1. With json_enabled, the gateway
publishes it to:
msh/US/2/json/LongFast/!<gateway_nodeid> (channel name = LongFast by default)
Add the entities in ha/ to your Home Assistant config (see those files), then reload.
- binary_sensor
cam1_motionflipsonwhen aMOTION at cam1text arrives. - button
cam1_snappublishes asendtextdownlink so the field node tells the XIAO to take a photo.
Downlink note: HA publishes to msh/US/2/json/mqtt/ with this payload (the
meshtastic/firmware JSON downlink format):
{ "from": 2130636288, "type": "sendtext", "payload": "snap", "channel": 0 }from = the decimal node ID of the gateway (ADV). Get it with
meshtastic --info (the num field) and put it in ha/automations.yaml.
Before adding any HA entities, confirm packets are actually flowing with the MQTT
client tools — see ha/mosquitto-cheatsheet.md. Subscribe to msh/#, watch the field
node's text arrive, and test the snap downlink by hand. Only wire up HA once you see
traffic.
ha/lovelace-card.yaml is a ready-to-paste card: motion indicator, last message, a
"Take photo" button (calls the snap script), and the gateway's battery/SNR.