ESP-MESH с ESP32 и ESP8266: начало работы (библиотека painlessMesh)

Узнайте, как использовать сетевой протокол ESP-MESH для создания mesh-сети с платами ESP32 и ESP8266 NodeMCU. ESP-MESH позволяет нескольким устройствам (узлам) взаимодействовать друг с другом в рамках единой беспроводной локальной сети. Он поддерживается на платах ESP32 и ESP8266. В этом руководстве мы покажем, как начать работу с ESP-MESH, используя ядро Arduino.

ESP-MESH с ESP32 и ESP8266: начало работы

Эта статья охватывает следующие темы:

Arduino IDE

Если вы хотите программировать платы ESP32 и ESP8266 с помощью Arduino IDE, у вас должны быть установлены дополнения для ESP32 или ESP8266. Следуйте следующим руководствам:

Если вы хотите программировать ESP32/ESP8266 с помощью VS Code + PlatformIO, следуйте следующему руководству:

Знакомство с ESP-MESH

Согласно документации Espressif:

«ESP-MESH — это сетевой протокол, построенный поверх протокола Wi-Fi. ESP-MESH позволяет множеству устройств (называемых узлами), распределённых по большой физической территории (как в помещении, так и на улице), быть объединёнными в единую беспроводную локальную сеть (WLAN).

ESP-MESH является самоорганизующимся и самовосстанавливающимся, что означает, что сеть может строиться и поддерживаться автономно.» Для получения дополнительной информации посетите официальную документацию ESP-MESH.

Традиционная архитектура Wi-Fi сети

В традиционной архитектуре Wi-Fi сети один узел (точка доступа — обычно маршрутизатор) подключён ко всем остальным узлам (станциям). Каждый узел может взаимодействовать друг с другом через точку доступа. Однако это ограничено зоной покрытия Wi-Fi точки доступа. Каждая станция должна находиться в зоне действия для прямого подключения к точке доступа. С ESP-MESH такого ограничения нет.

Традиционная Wi-Fi сеть ESP32 ESP8266

Архитектура сети ESP-MESH

С ESP-MESH узлам не нужно подключаться к центральному узлу. Узлы отвечают за ретрансляцию передач друг друга. Это позволяет множеству устройств распределяться по большой физической территории. Узлы могут самоорганизовываться и динамически взаимодействовать друг с другом, чтобы гарантировать доставку пакета до конечного узла назначения. Если какой-либо узел удаляется из сети, она способна самоорганизоваться для обеспечения доставки пакетов к месту назначения.

Сеть ESP-MESH ESP32 ESP8266

Библиотека painlessMesh

Библиотека painlessMesh позволяет легко создать mesh-сеть с платами ESP8266 и/или ESP32.

«painlessMesh — это настоящая ad-hoc сеть, что означает, что не требуется никакого планирования, центрального контроллера или маршрутизатора. Любая система из 1 или более узлов самоорганизуется в полностью функциональную mesh-сеть. Максимальный размер сети ограничен (как мы полагаем) объёмом памяти в куче, который может быть выделен для буфера подключений, и поэтому должен быть весьма большим.» Подробнее о библиотеке painlessMesh.

Установка библиотеки painlessMesh

Вы можете установить painlessMesh через менеджер библиотек Arduino. Перейдите в Tools > Manage Libraries. Должен открыться менеджер библиотек.

Найдите «painlessmesh» и установите библиотеку. Мы используем версию 1.4.5.

Установка библиотеки painlessMesh в Arduino IDE

Эта библиотека нуждается в некоторых дополнительных зависимостях. Должно появиться новое окно с предложением установить недостающие зависимости. Выберите «Install all».

Установка зависимостей библиотеки painlessMesh в Arduino IDE

Если это окно не появится, вам нужно установить следующие зависимости вручную:

Если вы используете PlatformIO, добавьте следующие строки в файл platformio.ini для подключения библиотек и изменения скорости монитора.

Для ESP32:

monitor_speed = 115200
lib_deps = painlessmesh/painlessMesh @ ^1.4.5
    ArduinoJson
    arduinoUnity
    TaskScheduler
    AsyncTCP

Для ESP8266:

monitor_speed = 115200
lib_deps = painlessmesh/painlessMesh @ ^1.4.5
    ArduinoJson
    TaskScheduler
    ESPAsyncTCP

Базовый пример ESP-MESH (широковещательные сообщения)

Для начала работы с ESP-MESH сначала поэкспериментируем с базовым примером библиотеки. Этот пример создаёт mesh-сеть, в которой все платы рассылают сообщения всем остальным платам.

Мы проверили этот пример на четырёх платах (два ESP32 и два ESP8266). Вы можете добавить или убрать платы. Код совместим как с платами ESP32, так и с ESP8266.

Базовый пример ESP-MESH painlessMesh ESP32 ESP8266

Код – базовый пример библиотеки painlessMesh

Скопируйте следующий код в вашу Arduino IDE (код из примеров библиотеки). Код совместим как с платами ESP32, так и с ESP8266.

Если вы используете ESP32, вам необходимо понизить версию дополнения для плат ESP32 до версии 2.0.X. На данный момент библиотека painlessMesh несовместима с версией 3.X.

/*
  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();
}

Просмотреть исходный код

Перед загрузкой кода вы можете настроить переменные MESH_PREFIX (это как имя MESH-сети) и MESH_PASSWORD (можете установить любое значение).

Затем мы рекомендуем изменить следующую строку для каждой платы, чтобы легко идентифицировать узел, отправивший сообщение. Например, для узла 1 измените сообщение следующим образом:

String msg = "Hi from node 1 ";

Как работает код

Начните с подключения библиотеки painlessMesh.

#include "painlessMesh.h"

Настройки MESH

Затем добавьте настройки mesh-сети. MESH_PREFIX относится к имени mesh-сети. Вы можете изменить его на любое удобное.

#define MESH_PREFIX "whateverYouLike"

MESH_PASSWORD, как следует из названия, — это пароль mesh-сети. Вы можете изменить его на любое удобное.

#define MESH_PASSWORD "somethingSneaky"

Все узлы в mesh-сети должны использовать одинаковые MESH_PREFIX и MESH_PASSWORD.

MESH_PORT относится к TCP-порту, на котором вы хотите запустить mesh-сервер. По умолчанию — 5555.

#define MESH_PORT 5555

Планировщик (Scheduler)

Рекомендуется избегать использования delay() в коде mesh-сети. Для поддержания mesh некоторые задачи должны выполняться в фоновом режиме. Использование delay() остановит выполнение этих задач и может привести к потере стабильности или распаду mesh-сети.

Вместо этого рекомендуется использовать TaskScheduler для запуска ваших задач, который также используется в самой библиотеке painlessMesh.

Следующая строка создаёт новый планировщик с именем userScheduler.

Scheduler userScheduler; // to control your personal task

painlessMesh

Создайте объект painlessMesh с именем mesh для управления mesh-сетью.

Создание задач

Создайте задачу taskSendMessage, отвечающую за вызов функции sendMessage() каждую секунду на протяжении всего времени работы программы.

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

Отправка сообщения в mesh-сеть

Функция sendMessage() отправляет сообщение всем узлам в mesh-сети (широковещательная рассылка).

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

Сообщение содержит текст «Hi from node 1», за которым следует ID чипа платы.

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

Для широковещательной отправки сообщения просто используйте метод sendBroadcast() объекта mesh и передайте в качестве аргумента сообщение (msg), которое хотите отправить.

mesh.sendBroadcast(msg);

При каждой отправке нового сообщения код изменяет интервал между сообщениями (от одной до пяти секунд).

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

Callback-функции mesh-сети

Далее создаётся несколько callback-функций, которые будут вызываться при возникновении определённых событий в mesh-сети.

Функция receivedCallback() выводит отправителя сообщения (from) и содержание сообщения (msg.c_str()).

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

Функция newConnectionCallback() выполняется каждый раз, когда новый узел присоединяется к сети. Эта функция просто выводит ID чипа нового узла. Вы можете модифицировать функцию для выполнения любой другой задачи.

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

Функция changedConnectionCallback() выполняется каждый раз, когда соединение в сети изменяется (когда узел присоединяется к сети или покидает её).

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

Функция nodeTimeAdjustedCallback() выполняется, когда сеть корректирует время для синхронизации всех узлов. Она выводит смещение.

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

setup()

В setup() инициализируйте монитор последовательного порта.

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 с ранее определёнными настройками.

mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);

Назначьте все callback-функции соответствующим событиям.

mesh.onReceive(&receivedCallback);
mesh.onNewConnection(&newConnectionCallback);
mesh.onChangedConnections(&changedConnectionCallback);
mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);

Наконец, добавьте функцию taskSendMessage в userScheduler. Планировщик отвечает за управление и запуск задач в нужное время.

userScheduler.addTask(taskSendMessage);

Далее включите taskSendMessage, чтобы программа начала отправлять сообщения в mesh-сеть.

taskSendMessage.enable();

Для поддержания работы mesh-сети добавьте mesh.update() в loop().

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

Демонстрация

Загрузите приведённый код на все ваши платы. Не забудьте изменить сообщение для лёгкой идентификации узла-отправителя.

Подключив платы к компьютеру, откройте последовательное соединение с каждой платой. Вы можете использовать Serial Monitor или программу типа PuTTY и открыть несколько окон для всех плат.

Вы должны увидеть, что все платы получают сообщения друг от друга. Например, вот сообщения, полученные Узлом 1. Он получает сообщения от Узла 2, 3 и 4.

Базовый пример ESP-MESH для 4 плат, Arduino Serial Monitor

Вы также должны увидеть другие сообщения при изменениях в mesh-сети: когда плата покидает сеть или присоединяется к ней.

Базовый пример ESP-MESH Serial Monitor, изменённые соединения

Обмен показаниями датчиков через ESP-MESH

В следующем примере мы будем обмениваться показаниями датчиков между 4 платами (вы можете использовать другое количество плат). Каждая плата получает показания от остальных плат.

ESP-MESH обмен показаниями датчика BME280 ESP32 ESP8266

В качестве примера мы будем обмениваться показаниями датчика BME280, но вы можете использовать любой другой датчик.

Необходимые компоненты

Вот компоненты, необходимые для этого примера:

Библиотека Arduino_JSON

В этом примере мы будем обмениваться показаниями датчиков в формате JSON. Для упрощения работы с JSON-переменными мы будем использовать библиотеку Arduino_JSON.

Вы можете установить эту библиотеку через менеджер библиотек Arduino IDE. Просто перейдите в Sketch > Include Library > Manage Libraries и найдите библиотеку по имени:

Установка библиотеки Arduino JSON в Arduino IDE

Если вы используете VS Code с PlatformIO, включите библиотеки в файл platformio.ini следующим образом:

ESP32

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

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

Схема подключения

Подключите датчик BME280 к стандартным пинам I2C ESP32 или ESP8266, как показано на следующих схемах.

ESP32

Схема подключения ESP32 с датчиком BME280 (температура, влажность, давление)

Рекомендуемое чтение: ESP32 с BME280 с использованием Arduino IDE (давление, температура, влажность)

ESP8266 NodeMCU

Схема подключения ESP8266 NodeMCU с датчиком BME280 (температура, влажность, давление)

Рекомендуемое чтение: ESP8266 с BME280 с использованием Arduino IDE (давление, температура, влажность)

Код – ESP-MESH широковещательная передача показаний датчиков

Загрузите следующий код на каждую из ваших плат. Этот код считывает и транслирует текущие показания температуры, влажности и давления всем платам в mesh-сети. Показания отправляются в виде JSON-строки, которая также содержит номер узла для идентификации платы-отправителя.

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp-mesh-esp32-esp8266-painlessmesh/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include "painlessMesh.h"
#include <Arduino_JSON.h>

// MESH Details
#define   MESH_PREFIX     "RNTMESH" //name for your MESH
#define   MESH_PASSWORD   "MESHpassword" //password for your MESH
#define   MESH_PORT       5555 //default port

//BME object on the default I2C pins
Adafruit_BME280 bme;

//Number for this node
int nodeNumber = 2;

//String to send to other nodes with sensor readings
String readings;

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

// User stub
void sendMessage() ; // Prototype so PlatformIO doesn't complain
String getReadings(); // Prototype for sending sensor readings

//Create tasks: to send messages and get readings;
Task taskSendMessage(TASK_SECOND * 5 , TASK_FOREVER, &sendMessage);

String getReadings () {
  JSONVar jsonReadings;
  jsonReadings["node"] = nodeNumber;
  jsonReadings["temp"] = bme.readTemperature();
  jsonReadings["hum"] = bme.readHumidity();
  jsonReadings["pres"] = bme.readPressure()/100.0F;
  readings = JSON.stringify(jsonReadings);
  return readings;
}

void sendMessage () {
  String msg = getReadings();
  mesh.sendBroadcast(msg);
}

//Init BME280
void initBME(){
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
}

// Needed for painless library
void receivedCallback( uint32_t from, String &msg ) {
  Serial.printf("Received from %u msg=%s\n", from, msg.c_str());
  JSONVar myObject = JSON.parse(msg.c_str());
  int node = myObject["node"];
  double temp = myObject["temp"];
  double hum = myObject["hum"];
  double pres = myObject["pres"];
  Serial.print("Node: ");
  Serial.println(node);
  Serial.print("Temperature: ");
  Serial.print(temp);
  Serial.println(" C");
  Serial.print("Humidity: ");
  Serial.print(hum);
  Serial.println(" %");
  Serial.print("Pressure: ");
  Serial.print(pres);
  Serial.println(" hpa");
}

void newConnectionCallback(uint32_t nodeId) {
  Serial.printf("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);

  initBME();

  //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();
}

Просмотреть исходный код

Код совместим как с платами ESP32, так и с ESP8266.

Как работает код

Продолжайте чтение этого раздела, чтобы узнать, как работает код.

Библиотеки

Начните с подключения необходимых библиотек: Adafruit_Sensor и Adafruit_BME280 для работы с датчиком BME280; библиотека painlessMesh для управления mesh-сетью и Arduino_JSON для простого создания и обработки JSON-строк.

#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include "painlessMesh.h"
#include <Arduino_JSON.h>

Настройки mesh-сети

Укажите настройки mesh-сети в следующих строках.

#define MESH_PREFIX    "RNTMESH" //name for your MESH
#define MESH_PASSWORD  "MESHpassword" //password for your MESH
#define MESH_PORT      5555 //default port

MESH_PREFIX относится к имени mesh-сети. Вы можете изменить его на любое удобное. MESH_PASSWORD, как следует из названия, — это пароль mesh-сети. Вы можете изменить его на любое удобное. Все узлы в mesh-сети должны использовать одинаковые MESH_PREFIX и MESH_PASSWORD.

MESH_PORT относится к TCP-порту, на котором вы хотите запустить mesh-сервер. По умолчанию — 5555.

BME280

Создайте объект Adafruit_BME280 с именем bme на стандартных пинах ESP32 или ESP8266.

Adafruit_BME280 bme;

В переменную nodeNumber внесите номер узла для вашей платы. Для каждой платы должен быть свой уникальный номер.

int nodeNumber = 2;

Переменная readings будет использоваться для сохранения показаний, отправляемых другим платам.

String readings;

Планировщик (Scheduler)

Следующая строка создаёт новый планировщик с именем userScheduler.

Scheduler userScheduler; // to control your personal task

painlessMesh

Создайте объект painlessMesh с именем mesh для управления mesh-сетью.

Создание задач

Создайте задачу taskSendMessage, отвечающую за вызов функции sendMessage() каждые пять секунд на протяжении всего времени работы программы.

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

getReadings()

Функция getReadings() получает показания температуры, влажности и давления от датчика BME280 и объединяет всю информацию, включая номер узла, в JSON-переменную jsonReadings.

JSONVar jsonReadings;
jsonReadings["node"] = nodeNumber;
jsonReadings["temp"] = bme.readTemperature();
jsonReadings["hum"] = bme.readHumidity();
jsonReadings["pres"] = bme.readPressure()/100.0F;

Следующая строка показывает структуру переменной jsonReadings с произвольными значениями.

{
  "node":2,
  "temperature":24.51,
  "humidity":52.01,
  "pressure":1005.21
}

Переменная jsonReadings затем преобразуется в JSON-строку с помощью метода stringify() и сохраняется в переменной readings.

readings = JSON.stringify(jsonReadings);

Эта переменная затем возвращается функцией.

return readings;

Отправка сообщения в mesh-сеть

Функция sendMessage() отправляет JSON-строку с показаниями и номером узла (getReadings()) всем узлам сети (широковещательная рассылка).

void sendMessage () {
  String msg = getReadings();
  mesh.sendBroadcast(msg);
}

Инициализация датчика BME280

Функция initBME() инициализирует датчик BME280.

void initBME(){
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
}

Callback-функции mesh-сети

Далее создаётся несколько callback-функций, которые будут вызываться при возникновении определённых событий в mesh-сети.

Функция receivedCallback() выводит отправителя сообщения (from) и содержание сообщения (msg.c_str()).

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

Сообщение приходит в формате JSON, поэтому мы можем получить доступ к переменным следующим образом:

JSONVar myObject = JSON.parse(msg.c_str());
int node = myObject["node"];
double temp = myObject["temp"];
double hum = myObject["hum"];
double pres = myObject["pres"];

Наконец, выведите всю информацию в Serial Monitor.

Serial.print("Node: ");
Serial.println(node);
Serial.print("Temperature: ");
Serial.print(temp);
Serial.println(" C");
Serial.print("Humidity: ");
Serial.print(hum);
Serial.println(" %");
Serial.print("Pressure: ");
Serial.print(pres);
Serial.println(" hpa");

Функция newConnectionCallback() выполняется каждый раз, когда новый узел присоединяется к сети. Эта функция просто выводит ID чипа нового узла. Вы можете модифицировать функцию для выполнения любой другой задачи.

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

Функция changedConnectionCallback() выполняется каждый раз, когда соединение в сети изменяется (когда узел присоединяется к сети или покидает её).

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

Функция nodeTimeAdjustedCallback() выполняется, когда сеть корректирует время для синхронизации всех узлов. Она выводит смещение.

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

setup()

В setup() инициализируйте монитор последовательного порта.

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

Вызовите функцию initBME() для инициализации датчика BME280.

initBME();

Выберите нужные типы отладочных сообщений:

//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 с ранее определёнными настройками.

mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);

Назначьте все callback-функции соответствующим событиям.

mesh.onReceive(&receivedCallback);
mesh.onNewConnection(&newConnectionCallback);
mesh.onChangedConnections(&changedConnectionCallback);
mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);

Наконец, добавьте функцию taskSendMessage в userScheduler. Планировщик отвечает за управление и запуск задач в нужное время.

userScheduler.addTask(taskSendMessage);

Далее включите taskSendMessage, чтобы программа начала отправлять сообщения в mesh-сеть.

taskSendMessage.enable();

Для поддержания работы mesh-сети добавьте mesh.update() в loop().

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

Демонстрация

После загрузки кода на все ваши платы (каждая плата с отдельным номером узла), вы должны увидеть, что каждая плата получает сообщения от остальных плат.

На следующем снимке экрана показаны сообщения, полученные узлом 1. Он получает показания датчиков от узлов 2, 3 и 4.

ESP-MESH обмен показаниями датчика BME280 ESP32 ESP8266 Serial Monitor

Заключение

Мы надеемся, что вам понравилось это краткое введение в сетевой протокол ESP-MESH. Вы можете ознакомиться с библиотекой painlessMesh для получения дополнительных примеров.

Вам также могут быть интересны следующие статьи:

Узнайте больше об ESP32 и ESP8266 с нашими ресурсами:

Спасибо за чтение.


Источник: ESP-MESH with ESP32 and ESP8266: Getting Started (painlessMesh library)