Zero-touch provisioning and imaging for OpenMANET mesh nodes.
Public product repositories:
EasyMANET is a local CLI and Electron desktop app that lets you define an entire OpenMANET mesh fleet in a single YAML config file, flash SD cards from that file, and boot Raspberry Pi nodes directly into a working mesh without touching the node-local web UI.
- A replacement for OpenMANET or OpenWrt
- A new MANET protocol
- A cloud dashboard
- A cloud management service
- A Meshtastic integration
- A drone UI
EasyMANET is a provisioning, imaging, and configuration layer on top of OpenMANET. Use OpenMANET as the base firmware.
OpenMANET requires booting each node, connecting to the node, opening the web UI, and running a setup wizard. For a multi-node field deployment, this is tedious and error-prone. EasyMANET removes that workflow entirely.
- Host: macOS and Linux (the laptop you flash from)
- Node: Raspberry Pi 4
- Radio: MM6108 SPI (OpenMANET rpi4 + mm6108-spi target)
- Single target:
rpi4-mm6108-spionly - Local CLI and Electron desktop workflows only
- No remote management
- No monitoring dashboard
- No incremental config updates (flash to reconfigure)
The installed CLI creates a shared workspace under
~/Documents/EasyMANET/. Fleet files live in
~/Documents/EasyMANET/Fleets/, and the Electron app reads the same folder.
easymanet init
easymanet fleetsSet EASYMANET_WORKSPACE=/path/to/EasyMANET if you need a different local
workspace.
Create ~/Documents/EasyMANET/Fleets/fleet.yml:
version: 1
mesh:
id: my-mesh
password: "strong-mesh-password"
channel: 42
bandwidth_mhz: 2
country: US
defaults:
target: rpi4-mm6108-spi
local_ap:
enabled: true
password: "ap-password"
management:
root_password_hash: ""
ssh_authorized_keys:
- "ssh-ed25519 AAAAC3..."
gateway:
wifi:
enabled: false
ssid: "operator-wifi"
password: "operator-wifi-password"
encryption: psk2
nodes:
gate01:
role: gate
hostname: gate01
ip: 10.41.1.1
local_ap:
enabled: false
gateway:
uplink_interface: wifi
wifi:
enabled: true
point01:
role: point
hostname: point01
ip: 10.41.2.1
local_ap:
ssid: point01-localThe checked-in starter fleet is
examples/three-node-field-mesh.yml.
See docs/sample-fleet.md for the copy command and a
smaller two-node example. EasyMANET does not create a fleet file automatically.
For a gate, uplink_interface: wifi joins the configured operator LAN.
uplink_interface: eth0 runs WAN DHCP directly on eth0 and keeps that port
out of the mesh bridge. Manage an Ethernet-uplink gate through the mesh, its
local AP, or another node. Treat any WAN-reachable management/API service as
trusted-LAN only.
easymanet diskseasymanet validate --config fleet
easymanet validate --config fleet --node point01easymanet flash \
--config fleet \
--node point01 \
--device /dev/disk4 \
--base-image ./openmanet-rpi4-mm6108-spi.img.gz \
--dry-runeasymanet image buildBy default this uses Docker, builds OpenMANET 1.6.5 for
rpi4-mm6108-spi, and copies the resulting image into ./dist/.
Local builds use a persistent Docker volume for the OpenMANET build cache.
CI can pass --cache-dir .openmanet-cache so GitHub Actions can cache the
same expensive OpenWrt download, host, and toolchain directories.
easymanet flash \
--config fleet \
--node point01 \
--device /dev/disk4 \
--base-image ./dist/openmanet-1.6.5-rpi4-mm6108-spi-squashfs-sysupgrade.img.gz \
--image-sha256 <sha256> \
--yesInsert the SD card into the Raspberry Pi and power it on. The node applies EasyMANET provisioning on first boot, restarts networking, and stays up. Give it at least 90–120 seconds for networking and mesh services to settle.
- Never auto-selects a disk. You must always provide
--device. --yesis required to flash. Use--dry-runto preview first.easymanet diskslists removable, USB, and MMC/SD-like devices on Linux; macOS shows external drives. Useeasymanet disks --allto list every block device.- Blocking checks refuse to flash system disks, large internal drives,
suspiciously large devices, and devices not in the default list unless
you pass
--force. - Partial failure recovery: if boot payload staging fails after the
image write, re-run the full
easymanet flashcommand. - Unmounts partitions before writing.
- Downloaded images require HTTPS and SHA-256 verification. Local
--base-imagefiles are allowed; pass--image-sha256to verify them before flashing. - Syncs writes and ejects after completion.
- SSH at flash time: use
--enable-sshor--disable-sshoneasymanet flash(gate nodes default to SSH on; point nodes default to off). See docs/flashing.md. - Boot-partition secrets:
provision.jsonon the FAT boot volume contains fleet secrets in cleartext until successful first boot, whenprovision.shremoves the boot copy. The overlay copy at/etc/easymanet/provision.json(mode0600) remains. Treat flashed media as sensitive until the node has provisioned. The marker means required activation commands accepted; it does not prove Wi-Fi association, WAN reachability, or physical mesh connectivity. See docs/flashing.md.
Set EASYMANET_SKIP_UPDATE_CHECK=1 to skip the optional GitHub release check
on flash and image build.
- Flash
gate01to one SD card. - Flash
point01to another SD card. - Boot both Raspberry Pis.
- Wait at least 90–120 seconds after first-boot provisioning.
- SSH into either node and verify mesh connectivity:
ssh root@10.41.1.1 ip addr show bat0 batctl n ping 10.41.2.1
| Command | Description |
|---|---|
easymanet init |
Create/show the shared ~/Documents/EasyMANET workspace |
easymanet fleets |
List fleet YAML files in the shared workspace |
easymanet disks |
List flashable disks (--all for every block device) |
easymanet validate --config FILE |
Validate fleet config |
easymanet validate --config FILE --node NAME |
Validate specific node |
easymanet render --config FILE --node NAME |
Print resolved provision.json |
easymanet image build |
Build an EasyMANET-flavored OpenMANET image with Docker |
easymanet image manifest --image IMG |
Write image release metadata with checksum and provenance |
easymanet flash --config FILE --node NAME --device DEV --base-image IMG --yes |
Flash and provision |
easymanet flash ... --dry-run |
Preview flash without writing |
easymanet diagnostics bundle |
Export a redacted support bundle ZIP |
npm --prefix apps/desktop/electron start |
Run the local Electron operator console |
easymanet-desktop serve |
Run the browser-served fallback console |
easymanet-publish export |
Generate local public product surfaces without setting up subrepos |
Run these from the repo root before handing off a change:
python tools/verify.py fast
python tools/verify.py openwrt-sim
python tools/verify.py package
python tools/verify.py artifactfast runs the normal local gate: Python tests, OpenWrt overlay shell syntax,
Electron shell check, overlay packaging, and git diff --check. Set
EASYMANET_VERIFY_PYTHON=/path/to/venv/bin/python when you want the Python
checks and Electron bridge smoke to use a specific development venv.
openwrt-sim runs the targeted shell-harnessed provisioning, first-boot, API,
and status tests. Use it for overlay, provisioning, status, topology, or
management-LAN changes.
package installs Electron dependencies with npm ci, then builds and smokes
the installed wheel through tools/release_smoke.py, including the installed
wheel Electron smoke. It uses clean temporary virtual environments with fresh
build tooling so it does not depend on a host Python with setuptools already
available.
artifact runs non-hardware image and release checks. Without arguments it
checks source overlay packaging, required files, executable modes, a synthetic
boot payload fixture, and read-only image-cache state. For built images, pass
--artifact and --release-manifest to the same profile.
hil delegates to the manual hardware-in-the-loop runner:
python tools/verify.py hil --config ... --gate-node ... --point-node ....
Use it for release, flashing, radio, or real image validation, not routine
application-only changes.
Documents/EasyMANET/Fleets/fleet.yml → validate → render → boot-partition provision.json → first boot → mesh
See docs/architecture.md for the full data flow.
- Documentation Index
- Architecture
- Monorepo Layout
- Historical Product and Release Planning
- Release Checklist
- Sample Fleet
- Manifest Reference — every config field documented
- Flashing Guide
- Public Product Repositories
- OpenMANET Config Investigation
- Design Decisions — durable choices and trade-offs (template)
- Problems — active blocker notes and an archive of resolved findings (template)
pip install -e ".[dev]"
pytestThe repo is split into shared core, CLI, image, Electron desktop, and publish/export source roots. See docs/monorepo.md for the ownership map.
Before cutting a release, run the installed-wheel smoke and the checklist in docs/release.md.
Pull requests run the CI workflow (unit tests, overlay shell syntax, and
packaging checks). Full OpenMANET firmware images are built via the
Build OpenMANET Image workflow (manual) or the weekly Prove Overlay Weekly
workflow on main. Docker-based easymanet image build on Apple Silicon uses
linux/amd64 emulation and is slower than on native x86_64 hosts.
Generated public product repositories are produced with
tools/packaging/publish_product_repos.py; see docs/public-repos.md.
- An empty
root_password_hashleaves the root password unchanged on the node. - On a gate,
gateway.uplink_interface: eth0is the WAN DHCP interface and is not available for mesh-side management. - Wi-Fi uplink (
gateway.wifi.enabled) can expose SSH on WAN when SSH is enabled. - Gate topology API exposure on WAN (port 10411) is default-off and must stay
limited to trusted uplinks when
--enable-wan-apiis used. - When
/etc/openmanetd/config.ymlexists, first-boot writes mesh credentials into that file in plaintext (OpenMANET daemon requirement; verify on hardware).
The first-boot scripts target standard OpenMANET UCI paths. Some UCI paths and service names may need adjustment based on the specific OpenMANET build. See docs/openmanet-config-investigation.md for a record of known paths and gaps.
The following need verification against a configured OpenMANET node:
- Exact wireless radio type string for MM6108 SPI
- Mesh identification field name (
mesh_idvsssid) - Encryption type (
saevspsk2) - OpenMANET daemon service name (
openmanetd) - Any additional UCI config files