If you want to get a Meshtastic-compatible library that works great in CircuitPython, of course there is no better place to start than the MeshFruit library!
Yet, there is another library in town, that might be a have some extra steps to install it, but because it has been written in Rust, and for CircuitPython, it bridges the two things we like the most: an efficient and fast full stack library with the ease of use of CircuitPython.
The way that it has been designed, you can connect to REPL and have the library already talking with the Meshtastic network, while you send messages or read your inbox using simple commands. But, if you power on the device and to manually take it to REPL, it will start running code.py acting as a Meshtastic client that you can connect with your phone via the official Meshtastic application, or you can interact with it over the network by using the official Meshtastic Python API.
So, you can use the REPL for simplicity, learning how to use the library, quick serial console or web-workflow testing, use the default code.py that comes with the library to connect your phone with the same app everyone else is using, and of course you can call the library from your own CircuitPython code to let your project start talking with the amazing Meshstastic network.
Compatible hardware
Since me, the author of the library, only has a handful of hardware that is both capable of running CircuitPython and that has a LoRa radio, so far the list of hardware is a bit limited to a couple of new and shiny boards that Meshstastic enthusiasts are gravitating to, because of very useful features. With the library released, now I will work on adding support for Adafruit hardware, and later for popular Meshtastic hardware. So far, we got:
- Muzi Works' Base Duo: nRF52840 with LR1121 radio. Cool features: 915MHz + 2.4GHz LoRa, BLE, integrated solar charger.
- Meshnology W12: ESP32-S3R8 (same S3 we know and love, but with 8M of PSRAM!) with LR2021 radio. Cool features: 915MHz + 2.4GHz LoRa, FLRC! (more on this, below), WiFi, multi-net navigation device, OLED screen, comes with case, a very decent 915MHz antenna and battery.
Note: This boards are not official CircuitPython supported hardware, yet. I'm working on it, but we found an external issue that Adafruit is trying to solve.
Integrated devices
- The latest generation of LoRa radios from Semtech: LR1121 and LR2021.
- A navigation device (GNSS or "GPS")
- An OLED screen
How to install
Any device
- Use a CircuitPython build that has
CIRCUITPY_ENABLE_MPY_NATIVEenabled. This might require a manual rebuild, but it's required for Rust support. - Copy the
mpyfiles for the radio used in your board to theCIRCUITPY/libon your board. Current support is for: LR1121 and LR2021 - Copy the
mpyfiles from the cpy-meshtastic library to theCIRCUITPY/libon your board. Note: Since Rust is compiled, in a similar way to Turbo, you need to use the mpy files compiled for your board's arch. - Copy the
code.py,repl.py, andsettings.tomlto the root ofCIRCUITPYon your board. Editsettings.tomlto configure the LoRa region, client short and long name, as well as any board specific features like WiFi connection, OLED, navigation device, and to enable how you want to connect to the Phone app.
This is a short example of a settings.toml file:
MESH_RADIO = "lr2021"
MESH_GPS = "gps"
MESH_PHONE = "tcp"
CIRCUITPY_WIFI_SSID = "your access point"
CIRCUITPY_WIFI_PASSWORD = "4d4fru1t-ru13z"
Board specific install
Meshtastic folks are used to flashing from a web browser, and using a single file to install the firmware.
Look for the UF2 file that includes both CircuitPython, the radio, and the cpy-meshtastic library, for either the Muzi Works Base Duo, or the Meshnology W12.
Notes:
- For the Base Duo board, embedding the library in the UF2 is needed anyway, to save memory.
- The W12 board is so new that they don't have UF2 support yet. Install TinyUF2 on it, first.
Usage
REPL
If you copied the repl.py file to the root of your CIRCUITPY folder on your board, use CTRL+C as usual to enter the REPL. The power of having repl.py on your board, means that all of the init that has to happen to use cpy-meshtastic is already happening there; so the board is already listening to incomming packets from the Meshtastic network, and if you want to send a message, just ahead and do it. This is an example of what you will see:
Press any key to enter the REPL. Use CTRL-D to reload.
repl.py output:
LR1121 fw 1.1, hw 0x22
# meshtastic node, firmware v2.7.26.54e0d8d
# US/LongFast ch 20/104 @ 906.8750 MHz SF11 BW250.00kHz CR4/5
# node 0x0b9dbde1 relay 0xe1 channel 0x08, key from nvm
# +22 dBm, duty cycle 0.00% of 100% over 3600s
# keystore: node_num=4 bytes, channel_key=16 bytes, channel_name=0 bytes, region=2 bytes, preset=8 bytes, channel_num=4 bytes, tx_power_dbm=4 bytes, duty_cycle_pct=4 bytes, nodeinfo_s=4 bytes, long_name=13 bytes, short_name=4 bytes
# cache: 32 nodes, 25 messages restored
# read() peek() unread() channels() nodes() listen(30)
# send("text") introduce() poll() status() save() stop()
# ask(num) ask(num, "environment") node() release()
# phone() serve()
# settings() configure(region="EU_868")
Adafruit CircuitPython 10.3.1-rust on 2026-09-14; muzi works Base Duo with nRF52840
>>> nodes()
# 32 nodes heard
# number short hops pkts snr last long
# 0xb2a73a5c 3h 117 10.5 56s
# 0xaca9f8e8 1h 549 10.5 1m
# 0xe277a008 4h 1 10.5 2m
(...)
>>> send("Hi from Costa Rica, using cpy-meshtastic")
# learned 0xcXXXXX is Long-Name (short-name), hw 101
1 (id=0xAAAA fr=0xBBBBB to=0xffffffff, WantAck=0, HopLim=2 Ch=0x8 Portnum=4 rxSNR=10.25 rxRSSI=-65 signalRSSI=-65 hopStart=7 relay=0xbd)
node=Hopp port=nodeinfo bytes=73
# clock set from 0xCCCCCC: 2026-09-25T17:31:49Z UTC
2 17:31:49 (id=0xDDDDD fr=EEEEEE to=0xffffffff, WantAck=0, HopLim=1 Ch=0x8 Portnum=67 rxSNR=10.5 rxRSSI=-52 signalRSSI=-52 hopStart=3 relay=0xbd)
node=0xGGGGGG port=telemetry bytes=22
code.py with Phone app
Install the Meshtastic phone app, power the CircuitPython device (remember to configure settings.toml), and in the settings of the phone app scan for either bluetooth or network devices, depending on the capabilities of the board you are using and it's configuration, and connect to that device.
The list of nodes, configuration, channels and other settings will be shared from the phone app to the CircuitPython device, and now you can use the phone app as you would if you had the original Meshtastic firmware on your LoRa device.
It's optional, but if you decide to open up a serial console to the device while running in code.py "mode", it sill show something like this:
Connected to /dev/tty.usbmodem441B67EA618F1
# code.py: last reset POWER_ON
# code.py: bringing the node up, Ctrl-C stops it here
# no GNSS module 'gps'; the clock will come from elsewhere
LR2021 fw 1.24
# meshtastic node, firmware v2.7.26.54e0d8d
# US/LongFast ch 20/104 @ 906.8750 MHz SF11 BW250.00kHz CR4/5
# node 0x0f61ea67 relay 0x67 channel 0x08, key from nvm
# +22 dBm, duty cycle 0.00% of 100% over 3600s
# keystore: node_num=4 bytes, channel_key=16 bytes, region=2 bytes
# cache: 24 nodes, 32 messages restored
# no interrupt support in this firmware, use listen()
# (cannot watch that pin: no port support, already in use, or no slot left)
# code.py: announcing, which keys the sub-GHz amplifier
# nodeinfo: Meshtastic ea67 (ea67), asking for replies
# sending 59 bytes, 681 ms on air
SENT (id=0x4cba0c09 fr=0x0f61ea67 to=0xffffffff, WantAck=0, HopLim=3 Ch=0x8 Portnum=4 WANTRESP hopStart=3 relay=0x67)
# phone: tcp starting, 8165120 bytes free
# phone: tcp on 192.168.123.123:4403 (meshtastic-0f61ea67.local), 8140624 bytes free
# code.py: node up, panel running -- Ctrl-C for the prompt
# phone: 192.168.123.123:4403 (meshtastic-0f61ea67.local) connected from 192.168.123.123
# phone: 12 bytes in, 1 queued, at 0.0s
# phone: 8 bytes in, 32 queued, at 0.2s
# clock set from the phone: 2026-09-25T17:54:29Z UTC
And if you keep looking you should see one printed line for every message that is received or sent on the Meshtastic network.
In this screenshot, you can see a connected device, which is shown as a full-compatible to a device that would be using the original Meshtastic firmware!
While using the Meshtastic phone app, of course you can use all of the features like text messages to/from on private and public channels, information on the nodes, run and receive traceroutes.
And something very cool, this is how the map for the Meshtastic network looks here in Costa Rica. With help from the Radio Club and enthusiasts, the network as been growing to almost 60 devices including routers, repeaters and of course many clients.
Features
We just talked about using the REPL for simplicity, the lib's code.py for connecting your phone, or using the library to write your own applications that talk with the Meshtastic network. But, what can you do?
- Full Meshtastic-compatible client support: it handles lot's of types of messages like receiving "node-info" (when a radio says the station name, what hardware is it running, etc), text messages in public and private channels, telemetry (battery charge, weather conditions if the board has sensor for it), and even position when you have a navigation device (so that you can find your friend, and your friend can find you!), and traceroute messages (so that you can map the Meshtastic network itself! Are we talking directly or is there one or many routers in between us?)
- Airtime: Transmitting is something that has to happen with care, you can only send so much information via Meshtastic over a period of time. The airtime module has a counter that checks all of the messages (automated or manual) that your radio sends, and if needed will limit you so that you don't go over the limits that any user of the Meshtastic network's agrees to.
- Radio interrupts: Even if not fully embraced by the library yet, it should be very easy to get Low-Power capabilities. CircuitPython already has some very cool Low-Power modes, and you can have the radios wake up blinka when there is an incomming packet, and then to go back to sleep to save battery, and maybe make it compatible with Solar power, which makes it the perfect hardware for deploying in the field as a remote station.
- NVM: Non-volatile memory is a very nice CircuitPython features, that allows the board to remember some information about the nodes and messages received, so that even if you reboot the board, you will still have nodes and messages available, for example for using the
REPLmode. - Discovery: You can discover devices if using the
code.pymode for connecting to the Meshtastic phone app. Depending on your hardware you can discover both Bluetooth devices and/or Network devices, in this case using mDNS.
What we don't do (yet?)
- Other roles different to client: No router, no store-and-forward, or any of the other cool and interesting modes of participation that you can have in a Meshtastic network. Just client.
- Limited hardware support: I'll be slowly but shurely adding more devices in time. This library is quite new!
- "stock" CircuitPython: The rust support in CircuitPython is also very new, I even added it because I wanted to write this library in Rust!. So for now you probably need a CircuitPython build that has
CIRCUITPY_ENABLE_MPY_NATIVEenabled. We will talk a bit more about this, later in this guide. I am also talking with the CircuitPython devs so Rust might be integrated and embraced. Can you imagine? A rusty blinka?<3.
More testing needed:
- Even if the supported radios have 2.4GHz antennas and capabilities, and there is a Meshtastic "region" for 2.4GHz, the library should handle those, but we haven't really tested them
- An FLRC side channel: "FLRC" is so now, that today there are no Youtube videos showing folks using FLRC, but it's one of the reasons why I got modern Semtech radios (only LR2021 has FLRC). Using FLRC is not part of Meshtastic, but it's a feature that would allow you to send files over large distances. The way I think of it, is like having old-times WiFi speeds, but over distances that are similar to LoRa. So we could coordinate with a device using a private channel, so that for a very short period we both disconnect from Meshtastic, transfer over a file using FLRC and then get back to Meshtastic.
- iPhone app: I've only tested the Android app. I'm guessing it should be the same. Also, why do we have different app? Are you also thinking of a Rust por using Tauri? Wow, you read my mind!
Disclaimer
Do not ask for support to Meshstatic or it's community if you see any errors or incompatibility with the Meshstastic Phone app. They only support using it with their firmware.
This library is very new and should not be considered as stable. Meshtastic has lots of uses for rescue, emergency communication, outdoor sports communication, etc. We do not recommend using this library for any of those uses.
This page (Meshtastic-compatible full stack (in 🦀) for CircuitPython) was last updated on September 25, 2026.
Text editor powered by tinymce.