Self-hosted service
meshtastic/python avatar
meshtastic/python

meshtastic python is a CLI and a library for talking to mesh radios

The Python CLI and API for talking to Meshtastic devices

851 stars353 forksPythonGPL-3.0

At a glance

What is it?
The meshtastic python project wraps the Meshtastic device protocol in a Python library, a command line client and a container image, with a publish-subscribe event model so a script can subscribe only to the packet types it cares about. It is GPL-3.0, actively released, and openly says it has gone without a consistent maintainer.
Who is it for?
meshtastic python suits a developer who needs to script a Meshtastic node, read position and telemetry data, or run the client somewhere without a Python environment, since the container image on GHCR makes the CLI reachable from any machine that can run Docker.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 14 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One protocol, two ways to use it

The project description calls it the Python CLI and API for talking to Meshtastic devices, and the README describes it as a library and example application that provides an easy API for sending and receiving messages over mesh radios. Two audiences sit behind that. Someone running a script against a node attached to a serial port or a Bluetooth connection wants the library, and someone on a terminal wants the CLI, which is the same code path with argument parsing in front of it. The library is published to PyPI under the name meshtastic, with the current version 2.7.11 recorded in pyproject.toml, and the project also publishes container images to GHCR for the repository. The scope is broader than messaging, because the README says it also provides access to any of the operations and data available in the device user interface or the Android application. That means configuration reads and writes, node inventory, telemetry and position data, not just chat.

Publish-subscribe events, so you only subscribe to what you need

The mechanism for receiving data is a publish-subscribe model, and the README is explicit that events are delivered this way and that you can subscribe to only the message types you are interested in. On a mesh network the volume of traffic is high and mostly irrelevant to any one script. A node listening to a busy channel receives position updates, telemetry, text messages, routing and administration packets, and a client that had to parse all of it would waste cycles and write complicated filtering code. Instead, a subscriber registers interest in the packet types it cares about, and the library delivers only those. The dependency list confirms the design: pypubsub, at version 4.0.3 or newer, is a required dependency rather than an optional one, alongside pyserial for serial links, protobuf for the wire format, requests for HTTP, pyyaml for configuration and bleak for Bluetooth. The examples directory shows the pattern in practice, with a file for publishing and subscribing over TCP and another for a serial message reader.

The container runs the CLI as its entrypoint

Container images are published to GHCR for this repository, and the entrypoint defaults to running meshtastic, so command line flags pass straight through:

bash
docker run --rm ghcr.io/meshtastic/python --help

To run something else, pass the command explicitly, for example a shell:

bash
docker run --rm -it --entrypoint /bin/sh ghcr.io/meshtastic/python

Two operational details are spelled out in the README. The container runs as a non-root user by default, which is the right default but matters for serial access, because a non-root user inside the container still needs permission to reach the device node on the host. When talking to local hardware you pass the serial device through explicitly, for example --device /dev/ttyUSB0:/dev/ttyUSB0, and you have to ensure host device permissions allow access. The repository carries several container definitions, a Containerfile, a Containerfile.alpine and a Containerfile.debian, so the image can be built on either base.

The dependency floor stops at Python 3.14

Installing locally is a normal pip install, and the pyproject.toml pins the interpreter range and the core libraries:

toml
python = "^3.9,<3.15"
pyserial = "^3.5"
protobuf = ">=4.21.12"
pypubsub = "^4.0.3"
bleak = ">=0.22.3"

The comment next to the Python constraint explains why the floor sits where it does, since 3.9 is needed for pandas. The optional extras extend the tool further rather than the core: argcomplete for shell completion, pyqrcode for QR codes, dotmap, print-color, the dash and dash-bootstrap-components pair for a web dashboard, pytap2 for TAP interfaces, pandas for data work and wcwidth for terminal width handling. The dev group adds pytest, pytest-cov, hypothesis for property based testing, pdoc3 for documentation, pylint, mypy and pyinstaller for packaging executables. The package is built with Poetry, and poetry.lock is committed, which is what you want for a library whose consumers depend on consistent behaviour.

Make targets separate unit tests from hardware smoke tests

The Makefile is a good map of how the project is tested, and it distinguishes three levels. The fast unit tests run with pytest -m unit, and the target for the slowest unit tests adds --durations=5. There is a virt target that runs the smoke tests against a virtual device, which is how the project exercises the protocol without radio hardware. Then there are hardware level smoke targets, with smoke1 documented as something to run after a factory reset and unplugging and replugging the device, which tells you that this suite depends on a real node and on the physical act of reconnecting it. The examples target runs the CLI examples as tests, which is why the Makefile has a FORCE hack to make those targets always run. For documentation, pdoc3 generates the HTML docs locally, and for code quality pylint covers the meshtastic package and the examples. The CI targets run pylint, mypy and pytest with coverage, in parallel through Poetry.

The protobuf layer is regenerated from a submodule

The wire format is not hand written. The repository keeps a protobufs/ directory and a .gitmodules file, and the Makefile has a protobufs target that updates the submodule recursively, pulls with rebase, updates the remote, and then runs ./bin/regen-protobufs.sh. That is the standard shape for a project whose protocol definition lives upstream and whose generated Python bindings have to be refreshed when the protocol changes. The dependency on protobuf 4.21.12 or newer follows from this. The cost of that design shows up in the tooling rather than the user API, but it does mean a contributor needs a working protoc toolchain and network access to regenerate the bindings, and it means the generated files are checked into the tree. The mypy CI target also runs against the generated protobuf stubs, since the project ships types-protobuf and mypy-protobuf in the dev dependencies.

The maintainer gap is stated in the README

The most useful thing this project does for an evaluator is tell you the truth about its own staffing. The README says the library and CLI have gone without a consistent maintainer for a while, that there are many improvements that could be made, and that everyone is a volunteer. It then invites contributions, with the roadmap as the place to start if you do not have a specific idea. The roadmap is framed as a list in progress and in flux, where inclusion does not guarantee implementation and exclusion does not mean something is unwanted. The items are concrete enough to be useful. Type annotations throughout the codebase with mypy running in CI at --strict. Async-friendliness. CLI completeness and consistency, with the goal that the CLI should support all features of the firmware and that there should be a consistent output format available for shell scripting. CLI input validation and documentation, including which arguments and options are compatible with one another and whether the options could be restructured to be more self-documenting. Helpers for third-party code, so that a script can support the same ways of connecting to nodes as the CLI. And data storage and processing, with a standardized way of recording packets, a persistence layer beyond the node database, a possible SQLite schema and tools for writing to it, and support for maps, charts and visualizations. The release list shows 2.7.11 on 2026-07-17, 2.7.10 on 2026-06-29 and 2.7.9 on 2026-06-09, and the last push was on 2026-10-09.

Editorial conclusion

meshtastic python suits a developer who needs to script a Meshtastic node, read position and telemetry data, or run the client somewhere without a Python environment, since the container image on GHCR makes the CLI reachable from any machine that can run Docker. It is a poor fit for a project that needs typed, async friendly code with a stable shell interface, since the roadmap lists type annotations with strict mypy, async-friendliness and CLI output consistency as work still to be done. Verify first that the device firmware features you rely on are actually exposed by the CLI, check the supported Python range of ^3.9,<3.15 against your environment, and remember the library is GPL-3.0-only, which decides how you may link it.

Frequently asked questions

How do I install the Meshtastic Python library and CLI?

The package is published to PyPI as meshtastic, and the Makefile provides a local install target that runs pip install . with a poetry managed project. Python 3.9 or newer and below 3.15 is required, with 3.9 needed for pandas.

Can I run the meshtastic CLI in a container?

Yes. Container images are published to GHCR, and the entrypoint defaults to running meshtastic so flags pass straight through, as in docker run --rm ghcr.io/meshtastic/python --help. The container runs as a non-root user by default, so serial hardware needs the device passed in explicitly, for example --device /dev/ttyUSB0:/dev/ttyUSB0.

How does the Meshtastic Python library deliver incoming packets?

Events are delivered using a publish-subscribe model, so you can subscribe only to the message types you are interested in. The pypubsub package is a required dependency of the library.

How do I run the tests for meshtastic python?

The Makefile provides pytest -m unit for the fast unit tests, pytest -m smokevirt for smoke tests against a virtual device, and a smoke1 target for hardware tests after a factory reset and a device reconnect. The CI targets run pylint, mypy and pytest with coverage.

Is the meshtastic Python project actively maintained?

Releases are still shipping, with 2.7.11 on 2026-07-17 and the last push on 2026-10-09, but the README states that the library and CLI have gone without a consistent maintainer for a while and that the contributors are volunteers. The roadmap lists type annotations with strict mypy, async-friendliness and CLI completeness as work still to be done.

Official sources

  1. License: GPL-3.0
  2. meshtastic/python on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/meshtastic-python.svg)](https://hysenlabs.com/projects/meshtastic-python)