Skip to content

How MMRelay Works

Jeremiah K edited this page Aug 17, 2026 · 6 revisions

How MMRelay Works

MMRelay is a self-hosted bridge between a Meshtastic meshnet and Matrix. It runs continuously on a computer or server, connects to a Meshtastic node, and logs in to Matrix with a dedicated bot account.

The important idea is simple:

Meshtastic meshnet ⇄ Meshtastic node ⇄ MMRelay ⇄ Matrix rooms

Only traffic covered by MMRelay's configuration crosses that boundary.

sequenceDiagram
    participant N as Meshtastic node
    participant R as MMRelay
    participant X as Matrix room

    Note over N,X: Mesh to Matrix
    N->>R: text packet on mapped channel
    R->>X: bot posts message with sender prefix

    Note over N,X: Matrix to Mesh
    X->>R: message from a Matrix user
    R->>N: transmit on the mapped channel
Loading

Why run it

  • Reach the mesh from anywhere. A Meshtastic mesh only covers as far as its radios. Bridged into a Matrix room, the mesh is reachable from any Matrix client with Internet access — you can keep up with (and talk to) your mesh from your phone while you're away from the radio, or from anywhere with connectivity but no LoRa coverage.
  • Let people without radios take part. Family, friends, or a community don't need LoRa hardware or a second app; from their side the mesh is just another Matrix room.
  • Connect meshnets across regions. LoRa range is local. Multiple operators can each bridge their meshnet into a shared Matrix room, joining communities that could never reach each other over the air (see Multiple meshnets in one room).
  • Ride Matrix's bridges. Matrix connects to many other chat platforms; a mesh bridged into a Matrix room can, through those bridges, reach users on other networks too.

The pieces

Meshtastic meshnet

A meshnet is the local Meshtastic network. Its radios (also commonly called nodes or devices) communicate over the mesh and may relay packets for one another.

MMRelay does not need a direct connection to every node. It communicates with the mesh through one Meshtastic node that is available to the MMRelay service. For an always-on bridge, dedicating a node to MMRelay is usually the simplest and most predictable setup, although the node is still a normal participant in the Meshtastic mesh.

The Meshtastic connection

MMRelay supports three connection modes to that node:

  • Serial — the node is attached directly to the MMRelay host.
  • BLE — the MMRelay host connects to the node over Bluetooth Low Energy.
  • TCP / network — the node is reachable by IP, commonly through Wi-Fi or Ethernet depending on its firmware and hardware.

These are alternative ways to connect MMRelay to its Meshtastic node; they are not separate relay stages.

MMRelay

MMRelay is the bridge service. It runs on infrastructure you control, receives eligible traffic from either side, applies its configured mapping and relay rules, and sends the resulting traffic to the other side.

MMRelay is not a Matrix client plugin and is not a public relay endpoint that other users configure remotely.

Matrix

MMRelay logs in with a dedicated Matrix bot account and joins the rooms listed in its configuration. Those rooms can be on matrix.org or another homeserver; the important part is that the bot account can access them.

Mapping Matrix rooms to Meshtastic channels

The matrix_rooms section maps a Meshtastic channel to a Matrix room:

matrix_rooms:
  - id: "#field-ops:example.org"
    meshtastic_channel: 0
  - id: "#weather:example.org"
    meshtastic_channel: 1

Meshtastic firmware provides eight channels per node, numbered 0–7. MMRelay requires at least one mapped channel and supports mapping up to all eight. Within one MMRelay instance the mapping is 1:1: one Meshtastic channel maps to one Matrix room.

To bridge multiple meshnets into a shared Matrix room, run one MMRelay instance per meshnet and map each instance's channel to the same room. Each instance relays as its own bot account, and each message carries its origin — see Multiple meshnets in one room for how that round-trips.

Unmapped rooms and channels are not automatically bridged simply because the bot or Meshtastic node can see them.

Meshtastic → Matrix

For an eligible text packet on a mapped channel:

  1. The mesh delivers the packet to the node MMRelay is connected to. MMRelay decodes it and resolves the sender's long/short name and meshnet name from its node database.
  2. MMRelay prefixes the text with the sender and origin — [Long name/Meshnet]: by default, configurable via matrix.prefix_format — and posts it to the mapped room as the bot. The prefix is part of the message body, which is how room members see who and where the message came from.
  3. The Matrix event also carries machine-readable fields (meshtastic_longname, meshtastic_shortname, meshtastic_meshnet, the Meshtastic packet ID, and the raw message text). These are not for display; they exist so other MMRelay instances sharing the room can relay the message onto their own meshnets with the original sender's identity intact (see below).
  4. When message storage is enabled, MMRelay records the packet ID ↔ Matrix event ID mapping in its SQLite database so later replies and reactions can be correlated across the bridge.

Matrix → Meshtastic

MMRelay ignores events sent by its own bot. For other events in a mapped room:

  • Messages from Matrix users are prefixed with the sender's Matrix display name — {display5}[M]: by default, so the mesh sees Alex[M]: hello — truncated to the Meshtastic payload size, and transmitted on the channel mapped to that room. The [M] marker tells the mesh the sender is a Matrix user; the format is configurable via meshtastic.prefix_format.
  • Messages relayed by another MMRelay instance are recognized by their meshtastic_* fields. MMRelay reads the original sender's identity from the event metadata — not from the display text — and transmits the message on its own mesh with that identity preserved, so the receiving mesh sees the original sender (Alice/MeshnetA), not a Matrix user. If the event's meshnet matches the local one, the message is dropped, which prevents relay loops.
  • Replies are sent as Meshtastic replies to the original packet, using the stored ID mapping. Reactions become a short text notice on the mesh, e.g. Alex[M] reacted 😀 to "message preview".

Transmission to the mesh is gated by the broadcast_enabled setting, and bot commands from plugins are handled before anything is relayed.

Multiple meshnets in one room

The multi-instance pattern relies on the event metadata described above:

  1. Alice sends a message on meshnet A. The meshnet A relay posts it to the shared room as [Alice/MeshnetA]: hello, with Alice's identity and the meshnet name in the event's meshtastic_* fields.
  2. The meshnet B relay sees the event from the meshnet A bot, reads the metadata, and transmits the message on meshnet B with Alice's identity preserved — nodes on meshnet B see the message as coming from Alice/MeshnetA, not from a Matrix user or a foreign bot.
  3. Replies and reactions flow back through the same path, so a node on meshnet B replying to Alice's message reaches meshnet A as a proper Meshtastic reply.

Every hop between meshnets is relay-to-relay over ordinary Matrix events; there is no separate inter-server channel.

sequenceDiagram
    participant A as Meshnet A node
    participant RA as MMRelay A
    participant X as Shared Matrix room
    participant RB as MMRelay B
    participant B as Meshnet B node

    A->>RA: text packet from Alice
    RA->>X: bot A posts message, sender identity in event fields
    X->>RB: event from bot A
    RB->>B: transmit with Alice's identity preserved
Loading

Identity and trust boundary

Matrix and Meshtastic have different identity systems. MMRelay bridges messages; it does not turn a Meshtastic node identity into a verified Matrix identity.

That means anyone able to send relay-eligible traffic on a bridged Meshtastic channel can cause the MMRelay bot to post corresponding traffic into its mapped Matrix room. Operators should therefore bridge only channels and rooms whose participants they intend to connect.

In a multi-instance room, each relay forwards the attribution supplied by the other instances. That attribution is data carried in the event, not something Matrix verifies, so a misconfigured or untrusted instance can present forged sender names to your mesh.

Matrix end-to-end encryption protects Matrix traffic and the MMRelay bot's Matrix device identity. It does not authenticate Meshtastic sender names across the bridge.

Where to go next

Clone this wiki locally