ESP-WIFI-MESH
Nodes that relay for each other, so the far end of the shed reaches the router through the one in the middle. It costs latency, throughput and complexity — here is when that trade is worth making.
What "self-healing" actually is
It is a sequence, not a property. A parent stops answering, its children notice after a few missed beacons, they scan for anything already in the mesh, and they re-attach wherever they can hear. Nobody configures it and no code of yours runs.
The cost is in the last frame: the node that lost its parent is now further from the root, so its messages cross more links. Self-healing keeps the network up; it does not keep it fast.
Two different things are called mesh here
ESP-WIFI-MESH is Espressif's own, in ESP-IDF. It has a root node that holds the connection to your router, so the mesh has a way out to the internet, and it manages the tree properly.
painlessMesh is the Arduino library everybody actually starts with. It builds a standalone network with no router in it at all. That makes it trivial to set up and means nothing reaches the internet until you write a bridge node that runs both the mesh and a normal Wi-Fi connection.
Knowing which one an example is using explains most of the confusion in mesh forum threads.
Before you build one
Ask whether you need a mesh or just more range. Three honest alternatives:
- A second access point. Cheap, boring, and it makes every board a plain station with no library at all.
- ESP-NOW. No router, no association, about two milliseconds per message, and a one-hop relay is ten lines. Most "mesh" projects are this.
- LoRa. If the far end is a paddock away rather than a room away, kilometres at a few hundred bytes a minute beats any number of Wi-Fi hops.
A mesh earns its complexity when there are many nodes, the layout is not known in advance, and nodes come and go. For six sensors in a house it is usually the harder path to the same result.
The code
painlessMesh is the approachable way in. Every node runs the same sketch and the tree forms itself — there is no root to configure and no addresses to assign.
#include <painlessMesh.h>
#define PREFIX "tinkerblock-mesh"
#define PASS "meshpassword"
#define PORT 5555
Scheduler scheduler;
painlessMesh mesh;
void sendReading() {
mesh.sendBroadcast("21.4 from " + String(mesh.getNodeId()));
}
Task tReport(TASK_SECOND * 5, TASK_FOREVER, &sendReading);
void setup() {
Serial.begin(115200);
mesh.setDebugMsgTypes(ERROR | CONNECTION);
mesh.init(PREFIX, PASS, &scheduler, PORT);
mesh.onReceive([](uint32_t from, String &msg) {
Serial.printf("%u: %s\n", from, msg.c_str());
});
mesh.onChangedConnections([]() {
Serial.printf("topology changed, %d nodes\n", mesh.getNodeList().size() + 1);
});
scheduler.addTask(tReport);
tReport.enable();
}
void loop() {
mesh.update();
}painlessMesh builds its own network with no router in it, which is the difference from Espressif's ESP-WIFI-MESH. Nothing here reaches the internet unless you add a bridge node.
There is no mesh library for MicroPython. ESP-NOW is the nearest thing that exists, and for two hops you can relay by hand — which is worth doing before you reach for a real mesh.
import network, espnow
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
e = espnow.ESPNow()
e.active(True)
GATEWAY = b'\xaa\xbb\xcc\xdd\xee\xff' # the node nearest the router
e.add_peer(GATEWAY)
# A relay: anything heard from a leaf is forwarded one hop towards the gateway.
while True:
host, msg = e.recv()
if msg and host != GATEWAY:
e.send(GATEWAY, msg)This is a one-hop relay, not a mesh: no self-healing, no routing table, no automatic parent selection. If that is enough for your building, it is also enormously easier to debug.
When it does not work
The prefix, password and port must be identical on every node, and the password must be at least eight characters. A node with a different port joins the same Wi-Fi and lands in a separate mesh that looks identical from the outside.
Mesh nodes need to hear each other, not the router. Two nodes at opposite ends with nothing in between do not form a link no matter how good the router is. Walk the path and place a node where the signal is still workable.
Every hop is a full Wi-Fi transmission, and the tree gets deeper as it spreads. Three hops is already several hundred milliseconds. If the data is a reading every minute this is irrelevant; if it is a light switch, it is not.
A node re-joining forces its children to re-parent, which ripples. Find why it resets — brown-out during a transmit burst is the usual answer — before blaming the mesh library.
The standardised version of this idea, on a different radio, with a phone app that already exists and did not need writing.
Zigbee, Thread and Matter →Edit this page — content/esp32/esp-wifi-mesh.mdx
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.