Skip to main content

A stateless thread-safe REST API for Meshtastic

Project description

restmesh

Buy me a coffee

A stateless thread-safe REST API for Meshtastic.

Description and features

Send messages on Meshtastic using a standard REST API:

  • thread safe via asyncio
  • safe because a FIFO queue avoid overwhelming the mesh
  • very simple to integrate in other projects: Apprise is already available
  • aims to have 100% unit test coverage
  • doesn't use a database, it merely acts as a gateway
  • no MQTT, WiFI, bluetooth: just plug in the radio via USB, set it as CLIENT_MUTE and enjoy

A typical use case for restmesh is for system error reporting, for example when local Internet is down. You could set up a script to interface with restmesh like this:

#!/usr/bin/env bash

# See:
# https://www.iana.org/domains/root/servers
#
# It is very improbable that 3 root DNS server go simultaneously offline.
#
ANYCAST_1='198.41.0.4'
ANYCAST_2='192.36.148.17'
ANYCAST_3='202.12.27.33'

(nc -zu -w 2 "${ANYCAST_1}" 53 || nc -zu -w 2 "${ANYCAST_2}" 53 || nc -zu -w 2 "${ANYCAST_3}" 53) 2>/dev/null && anycast_ok='true' || anycast_ok='false'

if [ "${anycast_ok}" = 'false' ]; then
    echo 'Internet unreachable, alerting mesh channel'

    # Use Meshtastic channel 1 (a non-primary channel).
    # Channel IDs are the same reported in the mobile app.
    #
    # You need to install apprise first via pip or your distro's package
    # manager.
    apprise -b 'ERROR: Internet unreachable' "json://127.0.0.1:8000/api/v1/integrations/apprise/channels/1/messages"
fi

Quickstart

Installation

pip install restmesh

CLI help

usage: restmesh [-h] [--host HOST] [--port PORT] [--radio-serial-path RADIO_SERIAL_PATH]

restmesh: stateless thread-safe REST API for Meshtastic

options:
  -h, --help            show this help message and exit
  --host HOST           Server host listening address (default: 127.0.0.1)
  --port PORT           Server listening port (default: 8000)
  --radio-serial-path RADIO_SERIAL_PATH
                        Path of the USB serial device radio (default: /dev/ttyUSB0)

Running

Defaults

restmesh --host 127.0.0.1 --port 8000 --radio-serial-path /dev/ttyUSB0

Connect to http://127.0.0.1/docs for the Swagger page to test the endpoints, or use Apprise directly.

Globally

restmesh --host 0.0.0.0 --port 8000 --radio-serial-path /dev/ttyUSB0

[!WARNING] At the moment no kind of authentication is implemented!

REST API

This endpoint documentation is automatically generated from FastAPI OpenAPI's generator and swagger-markdown.


[POST] /api/v1/channels/{channel_index}/messages

Send a message to a channel

Broadcast a text message to a specific mesh channel.

Parameters

Name Located in Description Required Schema
channel_index path The channel index (0 to 7) Yes integer

Request Body

Required Schema
Yes application/json: ChannelBroadcastPayload

Responses

Code Description Schema
202 Successful Response application/json: MeshActionResponse
422 Validation Error application/json: HTTPValidationError
429 Unable to handle more requests because the FIFO queue is full application/json: QueueErrorResponse
503 Meshtastic radio problem. Different errors can be returned. application/json: RadioErrorResponse

[POST] /api/v1/nodes/{node_target}/messages

Send Text To Node

Send a DM text to a node via nodeId string or nodeNum integer.

Parameters

Name Located in Description Required Schema
node_target path Target destination: can be a lowercase hex string NodeId (e.g. !2c3b4f5a) or a numeric NodeNum < 2^32 (e.g. 60). Yes string or integer

Request Body

Required Schema
Yes application/json: NodeDirectPayload

Responses

Code Description Schema
202 Successful Response application/json: MeshActionResponse
422 Validation Error application/json: HTTPValidationError
429 Unable to handle more requests because the FIFO queue is full application/json: QueueErrorResponse
503 Meshtastic radio problem. Different errors can be returned. application/json: RadioErrorResponse

[POST] /api/v1/integrations/apprise/channels/{channel_index}/messages

Apprise Gateway Adapter Send Text Channel

Adapter gateway.

Parameters

Name Located in Description Required Schema
channel_index path The channel index (0 to 7) Yes integer

Request Body

Required Schema
Yes application/json: AppriseJsonChannelBroadcastPayload

Responses

Code Description Schema
202 Successful Response application/json: MeshActionResponse
422 Validation Error application/json: HTTPValidationError
429 Unable to handle more requests because the FIFO queue is full application/json: QueueErrorResponse
503 Meshtastic radio problem. Different errors can be returned. application/json: RadioErrorResponse

[POST] /api/v1/integrations/apprise/nodes/{node_target}/messages

Apprise Gateway Adapter Send Text Node

Adapter gateway.

Parameters

Name Located in Description Required Schema
node_target path Target destination: can be a lowercase hex string NodeId (e.g. !2c3b4f5a) or a numeric NodeNum < 2^32 (e.g. 60). Yes string or integer

Request Body

Required Schema
Yes application/json: AppriseJsonNodeDirectPayload

Responses

Code Description Schema
202 Successful Response application/json: MeshActionResponse
422 Validation Error application/json: HTTPValidationError
429 Unable to handle more requests because the FIFO queue is full application/json: QueueErrorResponse
503 Meshtastic radio problem. Different errors can be returned. application/json: RadioErrorResponse

Schemas

AppriseJsonChannelBroadcastPayload Schema

Name Type Description Required
version string Yes
title string or null Unused parameter No
message string UTF-8 text limited to the 237 byte Meshtastic MTU (200 here for safety) Yes
type string,
Available values: "info", "warning", "success", "failure" or null
Unused parameter No
attachment [ ],
Default:
Unused parameter No
wantAck boolean true if you want the message sent in a reliable manner (with retries and ack/nak provided for delivery) No
portNum integer,
Default: 1
Protobuf application port number No

AppriseJsonNodeDirectPayload Schema

Name Type Description Required
version string Yes
title string or null Unused parameter No
message string UTF-8 text limited to the 237 byte Meshtastic MTU (200 here for safety) Yes
type string,
Available values: "info", "warning", "success", "failure" or null
Unused parameter No
attachment [ ],
Default:
Unused parameter No
wantAck boolean true if you want the message sent in a reliable manner (with retries and ack/nak provided for delivery) No
wantResponse boolean,
Default: true
true if you want the service on the other side to send an application layer response No
portNum integer,
Default: 1
Protobuf application port number No

ChannelBroadcastPayload Schema

Name Type Description Required
text string UTF-8 text limited to the 237 byte Meshtastic MTU (200 here for safety) Yes
wantAck boolean true if you want the message sent in a reliable manner (with retries and ack/nak provided for delivery) No
portNum integer,
Default: 1
Protobuf application port number No

HTTPValidationError Schema

Name Type Description Required
detail [ ValidationError ] No

MeshActionResponse Schema

Name Type Description Required
status string Yes
routing_mode string,
Available values: "broadcast", "direct"
Enum: "broadcast", "direct" Yes
packet MeshPacketDetails Yes
onResponse_callback_payload object or null No
truncated boolean No

MeshPacketDetails Schema

Name Type Description Required
id integer Yes
from integer or string Yes
to integer or string Yes
channel integer The channel index (0 to 7) Yes
portnum integer Protobuf application port number Yes
text string The message sent to the mesh Yes
wantAck boolean true if you want the message sent in a reliable manner (with retries and ack/nak provided for delivery) No
wantResponse boolean,
Default: true
true if you want the service on the other side to send an application layer response No

NodeDirectPayload Schema

Name Type Description Required
text string UTF-8 text limited to the 237 byte Meshtastic MTU (200 here for safety) Yes
wantAck boolean true if you want the message sent in a reliable manner (with retries and ack/nak provided for delivery) No
wantResponse boolean,
Default: true
true if you want the service on the other side to send an application layer response No
portNum integer,
Default: 1
Protobuf application port number No

QueueErrorResponse Schema

Name Type Description Required
detail string,
Default: Unable to handle more requests, queue full.
No

RadioErrorResponse Schema

Name Type Description Required
detail string,
Default: Meshtastic radio problem
No

ValidationError Schema

Name Type Description Required
loc [ string or integer ] Yes
msg string Yes
type string Yes
input No
ctx object No

Integrations

Apprise

restmesh accepts Apprise via the JSON schema. To be able to use it you need to install it first. See also the Repology page to see the available packages for Apprise.

[!NOTE] The title parameter is ignored! Write your full text in the body.

Channel

Simple example using channel 0:

apprise -b 'My message here' "json://localhost:8000/api/v1/integrations/apprise/channels/0/messages"

With parameters:

apprise -b 'Hello world!' "json://localhost:8000/api/v1/integrations/apprise/channels/0/messages?:wantAck=false&:portNum=1"

Node

Send a message to the node with hex id !0a1b2c3d. Alternatively you can use the decimal integer representation of the node id, without prepending the ! character:

apprise -b 'My message here' "json://localhost:8000/api/v1/integrations/apprise/nodes/!0a1b2c3d/messages"

apprise -b 'My message here' "json://localhost:8000/api/v1/integrations/apprise/nodes/169552957/messages"

With parameters:

apprise -b 'Hello world!' "json://localhost:8000/api/v1/integrations/apprise/nodes/!0a1b2c3d/messages?:wantResponse=true&wantAck=false&:portNum=1"

apprise -b 'Hello world!' "json://localhost:8000/api/v1/integrations/apprise/nodes/169552957/messages?:wantResponse=true&wantAck=false&:portNum=1"

Contributing

See Contributing.

Responsible usage policy

Meshtastic

In some places, such as Europe, the non-ham LoRa band has limited air time use. Please don't use restmesh for mass spamming, and never broadcast automated messages on public channels such as MediumFast or LongFast. Setup private channels instead.

restmesh has a basic message FIFO queue also to mitigate the air time problem.

Consulting and custom integrations

If you need help or custom endpoints and integrations, I'm available for contract-based freelance consulting and custom Python development:

License

Copyright (C) 2026 Franco Masotti

restmesh is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

restmesh is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with restmesh. If not, see http://www.gnu.org/licenses/.

Changelog and trusted source

You can check the authenticity of new releases using my public key.

Changelogs, instructions, sources and keys can be found at blog.franco.net.eu.org/software/#restmesh.

Git forge mirrors

URL Type
https://codeberg.org/frnmst/restmesh RW
https://framagit.org/frnmst/restmesh RW
https://repos.franco.net.eu.org/frnmst/restmesh RW
https://github.com/frnmst/restmesh RO (push mirror only)

Support this project

  • Buy Me a Coffee
  • Liberapay
  • Bitcoin: bc1qnkflazapw3hjupawj0lm39dh9xt88s7zal5mwu
  • Monero: 84KHWDTd9hbPyGwikk33Qp5GW7o7zRwPb8kJ6u93zs4sNMpDSnM5ZTWVnUp2cudRYNT6rNqctnMQ9NbUewbj7MzCBUcrQEY
  • Dogecoin: DMB5h2GhHiTNW7EcmDnqkYpKs6Da2wK3zP
  • Vertcoin: vtc1qd8n3jvkd2vwrr6cpejkd9wavp4ld6xfu9hkhh0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

restmesh-0.1.0.tar.gz (30.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

restmesh-0.1.0-py3-none-any.whl (25.4 kB view details)

Uploaded Python 3

File details

Details for the file restmesh-0.1.0.tar.gz.

File metadata

  • Download URL: restmesh-0.1.0.tar.gz
  • Upload date:
  • Size: 30.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for restmesh-0.1.0.tar.gz
Algorithm Hash digest
SHA256 046908b72ca2e39eb85dfb563733a44f969e53c350f5a07715cfc3a54da35f5f
MD5 02c8e2424028d43a74643a55cb32a448
BLAKE2b-256 3d22dfc8e3ad9c3b560f6b05edcecd046ffc213dc816518bec6fee84c90528de

See more details on using hashes here.

File details

Details for the file restmesh-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: restmesh-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for restmesh-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e5d92e70a381d8fdb7b269491de619a299ec9f24a54b328303d9e00aef523666
MD5 a7a6c8522311256150743634c85838e4
BLAKE2b-256 c282a64dea3b087cbb8aafe08d8a0cf8b4d0f2c4974971c233a1ad0913c1d040

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page