star twitter facebook envelope linkedin youtube alert-red alert home left-quote chevron hamburger minus plus search triangle x

ESP-MESH with ESP32 and ESP8266


Learn how to use ESP-MESH networking protocol to build a mesh network with the ESP32 and ESP8266 NodeMCU boards. ESP-MESH allows multiple devices (nodes) to communicate with each other under a single wireless local area network. It is supported on the ESP32 and ESP8266 boards. In this guide, we’ll show you how to get started with ESP-MESH using the Arduino core.

ESP-MESH with ESP32 and ESP8266: Getting Started

Introducing ESP-MESH

Accordingly to the Espressif documentation:

“ESP-MESH is a networking protocol built atop the Wi-Fi protocol. ESP-MESH allows numerous devices (referred to as nodes) spread over a large physical area (both indoors and outdoors) to be interconnected under a single WLAN (Wireless Local-Area Network).

ESP-MESH is self-organizing and self-healing meaning the network can be built and maintained autonomously.” For more information, visit the ESP-MESH official documentation.

Traditional Wi-Fi Network Architecture

In a traditional Wi-Fi network architecture, a single node (access point – usually the router) is connected to all other nodes (stations). Each node can communicate with each other using the access point. However, this is limited to the access point wi-fi coverage. Every station must be in the range to connect directly to the access point. This doesn’t happen with ESP-MESH.

Traditional Wi-Fi Network ESP32 ESP8266

ESP-MESH Network Architecture

With ESP-MESH, the nodes don’t need to connect to a central node. Nodes are responsible for relaying each others transmissions. This allows multiple devices to spread over a large physical area. The Nodes can self-organize and dynamically talk to each other to ensure that the packet reaches its final node destination. If any node is removed from the network, it is able to self-organize to make sure that the packets reach their destination.

ESP-MESH Network ESP32 ESP8266i

 

painlessMesh Library

The painlessMesh library allows us to create a mesh network with the ESP8266 or/and ESP32 boards in an easy way.

“painlessMesh is a true ad-hoc network, meaning that no-planning, central controller, or router is required. Any system of 1 or more nodes will self-organize into fully functional mesh. The maximum size of the mesh is limited (we think) by the amount of memory in the heap that can be allocated to the sub-connections buffer and so should be really quite high.” More information about the painlessMesh library.

Installing painlessMesh Library

You can install painlessMesh through the Arduino Library manager. Go to Tools > Manage Libraries. The Library Manager should open.

Search for “painlessmesh” and install the library. We’re using Version 1.4.5

Install painlessMesh library Arduino IDE

This library needs some other library dependencies. A new window should pop up asking you to install any missing dependencies. Select “Install all”.

Install painlessmesh library dependencies Arduino IDE

If this window doesn’t show up, you’ll need to install the following library dependencies:

If you’re using PlatformIO, add the following lines to the platformio.ini file to add the libraries and change the monitor speed.

ESP-MESH Basic Example (Broadcast messages)

To get started with ESP-MESH, we’ll first experiment with the library’s basic example. This example creates a mesh network in which all boards broadcast messages to all the other boards.

We’ve experimented this example with four boards (two ESP32 and two ESP8266). You can add or remove boards. The code is compatible with both the ESP32 and ESP8266 boards.

ESP-MESH painlessMesh basic example ESP32 ESP8266

Code – painlessMesh Library Basic Example

Copy the following code to your Arduino IDE (code from the library examples). The code is compatible with both the ESP32 and ESP8266 boards.

CODE:

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp-mesh-esp32-esp8266-painlessmesh/
  
  This is a simple example that uses the painlessMesh library: https://github.com/gmag11/painlessMesh/blob/master/examples/basic/basic.ino
*/

 

#include "painlessMesh.h"

#define   MESH_PREFIX     "whateverYouLike"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555

Scheduler userScheduler; // to control your personal task
painlessMesh  mesh;

// User stub
void sendMessage() ; // Prototype so PlatformIO doesn't complain

Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );

void sendMessage() {
  String msg = "Hi from node1";
  msg += mesh.getNodeId();
  mesh.sendBroadcast( msg );
  taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 5 ));
}

// Needed for painless library
void receivedCallback( uint32_t from, String &msg ) {
  Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str());
}

void newConnectionCallback(uint32_t nodeId) {
    Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
}

void changedConnectionCallback() {
  Serial.printf("Changed connections\n");
}

void nodeTimeAdjustedCallback(int32_t offset) {
    Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset);
}

void setup() {
  Serial.begin(115200);

//mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on
  mesh.setDebugMsgTypes( ERROR | STARTUP );  // set before init() so that you can see startup messages

  mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
  mesh.onReceive(&receivedCallback);
  mesh.onNewConnection(&newConnectionCallback);
  mesh.onChangedConnections(&changedConnectionCallback);
  mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);

  userScheduler.addTask( taskSendMessage );
  taskSendMessage.enable();
}

void loop() {
  // it will run the user scheduler as well
  mesh.update();
}

 

 

Before uploading the code, you can set up the MESH_PREFIX (it’s like the name of the MESH network) and the MESH_PASSWORD variables (you can set it to whatever you like).

Then, we recommend that you change the following line for each board to easily identify the node that sent the message. For example, for node 1, change the message as follows:

String msg = "Hi from node 1 ";

How the Code Works

Start by including the painlessMesh library.

#include "painlessMesh.h"

MESH Details

Then, add the mesh details. The MESH_PREFIX refers to the name of the mesh. You can change it to whatever you like.

#define MESH_PREFIX "whateverYouLike"

The MESH_PASSWORD, as the name suggests is the mesh password. You can change it to whatever you like.

#define MESH_PASSWORD "somethingSneaky"

All nodes in the mesh should use the same MESH_PREFIX and MESH_PASSWORD.

The MESH_PORT refers to the the TCP port that you want the mesh server to run on. The default is 5555.

Scheduler

It is recommended to avoid using delay() in the mesh network code. To maintain the mesh, some tasks need to be performed in the background. Using delay() will stop these tasks from happening and can cause the mesh to lose stability/fall apart.

Instead, it is recommended to use TaskScheduler to run your tasks which is used in painlessMesh itself.

The following line creates a new Scheduler called userScheduler.

Scheduler userScheduler; // to control your personal task

painlessMesh

Create a painlessMesh object called mesh to handle the mesh network.

Create tasks

Create a task called taskSendMessage responsible for calling the sendMessage() function every second as long as the program is running.

Task taskSendMessage(TASK_SECOND * 1 , TASK_FOREVER, &sendMessage);

Send a Message to the Mesh

The sendMessage() function sends a message to all nodes in the message network (broadcast).

 

void sendMessage() {

String msg = "Hi from node 1";

msg += mesh.getNodeId();

mesh.sendBroadcast( msg );

taskSendMessage.setInterval(random(TASK_SECOND * 1, TASK_SECOND * 5)); }

The message contains the “Hi from node 1” text followed by the board chip ID.

String msg = "Hi from node 1";
msg += mesh.getNodeId();

To broadcast a message, simply use the sendBroadcast() method on the mesh object and pass as argument the message (msg) you want to send.

mesh.sendBroadcast(msg);

Every time a new message is sent, the code changes the interval between messages (one to five seconds).

taskSendMessage.setInterval(random(TASK_SECOND * 1, TASK_SECOND * 5));

Mesh Callback Functions

Next, several callback functions are created that will be called when specific events happen on the mesh.

The receivedCallback() function prints the message sender (from) and the content of the message (msg.c_str()).

void receivedCallback( uint32_t from, String &msg ) {
  Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str());
}

The newConnectionCallback() function runs whenever a new node joins the network. This function simply prints the chip ID of the new node. You can modify the function to do any other task.

void newConnectionCallback(uint32_t nodeId) {
  Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
}

The changedConnectionCallback() function runs whenever a connection changes on the network (when a node joins or leaves the network).

void changedConnectionCallback() {
  Serial.printf("Changed connections\n");
}

The nodeTimeAdjustedCallback() function runs when the network adjusts the time, so that all nodes are synchronized. It prints the offset.

void nodeTimeAdjustedCallback(int32_t offset) {
  Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset);
}

setup()

In the setup(), initialize the serial monitor.

void setup() {
  Serial.begin(115200);

Choose the desired debug message types:

//mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on

mesh.setDebugMsgTypes( ERROR | STARTUP );  // set before init() so that you can see startup messages

Initialize the mesh with the details defined earlier.

Exchange Sensor Readings using ESP-MESH

In this next example, we’ll exchange sensor readings between 4 boards (you can use a different number of boards). Every board receives the other boards’ readings.

ESP-MESH Exchange BME280 Sensor Readings ESP32 ESP8266

As an example, we’ll exchange sensor readings from a BME280 sensor, but you can use any other sensor.

Parts Required

Here’s the parts required for this example:

Arduino_JSON library

In this example, we’ll exchange the sensor readings in JSON format. To make it easier to handle JSON variables, we’ll use the Arduino_JSON library.

You can install this library in the Arduino IDE Library Manager. Just go to Sketch Include Library > Manage Libraries and search for the library name as follows:

Install Arduino JSON library Arduino IDE

If you’re using VS Code with PlatformIO, include the libraries in the platformio.ini file as follows:

ESP32

Giải thích

monitor_speed = 115200
lib_deps = painlessmesh/painlessMesh @ ^1.4.5
    ArduinoJson
    arduinoUnity
    AsyncTCP
    TaskScheduler
    adafruit/Adafruit Unified Sensor @ ^1.1.4
    adafruit/Adafruit BME280 Library @ ^2.1.2
    arduino-libraries/Arduino_JSON @ ^0.1.0

ESP8266

Giải thích

monitor_speed = 115200
lib_deps = painlessmesh/painlessMesh @ ^1.4.5
    ArduinoJson
    TaskScheduler
    ESPAsyncTCP
    adafruit/Adafruit Unified Sensor @ ^1.1.4
    adafruit/Adafruit BME280 Library @ ^2.1.2
    arduino-libraries/Arduino_JSON @ ^0.1.0

Circuit Diagram

Wire the BME280 sensor to the ESP32 or ESP8266 default I2C pins as shown in the following schematic diagrams.

ESP32

ESP32 BME280 Sensor Temperature Humidity Pressure Wiring Diagram Circuit

https://randomnerdtutorials.com/esp-mesh-esp32-esp8266-painlessmesh/