Chatting via Meshtastic in Emacs | Andros Fenollosa
I'd like to show you how to connect a Meshtastic device over USB directly to Emacs using a package I built for myself called meshtastic.el.
How it works
meshtastic.el spawns a Python subprocess that talks to the device over serial. Messages arrive as JSON lines at the Emacs process filter.
flowchart LR<br>D["๐ป Meshtastic\ndevice"]:::device<br>B["๐ meshtastic-bridge.py\n(Python subprocess)"]:::bridge<br>E["meshtastic.el\n(Emacs)"]:::emacs
D |"USB serial"| B<br>B |"JSON\nstdin / stdout"| E
classDef device fill:#37474F,stroke:#263238,stroke-width:2px,color:#fff<br>classDef bridge fill:#00897B,stroke:#00695C,stroke-width:2px,color:#fff<br>classDef emacs fill:#7B1FA2,stroke:#4A148C,stroke-width:2px,color:#fff<br>They are shown in ERC-style chat buffers.
Installation
The first thing you need to do is install the Meshtastic Python library.
pip install meshtastic<br>Next, install my package. It's available on MELPA.
M-x package-install RET meshtastic RET<br>Otherwise you can use use-package and :vc, which are native to Emacs.
(use-package meshtastic<br>:vc (:url "https://git.andros.dev/andros/meshtastic.el"<br>:rev :newest))<br>Configuration
Linux
Find the port with:
ls /dev/ttyUSB* /dev/ttyACM*<br>(setq meshtastic-serial-port "/dev/ttyUSB0")<br>If you get a permission error, add your user to the dialout group:
sudo usermod -aG dialout $USER<br>macOS
Ports on macOS use the cu.usbserial-* scheme:
ls /dev/cu.usbserial-*<br>(setq meshtastic-serial-port "/dev/cu.usbserial-0001")<br>Windows
(setq meshtastic-serial-port "COM3")<br>(setq meshtastic-python-executable "python")<br>The port number appears in Device Manager, under "Ports (COM & LPT)".
Usage
With everything ready, you can run M-x meshtastic. The bridge starts automatically and the welcome screen shows the connection status:
Meshtastic
Connection<br>Port: /dev/ttyUSB0<br>Status: Connected<br>Node: Hilltop Relay (!a1b2c3d4)
Statistics<br>Nodes: 12<br>Channels: 2
[c] Channels [n] Nodes<br>[g] Refresh [q] Quit
While connecting, the status shows Connecting.... Once the connection is established it changes to Connected and the node and channel statistics appear without needing to refresh manually.
Channel list
Press c to see the available channels:
ID Name Role<br>0 LongFast Primary<br>1 HikingGroup Secondary<br>Press RET on any channel to open its chat, or use the 0-7 keys directly.
Node list
Press n to see all the nodes on the mesh:
Hops Name Node ID Last heard Battery<br>0 ๐ข Hilltop Relay !a1b2c3d4 now 85%<br>1 ๐ข Solar Node 7 !d4e5f6a7 12m -<br>2 ๐ข BaseStation K9 !b8c9d0e1 5m 62%<br>3 โซ Mountain Peak !f2a3b4c5 1h -<br>The list is sorted by hops. The ๐ข indicator means the node has been heard in the last 15 minutes. The Battery column shows the battery level when the node has sent telemetry; - if there's no data yet.
The list updates automatically when nodes exchange information on the mesh, without needing to press g.
Chat
Press RET on a channel or node to open the chat buffer:
[08:15] Good morning mesh!<br>[08:20] Morning! Signal is great today<br>[08:21] Copy that, 3 hops from here<br>[09:05] Confirmed โ<br>#LongFast> _<br>Type your message after the prompt and press RET to send. Your own messages show ยท while they wait for confirmation from the bridge and change to โ when the bridge confirms the send.
Navigate the input history with M-p and M-n.
Traceroute
Press t on any node in the list to send a traceroute. A dedicated log buffer opens:
[08:30:01] โ Solar Node 7 (!d4e5f6a7)<br>โ โ Hilltop Relay โ BaseStation K9 (8.0dB) โ Solar Node 7<br>โ Solar Node 7 โ BaseStation K9 (7.0dB) โ Hilltop Relay
[08:31:15] โ Mountain Peak (!f2a3b4c5)<br>โง Pending...<br>Each entry shows the forward route with the SNR values of each hop, and the return route. While waiting for the response, โง Pending... appears and updates as soon as it arrives.
You can also use M-x meshtastic-traceroute from a DM buffer (it uses the chat's node) or from any other buffer (it asks for the Node ID).
Send position
M-x meshtastic-send-position sends your GPS coordinates to the selected node. It uses calendar-latitude and calendar-longitude if they are configured in Emacs; if not, it falls back to the device's own GPS; and if there's none either, it shows an error.
It works from the node list, from a DM, or from any buffer (in which case it asks for the Node ID).
Limitations
We shouldn't equate a modern messaging app with a LoRa conversation. Its limitations are structural and you have to learn to live with them. Emacs can't get around them.
No history on startup : the bridge has no database. Only the messages received since it started are available.
Limited bandwidth : LoRa is a long-range but low-speed radio. Messages must be short.
One device per instance : each Emacs instance connects to a single serial port.
Messages can be lost : nobody guarantees that messages reach the recipient.
But what has no limit is the fun and all the people you can get to meet in your area.
How it...