2026-07-31 23:16:45 -07:00
|
|
|
# MicroMesh
|
|
|
|
|
|
|
|
|
|
MicroMesh is a small, dependency-free Meshtastic client for MicroPython. It talks to a
|
|
|
|
|
Meshtastic device over its serial API and implements the protobuf wire format directly,
|
|
|
|
|
so `google.protobuf`, threads, and `pyserial` are not required.
|
|
|
|
|
|
|
|
|
|
The initial release supports:
|
|
|
|
|
|
|
|
|
|
- serial `ToRadio` / `FromRadio` framing and resynchronization;
|
|
|
|
|
- the configuration handshake and a small in-memory node list;
|
|
|
|
|
- text, arbitrary data, and position packets;
|
|
|
|
|
- routing acknowledgements, node/user data, waypoints, and device metrics;
|
|
|
|
|
- familiar generated-protobuf methods: `SerializeToString`, `ParseFromString`,
|
|
|
|
|
`CopyFrom`, `HasField`, `ClearField`, and `WhichOneof`;
|
|
|
|
|
- preservation of unknown protobuf fields for forward compatibility.
|
|
|
|
|
|
|
|
|
|
This is intentionally not a complete replacement for the desktop
|
|
|
|
|
[`meshtastic`](https://github.com/meshtastic/python) package. Configuration and admin
|
|
|
|
|
messages are currently returned as raw encoded bytes.
|
|
|
|
|
|
|
|
|
|
## Install
|
|
|
|
|
|
|
|
|
|
From a checkout of this repository, install with a current `mpremote`:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
mpremote mip install package.json
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Alternatively, copy the `micromesh` directory to `/lib` on the board. After this
|
|
|
|
|
repository is published on GitHub it can also be installed as
|
|
|
|
|
`mpremote mip install github:ORG/micromesh`.
|
|
|
|
|
|
|
|
|
|
It can also be installed on CPython for development:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
python -m pip install .
|
|
|
|
|
```
|
|
|
|
|
|
2026-07-31 23:46:37 -07:00
|
|
|
After the first PyPI release, install it by name with:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
python -m pip install micromesh
|
|
|
|
|
```
|
|
|
|
|
|
2026-07-31 23:16:45 -07:00
|
|
|
## Quick start
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
from machine import UART, Pin
|
|
|
|
|
from micromesh import PortNum, SerialInterface
|
|
|
|
|
|
|
|
|
|
uart = UART(1, baudrate=115200, tx=Pin(17), rx=Pin(16), timeout=0)
|
|
|
|
|
|
|
|
|
|
def received(packet):
|
|
|
|
|
if packet.WhichOneof("payload_variant") != "decoded":
|
|
|
|
|
return
|
|
|
|
|
if packet.decoded.portnum == PortNum.TEXT_MESSAGE_APP:
|
|
|
|
|
print("from !%08x:" % packet.from_, packet.decoded.payload.decode())
|
|
|
|
|
|
|
|
|
|
mesh = SerialInterface(uart, on_packet=received)
|
|
|
|
|
mesh.connect()
|
|
|
|
|
mesh.sendText("hello mesh")
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
mesh.poll()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The UART baud rate and pins depend on the attached Meshtastic device. `poll()` is
|
|
|
|
|
non-blocking when the UART is configured with `timeout=0`.
|
|
|
|
|
|
2026-07-31 23:46:37 -07:00
|
|
|
Ready-to-run wiring and code for the Seeed Studio XIAO RP2040, Raspberry Pi Pico, and
|
|
|
|
|
generic ESP32 boards are in [`examples/`](examples/README.md).
|
|
|
|
|
|
2026-07-31 23:16:45 -07:00
|
|
|
Direct messages accept either an integer or Meshtastic's hexadecimal node ID:
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
mesh.sendText("hello", destinationId="!a1b2c3d4", wantAck=True)
|
|
|
|
|
mesh.sendPosition(45.5152, -122.6784, altitude=15)
|
|
|
|
|
mesh.sendData(b"custom", portNum=PortNum.PRIVATE_APP)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Protobufs
|
|
|
|
|
|
|
|
|
|
Messages can be used without a radio:
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
from micromesh import Data, PortNum
|
|
|
|
|
|
|
|
|
|
data = Data(portnum=PortNum.TEXT_MESSAGE_APP, payload=b"hello")
|
|
|
|
|
encoded = data.SerializeToString()
|
|
|
|
|
decoded = Data().ParseFromString(encoded)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Generated-module-style imports are available as `micromesh.mesh_pb2` and
|
|
|
|
|
`micromesh.portnums_pb2` for easier porting from the desktop library.
|
|
|
|
|
|
|
|
|
|
Only the commonly useful schemas are modeled. Unknown fields survive a decode/encode
|
|
|
|
|
round trip, but their contents are not interpreted. A field named `from` is accessed as
|
|
|
|
|
`packet.from_` because `from` is a Python keyword.
|
|
|
|
|
|
|
|
|
|
## Development
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
python -m unittest discover -s tests
|
|
|
|
|
```
|
|
|
|
|
|
2026-07-31 23:46:37 -07:00
|
|
|
## Releasing to PyPI
|
|
|
|
|
|
|
|
|
|
PyPI publishing uses GitHub Trusted Publishing, so no API token is stored in the
|
|
|
|
|
repository. Configure a pending publisher at
|
|
|
|
|
[`pypi.org/manage/account/publishing`](https://pypi.org/manage/account/publishing/)
|
|
|
|
|
with these values:
|
|
|
|
|
|
|
|
|
|
- PyPI project name: `micromesh`
|
|
|
|
|
- GitHub owner: `pdxlocations`
|
|
|
|
|
- Repository: `micromesh`
|
|
|
|
|
- Workflow: `release.yaml`
|
|
|
|
|
- Environment: `pypi`
|
|
|
|
|
|
|
|
|
|
Keep the version in `pyproject.toml`, `package.json`, and `micromesh/__init__.py` in
|
|
|
|
|
sync. Push the change, create a matching GitHub release such as `v0.1.0`, and publish
|
|
|
|
|
the release. The workflow builds, validates, and uploads both the wheel and source
|
|
|
|
|
distribution.
|
|
|
|
|
|
2026-07-31 23:16:45 -07:00
|
|
|
The API protocol is defined by the
|
|
|
|
|
[`meshtastic/protobufs`](https://github.com/meshtastic/protobufs) project. Update the
|
|
|
|
|
field declarations in `micromesh/messages.py` when adopting newer schemas.
|
|
|
|
|
|
|
|
|
|
`manifest.py` is also included for freezing the package into custom MicroPython firmware.
|