Chatting via Meshtastic in Emacs

Leer en español

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
    D["📻 Meshtastic\ndevice"]:::device
    B["🐍 meshtastic-bridge.py\n(Python subprocess)"]:::bridge
    E["meshtastic.el\n(Emacs)"]:::emacs

    D <-->|"USB serial"| B
    B <-->|"JSON\nstdin / stdout"| E

    classDef device fill:#37474F,stroke:#263238,stroke-width:2px,color:#fff
    classDef bridge fill:#00897B,stroke:#00695C,stroke-width:2px,color:#fff
    classDef emacs fill:#7B1FA2,stroke:#4A148C,stroke-width:2px,color:#fff

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

Next, install my package. It's available on MELPA.

M-x package-install RET meshtastic RET

Otherwise you can use use-package and :vc, which are native to Emacs.

(use-package meshtastic
  :vc (:url "https://git.andros.dev/andros/meshtastic.el"
       :rev :newest))

Configuration

Linux

Find the port with:

ls /dev/ttyUSB* /dev/ttyACM*
(setq meshtastic-serial-port "/dev/ttyUSB0")

If you get a permission error, add your user to the dialout group:

sudo usermod -aG dialout $USER

macOS

Ports on macOS use the cu.usbserial-* scheme:

ls /dev/cu.usbserial-*
(setq meshtastic-serial-port "/dev/cu.usbserial-0001")

Windows

(setq meshtastic-serial-port "COM3")
(setq meshtastic-python-executable "python")

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
  Port:      /dev/ttyUSB0
  Status:    Connected
  Node:      Hilltop Relay (!a1b2c3d4)

  Statistics
  Nodes:     12
  Channels:  2

  --------------------------------------

  [c] Channels          [n] Nodes
  [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
  0   LongFast      Primary
  1   HikingGroup   Secondary

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
  0     🟢 Hilltop Relay               !a1b2c3d4       now         85%
  1     🟢 Solar Node 7                !d4e5f6a7       12m         -
  2     🟢 BaseStation K9              !b8c9d0e1       5m          62%
  3     ⚫ Mountain Peak               !f2a3b4c5       1h          -

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] <Hilltop Relay> Good morning mesh!
[08:20] <BaseStation K9> Morning! Signal is great today
[08:21] <Solar Node 7> Copy that, 3 hops from here
[09:05] <BaseStation K9> Confirmed ✓
#LongFast> _

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)
  ✓ → Hilltop Relay → BaseStation K9 (8.0dB) → Solar Node 7
  ← Solar Node 7 → BaseStation K9 (7.0dB) → Hilltop Relay

[08:31:15] → Mountain Peak (!f2a3b4c5)
  ⧖ Pending...

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.

Ayúdame a seguir escribiendo

Cada café me da un empujón para escribir el siguiente artículo.

Comentarios

Todavía no hay ningún comentario.

Sigue leyendo