Meshtastic Python Scripting
The meshtastic Python Library
The official meshtastic Python library provides programmatic access to any Meshtastic device. It exposes the full device API: sending and receiving messages, reading/writing configuration, querying node lists, requesting telemetry, and subscribing to real-time events.
Install:
pip install meshtastic
Official documentation: python.meshtastic.org
Source and examples: github.com/meshtastic/python
Connection Types
| Interface class | Transport | Typical use |
|---|---|---|
meshtastic.SerialInterface |
USB serial (CDC ACM) | Direct connection, most reliable; default port auto-detected or specify /dev/ttyUSB0 |
meshtastic.TCPInterface |
TCP/IP over WiFi | Wireless connection to nodes with WiFi enabled (ESP32 devices); specify host IP |
meshtastic.BLEInterface |
Bluetooth Low Energy | Short-range wireless; requires BlueZ on Linux or appropriate BLE stack |
Basic Usage Examples
Connect and print node info
import meshtastic import meshtastic.serial_interface iface = meshtastic.serial_interface.SerialInterface() print(iface.nodes) # dict of all known nodes iface.close()
Send a message to a channel
iface.sendText("Hello mesh", channelIndex=0)
# channelIndex=0 is the primary channel; 1–7 are secondary channels
Subscribe to received messages
from pubsub import pub
def on_receive(packet, interface):
print(f"Received: {packet}")
pub.subscribe(on_receive, "meshtastic.receive")
# Keep the script alive while the interface thread processes events
import time
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
iface.close()
Get node list with last-heard timestamps
for node_id, node in iface.nodes.items():
last_heard = node.get("lastHeard", "unknown")
name = node.get("user", {}).get("longName", node_id)
print(f"{name}: last heard {last_heard}")
Read and write device config
local = iface.getNode('^local')
# Read
print(local.localConfig.lora.hop_limit)
# Write
local.localConfig.lora.hop_limit = 5
local.writeConfig("lora")
Request position from local node
iface.getNode('^local').requestPosition()
Automation Use Cases
- Automated mesh announcements — scheduled weather, news, or system status broadcasts on a channel.
- Message bridges — relay messages between the mesh and Telegram, Discord, Matrix, or SMS (via Twilio). Bidirectional bridging is straightforward with the pub/sub event model.
- Telemetry logging — write incoming telemetry packets to CSV, SQLite, or InfluxDB for Grafana dashboards.
- Position mapping — forward GPS positions to a self-hosted map (e.g. Traccar, OwnTracks, or a custom Leaflet map).
- Alert systems — trigger SMS or email alerts when specific nodes go offline (last-heard threshold exceeded).
- Config management — script bulk configuration changes across many nodes connected via TCP.
Common Patterns
# Connect (serial, auto-detect port)
iface = meshtastic.serial_interface.SerialInterface()
# Connect (TCP)
iface = meshtastic.tcp_interface.TCPInterface("192.168.1.50")
# Send text
iface.sendText("Hello mesh", channelIndex=0)
# Send to specific node (DM)
iface.sendText("Private message", destinationId="!a1b2c3d4", channelIndex=0)
# Request position
iface.getNode('^local').requestPosition()
# Write channel config
ch = iface.getNode('^local').channels[0]
ch.settings.name = "MyNet"
iface.getNode('^local').writeChannel(0)
Event Loop and Threading
The library spawns a background thread that reads from the serial/TCP connection and dispatches events via the PyPubSub pub/sub system. Your on_receive callback is called in that background thread — use thread-safe data structures (queues, locks) if you share state with your main thread.
Available topics:
meshtastic.receive— any incoming packetmeshtastic.receive.text— text messages onlymeshtastic.receive.position— position updatesmeshtastic.receive.telemetry— telemetry packetsmeshtastic.connection.established— fired after successful connectmeshtastic.connection.lost— fired on disconnect
Error Handling
- Serial port busy: only one process can hold the serial port. Close the Meshtastic app or CLI before running your script. Use
try/finally: iface.close()to release cleanly. - Reconnection on disconnect: subscribe to
meshtastic.connection.lostand re-instantiate the interface with exponential backoff. - Timeout handling:
SerialInterfacehas anoProtoparameter — set it toTruefor raw serial access without waiting for a Meshtastic handshake, useful for debugging hardware. - Packet validation: always guard against missing keys in the packet dict; not all fields are present in every packet type.
No comments to display
No comments to display