了解如何使用ESP-MESH网络协议通过ESP32和ESP8266 NodeMCU板构建网状网络。 ESP-MESH允许多个设备(节点)在单个无线局域网下相互通信。 ESP32和ESP8266板均支持该功能。 在本指南中,我们将向您展示如何使用Arduino内核开始使用ESP-MESH。
本文涵盖以下主题:
介绍ESP-MESH
ESP-MESH基本示例(广播消息)
使用ESP-MESH交换传感器读数(广播)
根据Espressif文档:
“ ESP-MESH是建立在Wi-Fi协议之上的网络协议。 ESP-MESH允许散布在较大物理区域(室内和室外)中的众多设备(称为节点)在单个WLAN(无线局域网)下互连。
ESP-MESH具有自我组织和自我修复的功能,这意味着该网络可以自动构建和维护。” 有关更多信息,请访问ESP-MESH官方文档。
传统的Wi-Fi网络架构
在传统的Wi-Fi网络体系结构中,单个节点(访问点–通常为路由器)连接到所有其他节点(站)。 每个节点都可以使用访问点相互通信。 但是,这仅限于接入点的Wi-Fi覆盖范围。 每个站点必须在范围内才能直接连接到接入点。 ESP-MESH不会发生这种情况。
ESP-MESH网络架构
使用ESP-MESH,节点无需连接到中央节点。 节点负责彼此中继传输。 这允许多个设备分布在较大的物理区域上。 节点可以自组织并彼此动态对话,以确保数据包到达其最终节点目的地。 如果从网络中删除了任何节点,则它可以自我组织以确保数据包到达其目的地。
painlessMesh库使我们能够以简单的方式使用ESP8266或/和ESP32板创建网状网络。
“ painlessMesh是真正的自组织网络,这意味着不需要计划,中央控制器或路由器。 任何包含1个或多个节点的系统都将自组织成功能齐全的网格。 网格的最大大小受堆中可分配给子连接缓冲区的内存量的限制(我们认为),因此应该确实很高。 有关painlessMesh库的更多信息。
您可以通过Arduino库管理器安装painlessMesh。 转到工具>管理库。 图书馆管理器应打开。
搜索“ painlessmesh”并安装该库。 我们正在使用1.4.5版
该库还需要其他一些库依赖项。 应该会弹出一个新窗口,要求您安装所有缺少的依赖项。 选择“全部安装”。
如果未显示此窗口,则需要安装以下库依赖项:
ArduinoJson(来自bblanchon)
任务计划程序
ESPAsyncTCP(ESP8266)
AsyncTCP(ESP32)
如果您使用的是PlatformIO,则将以下行添加到platformio.ini文件中,以添加库并更改监视器速度。
For the ESP32:
monitor_speed = 115200 lib_deps = painlessmesh/painlessMesh @ ^1.4.5
ArduinoJson
arduinoUnity
TaskScheduler
AsyncTCP
For the ESP8266:
monitor_speed = 115200 lib_deps = painlessmesh/painlessMesh @ ^1.4.5
ArduinoJson
TaskScheduler
ESPAsyncTCP
要开始使用ESP-MESH,我们首先尝试使用该库的基本示例。 本示例创建一个网状网络,其中所有板均向所有其他板广播消息。
我们以四个板(两个ESP32和两个ESP8266)为例进行了实验。 您可以添加或删除板。 该代码与ESP32和ESP8266板均兼容。
代码– painlessMesh库基本示例
将以下代码复制到您的Arduino IDE(库示例中的代码)。 该代码与ESP32和ESP8266板均兼容。
/*
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_PREFIX引用网格的名称。 您可以将其更改为任何您喜欢的。
#define MESH_PREFIX “whateverYouLike”
顾名思义,MESH_PASSWORD是MESH密码。 您可以将其更改为任何您喜欢的。
#define MESH_PASSWORD “somethingSneaky”
网格中的所有节点应使用相同的MESH_PREFIX和MESH_PASSWORD。
MESH_PORT指您要在其上运行网格服务器的TCP端口。 默认值为5555。
#define MESH_PORT 5555
Scheduler
建议避免在网状网络代码中使用delay()。 为了维护网格,需要在后台执行一些任务。 使用delay()将阻止这些任务的发生,并可能导致网格失去稳定性/崩溃。
相反,建议使用TaskScheduler运行在painlessMesh本身中使用的任务。
下面的行创建了一个名为userScheduler的新Scheduler。
painlessMesh
创建一个名为mesh的painlessMesh对象,以处理网格网络。
Create tasks
创建一个名为taskSendMessage的任务,该任务负责在程序运行时每秒调用一次sendMessage()函数。
Task taskSendMessage(TASK_SECOND * 1 , TASK_FOREVER, &sendMessage);
Send a Message to the Mesh sendMessage()函数将消息发送到消息网络(广播)中的所有节点。
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();
要广播消息,只需在网格对象上使用sendBroadcast()方法,然后将要发送的消息(msg)作为参数传递。
mesh.sendBroadcast(msg);
每次发送新消息时,代码都会更改消息之间的间隔(一到五秒)。
taskSendMessage.setInterval(random(TASK_SECOND * 1, TASK_SECOND * 5));
Mesh Callback Functions
接下来,创建多个回调函数,当特定事件在网格上发生时将被调用。
receiveCallback()函数打印消息发件人(来自)和消息内容(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()
选择所需的调试消息类型:
//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);
最后,将taskSendMessage函数添加到userScheduler。 调度程序负责在正确的时间处理和运行任务。
userScheduler.addTask(taskSendMessage);
最后,启用taskSendMessage,以便程序开始将消息发送到网格。
taskSendMessage.enable();
为了使网格保持运行,将mesh.update()添加到loop()中。
void loop() {
// it will run the user scheduler as well
mesh.update();
}
将提供的代码上传到所有主板。 不要忘记修改邮件以轻松识别发件人节点
将板连接到计算机后,打开每个板的串行连接。 您可以使用串行监视器,也可以使用类似PuTTY的软件并为所有板打开多个窗口。
您应该看到所有板都收到彼此的消息。 例如,这些是节点1收到的消息。它从节点2、3和4接收消息。
当网格上发生更改时,您还应该看到其他消息:板子离开或加入网络时。
使用ESP-MESH交换传感器读数
在下一个示例中,我们将在4个板之间交换传感器读数(您可以使用不同数量的板)。 每个板都接收其他板的读数。
例如,我们将交换来自BME280传感器的传感器读数,但是您可以使用任何其他传感器。