Edge Mesh is a throwaway proof-of-concept / learning experiment built on top of the Greengrass reference implementation. It is not a supported or maintained deliverable and may be removed. The reference implementation itself is long-lived; Edge Mesh is not.
Edge Mesh Architecture
The mesh is three stacked layers (radio → batman-adv → IP) that each depend on the one below, brought up by three ordered systemd units. The core and the Pis are both mesh nodes at that level but play different roles above it (Greengrass core vs. client device). Read this if: you want the conceptual map of how the mesh is built and how the software on top is arranged. Before this: skim the Overview.
This page is the conceptual map of how the mesh is built and how the software on top of it is arranged. For the authoritative, code-adjacent version, see tools/mesh/ARCHITECTURE.md in the iot-edge repo. It carries the full glossary and the deep rationale.
The three-layer model
The mesh is built in three stacked layers. Each layer only works if the one below it is already up. That ordering is important to understand, and it is why there are three separate systemd units (see the boot chain below).
- L1, the radio. A WiFi interface is taken out of normal "managed" mode and put into IBSS (Independent Basic Service Set) mode. This makes it peer-to-peer with no access point. It is then joined to a named cell every node shares. Every node must use identical SSID / channel / BSSID or it lands on a different cell and sees no one. That radio must be an
ath9k_htcUSB dongle (see Hardware & RF). - L2, batman-adv. The mesh-routing protocol, running as a Linux kernel module. It takes the raw radio and exposes a virtual interface,
bat0. Behindbat0, batman floods small "originator" beacons (OGMs) so every node learns a route to every other node, measures each link's quality (TQ, 0-255), and forwards frames multi-hop. You never configure a per-route table: that is the whole point of a mesh protocol. - L3, IP. Once
bat0exists, it gets a static address in the mesh subnet:mesh-node-N→10.88.0.(N+2), and the core at the reserved10.88.0.1. From here up it is ordinary IP: youping 10.88.0.3and the frame ridesbat0, batman routes it, it arrives.bat0is the interface you ping; the rawwlanXis plumbing you mostly forget about. - App layer (core only). The health portal runs on the core (itself just another mesh node) and shells out to
batctllocally to read what the mesh looks like from the core's vantage point, then serves it locally at/mesh.
Core and Pi roles
The core and the Pis are both mesh nodes at L1 to L3, but they play very different roles above that.
| Role | Core (CompuLab iMX8, 10.88.0.1) | Pi mesh-node (10.88.0.2 … .6) |
|---|---|---|
| Greengrass role | Core (runs the Greengrass nucleus + components) | Client device (authenticates to the core's broker; not a Greengrass core) |
| Cellular uplink | Yes, the only path to AWS | No |
| Local MQTT | Runs the Moquette broker + Bridge (relays mesh topics ⇄ AWS IoT Core) | Connects to the core's Moquette broker at 10.88.0.1:8883 |
| BLE scanning | ble-scanner component (subprocess-per-scan, BlueZ 5.50 workaround) | pi/scanner.py (systemd service) |
| Publishing | asset-publisher Greengrass component | pi/publisher.py (systemd service) |
| Health / map | health-portal (reads batctl, draws the map) | pi/mesh_reporter.py reports its neighbor view to the portal (systemd service) |
| Software delivery | Greengrass cloud/local deployment | Imaging + tools/provision-pi.sh (not a Greengrass deployment) |
Each Pi maps to one IoT thing named by its MPBID (mesh-Pi MPBIDs begin with FFFC, e.g. FFFC000101). Because Greengrass Client Device Auth (CDA) ties the MQTT client id to the thing name, a Pi holds exactly one authenticated Moquette connection, shared by scanning and EdgeMesh relay.
The Pi boot chain
The three mesh layers map one-to-one onto three systemd units, rendered by tools/provision-pi.sh. They form an ordered chain because each layer depends on the one below it already being up:
All three are Type=oneshot with RemainAfterExit=yes: they do their setup once at boot and then "stay active" so systemd treats the layer as established. NetworkManager is told to ignore the mesh radio (a 99-mesh-unmanaged.conf drop-in) so it does not fight these units for control of the interface.
On a Pi, the client-device units stack on top of that chain:
pi-provision.service(oneshot):After/Requires=mesh-ip.service; obtains the operational cert on first boot, then is skipped once the cert exists.pi-publisher.service(simple,Restart=always):After/Requires=pi-provision.service; runs the scan-and-publish loop and hosts the EdgeMesh relay.pi-mesh-reporter.service(simple): reports batman neighbors to the core health portal.
How the portal reads the mesh: three topology sources
The map you see in the health portal is the mesh as the core sees it. health-portal's mesh.py can build the topology graph from three sources:
| Source | When | What it shows |
|---|---|---|
core-batctl | Live read of batctl o / batctl n + ip neigh from the core. | A core-rooted routing tree: only what the core can hear, with its best-route TQ and next hop to each node. Not full node-to-node adjacency. |
| node-reports | Each node (pi/mesh_reporter.py) POSTs what it hears to /mesh/node-report; read_topology merges those reports (within NODE_REPORT_TTL_S) into the core-batctl tree. | Enriched Pi-to-Pi adjacency: relay-link TQ and per-node neighbors the core can't see alone. |
fake | Dev / demo, when MESH_FIXTURE_DIR points at a committed graph.json. | A full pre-baked adjacency graph, so the UI can be exercised without hardware during development. |
Where the code lives
tools/mesh/ARCHITECTURE.md: the authoritative layered model, boot chain, and glossary.tools/mesh/README.md: Pi bring-up;tools/mesh/COMPULAB-IMX8.md: the core.tools/mesh/runbooks/core-mesh-bringup.md: bring the core up as10.88.0.1(module load, 3-unit chain, verify).pi/README.md: the Pi client-device modules and the three systemd units.shared/README.md: theedge_sharedlibrary map (payload,shadow/shadow_mqtt,ipc,provision,csr,ble,location,sessions).components/health-portal/README.md: the mesh map, placements, and the three topology sources.