This Discord bot is used to communicate directly with the Meshtastic network using a Meshtastic compatible device.
Having a Discord bot directly connected to the Meshtastic network allows users to test their devices and get instant feedback on whether another device has received their message. It also allows the user to communicate on their local network no matter where they are in the world.
- Relays text messages from your configured mesh channels into Discord as embeds, with the sender's name, node ID, channel, hop count, and time — each node gets a consistent color derived from its ID so conversations are easy to follow.
- Mesh replies become threaded Discord replies, and mesh emoji tapbacks become reactions on the original Discord message.
- Message routing: automated messages (node status pings, welcome announcements, etc.) can be redirected to a separate Discord channel by regex, keeping your main channel human-only.
- Send from Discord to the mesh via slash commands — to a channel, or directly to a node by ID or number. Messages are truncated to fit the mesh packet size limit, with a warning when that happens.
- Direct messages seen on the mesh are never relayed to Discord, by design.
- Automatic reconnection with exponential backoff, plus a periodic heartbeat health check that detects silently-dead connections.
- Rotating daily log files (7-day retention) for diagnostics.
-
Install dependencies (Python 3.10+ recommended):
pip install -r requirements.txt
-
Connect to your Meshtastic device. Two connection modes, chosen via
mesh_connection.typeinconfig.json:serial(default) — plug your device into the host over USB. See supported hardware. With multiple serial devices connected, setmesh_connection.serial_portto the exact port (e.g./dev/ttyUSB0on Linux,COM3on Windows); otherwise leave it blank to auto-detect.tcp— connect to a node reachable over your network (WiFi/Ethernet-enabled, or one you expose remotely yourself). Setmesh_connection.tcp_hostnameandmesh_connection.tcp_port(Meshtastic's default API port is4403).
-
Create a Discord bot and invite it to your server. Instructions here.
Copy the example config and fill in your own values:
cp config.example.json config.json| Field | Description |
|---|---|
discord_bot_token |
Your Discord bot's token. |
discord_default_channel_id |
The Discord channel mesh messages are relayed to (unless a message route redirects them). How to find a channel ID. |
time_zone |
Your timezone, used for message timestamps. List of valid values. Validated at startup. |
mesh_connection |
Connection settings — see Setup above. If omitted entirely, defaults to serial auto-detect. |
channel_names |
Maps mesh channel indices (0–7) to the channel names configured on your radio. Only channels listed here are relayed to Discord — leave a channel out to ignore it entirely. Each name also becomes a /channelname slash command, so names must be unique. |
message_routes |
Optional. Redirect specific mesh messages to a different Discord channel by content — see below. |
Message routing. By default every relayed message goes to discord_default_channel_id. Routes redirect messages elsewhere based on their text — handy for splitting automated chatter (status pings, join announcements) away from human conversation. Each entry has a name (label used in logs), a pattern (Python regex tested against the message text — first match wins), and a channel_id (destination). Messages matching no route go to the default channel; a route with an invalid regex or missing field is skipped with a warning at startup. Tapbacks and threaded replies follow the message to whichever channel it was routed to.
Example — routing two kinds of bot-generated messages to a separate channel:
"message_routes": [
{
"name": "node_status",
"pattern": "^.+ has been online for .*?\\|.*\\d+ of \\d+ online",
"channel_id": "YOUR_STATUS_CHANNEL_ID"
},
{
"name": "welcome",
"pattern": "^Welcome .+ \\([^)]+\\) to the mesh!",
"channel_id": "YOUR_WELCOME_CHANNEL_ID"
}
]python main.pyConsole output shows INFO and above; the rotating meshbot.log files capture full DEBUG detail including complete packet dumps.
Channel command names depend on your channel_names entries.
/sendid <nodeid> <message>— direct message a node by ID, e.g./sendid !7c5acfa4 hello./sendnum <nodenum> <message>— direct message a node by number, e.g./sendnum 2086326180 hello./<channel-name> <message>— one command perchannel_namesentry (e.g./longfast), sends on that mesh channel./active— nodes heard in the last 30 minutes, with hops, SNR, and battery./help— command list and useful links.
The idea for this bot was inspired by the Meshtastic Discord Bridge created by raudette.





