A GTK-based native desktop application for interacting with MeshCore radios on Raspberry Pi. Supports all hardware that openhop-core supports, including the HackerGadgets AIO (uConsole), Waveshare LoRa HATs, and meshadv-mini boards. Built-in hardware presets let you switch between boards without manually configuring every pin.
Inspired by YAMPA, and built on top of the great openhop-core library.
You can run a Mock version of the application on anything that supports Nix, and then you can run the real application on the uConsole either by cloning the repo and following the below instructions, or installing from the APT repository.
Packages are built for Bookworm (Debian 12 / Raspberry Pi OS) and Trixie (Debian 13). Check your version with lsb_release -cs.
# Add signing key
curl -fsSL https://cwill747.github.io/meshcore-uconsole/KEY.gpg \
| sudo gpg --dearmor -o /usr/share/keyrings/meshcore.gpg
# Add repository — replace DISTRO with bookworm or trixie
echo "deb [signed-by=/usr/share/keyrings/meshcore.gpg arch=arm64] \
https://cwill747.github.io/meshcore-uconsole DISTRO main" \
| sudo tee /etc/apt/sources.list.d/meshcore.list
# Install
sudo apt update && sudo apt install meshcore-uconsoleFuture updates are available via sudo apt update && sudo apt upgrade.
Download the .deb for your distro from Releases and install:
# Bookworm (Debian 12)
sudo apt install ./meshcore-uconsole_*~bookworm_arm64.deb
# Trixie (Debian 13)
sudo apt install ./meshcore-uconsole_*~trixie_arm64.deb| Analyzer | Peers |
|---|---|
![]() |
![]() |
| Channels | Map |
|---|---|
![]() |
![]() |
| Platform | Requirements |
|---|---|
| macOS | Nix package manager |
| Raspberry Pi | Python 3.11+, uv |
Why --system-site-packages? PyGObject cannot be installed via pip on most platforms. It must come from system packages (Raspberry Pi) or Nix (macOS). The --system-site-packages flag allows the virtual environment to access these system-installed packages.
- Create and sync the local Python environment:
nix develop --command sh -lc 'uv venv --python "$(which python)" --system-site-packages'
nix develop --command uv sync- Run the app in mock mode:
./scripts/run-dev.sh- Run smoke checks:
uv run pytestNote: run-dev.sh always enables mock mode (MESHCORE_MOCK=1) since macOS has no radio hardware.
- On the Pi, run base bootstrap and reboot:
./scripts/bootstrap-pi.sh
sudo reboot- Create/sync the local Python environment:
uv venv --python python3 --system-site-packages
uv sync- Validate host + hardware:
uv run meshcore-console doctor- Start listening for mesh events:
uv run meshcore-console listen- Send a message:
uv run meshcore-console send --peer "<contact-name>" --message "hello"- Launch GTK UI on Pi:
./scripts/run-gtk-pi.shUse mock mode on Pi if desired:
MESHCORE_MOCK=1 ./scripts/run-gtk-pi.sh| Command | Description |
|---|---|
meshcore-console doctor |
Validate SPI/GPIO configuration and radio hardware connectivity |
meshcore-console listen |
Listen for mesh packets and print decoded events to stdout |
meshcore-console send |
Send a direct message to a named peer |
If doctor fails on SPI/GPIO, confirm these before retrying:
/boot/firmware/config.txtcontainsdtoverlay=spi1-1cs(enables SPI1 for the radio)- You rebooted after adding the overlay
Warning: Do not run
sudo raspi-config nonint do_spi 0— this enables SPI0 (dtparam=spi=on), not SPI1, and on CM5 + Trixie it can disable the uConsole internal display. If this has happened, removedtparam=spi=onfrom/boot/firmware/config.txtvia SSH and reboot.
Hardware overrides can be supplied via env vars when running meshcore-console
or the GTK app. An env var wins over the value saved in Settings > Hardware, so
a saved setting that stops the radio from starting stays recoverable from the
command line. Notable radio bring-up flags:
MESHCORE_USE_DIO2_RF=1(default in this repo)MESHCORE_USE_DIO3_TCXO=1(default in this repo)MESHCORE_GPIO_CHIP=15— which/dev/gpiochipNcarries the 40-pin header. It is 0 on CM4, but 15 on CM5 and Pi 5 kernels, where the header hangs off the RP1.doctorlists the chips your host actually has.MESHCORE_EN_PINS=27— GPIO pins driven HIGH at init to power the radio. The HackerGadgets AIOv2 enable pin is 27; the uConsole HG AIOv2 board preset sets this for you.MESHCORE_USE_GPIOD_BACKEND=1— poll for IRQ edges instead of asking the kernel for edge interrupts. Try this if the radio connects but receives nothing, which happens on kernels that reject the edge request.



