文章目錄標題
ESP-MESH與ESP32和ESP8266:入門(painlessMesh庫)
了解如何使用ESP-MESH網路協議通過ESP32和ESP8266 NodeMCU板建立網狀網路。ESP-MESH允許多個設備(節點)在單個無線區域網下相互通信。ESP32和ESP8266板均支持該功能。在本指南中,我們將向您展示如何使用Arduino內核開始使用ESP-MESH。
本文涵蓋以下主題:
Arduino IDE
如果要使用Arduino IDE對 ESP32和ESP8266開發板進行編程,則應安裝ESP32或ESP8266插件。請遵循以下指南:
- 在Arduino IDE(Windows,Mac OS X和Linux)中安裝ESP32開發板
- 在Arduino IDE(Windows,Mac OS X,Linux)中安裝ESP8266開發板
介紹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庫
該painlessMesh庫使我們能夠在一個簡單的方法建立一個網狀網路與ESP8266或ESP32開發板。
painlessMesh是真正的自組織網路,這意味著不需要計劃、中央控制器或路由器。任何由1個或多個節點組成的系統都將自組織成功能齊全的網路。網路的最大大小受heap中可分配給子連接緩衝區的記憶體的限制(我們認為),所以確實真的很高。有關painlessMesh庫的更多信息。
安裝painlessMesh庫
您可以通過Arduino庫管理器安裝painlessMesh,轉到工具>管理程式庫,程式庫管理員打開。
搜索“ painlessmesh ”並安裝該庫。我們使用1.4.5版
該庫還需要依賴其他一些庫。應該會彈出一個新窗口,要求您安裝所有缺少的依賴庫。選擇“全部安裝”。
如果未顯示此窗口,則需要安裝以下依賴庫:
- ArduinoJson(來自bblanchon)
- 任務計劃程序
- ESPAsyncTCP(ESP8266)
- AsyncTCP(ESP32)
如果您使用的是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基本範例(廣播消息)
我們已經用四個板(兩個ESP32和兩個ESP8266)對這個範例進行了實驗。您可以增加或刪除開發板。該程式碼與ESP32和ESP8266開發板均兼容。
程式碼– painlessMesh庫基本範例
將以下程式碼複製到您的Arduino IDE(庫範例中的程式碼)。該程式碼與ESP32和ESP8266開發板均兼容。
/*
Terry Lee
完整說明請參閱 http://honeststore.com.tw/esp8266-esp-mesh/
*/
#include "painlessMesh.h"
#define MESH_PREFIX "whateverYouLike"
#define MESH_PASSWORD "somethingPASSWORD"
#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 node ";
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 ";
程式碼如何工作
首先使用include(包含) painlessMesh 程式庫。
#include "painlessMesh.h"
MESH詳細信息
然後,增加mesh詳細信息。這MESH_PREFIX指mesh的名稱。您可以將其改成任何您喜歡的。
#define MESH_PREFIX "whateverYouLike"
MESH_PASSWORD,顧名思義就是mesh密碼。您可以將其更改為任何您喜歡的。
#define MESH_PASSWORD "somethingpassword"
mesh中的所有節點應使用相同的 MESH_PREFIX 和 MESH_PASSWORD。
MESH_PORT指您要在其上執行mesh服務器的TCP端口。預設值為5555。
#define MESH_PORT 5555
Scheduler排程器
建議避免使用 delay()在mesh網路程式碼中。為了維護網格,需要在後台執行一些任務。使用delay() 會阻止這些任務的發生,並可能導致網格失去穩定性/崩潰。
相反地,建議使用 TaskScheduler 執行您在painlessMesh本身中使用的任務。
以下建立了一個新的 Scheduler排程器 叫 userScheduler。
Scheduler userScheduler; // to control your personal task
painlessMesh
建立 一個 painlessMesh 物件稱為 mesh 來處理網狀網路。
建立任務
建立一個名為 taskSendMessage 負責呼叫 sendMessage() 只要程序正在執行,就每秒執行一次。
Task taskSendMessage(TASK_SECOND * 1 , TASK_FOREVER, &sendMessage);
發送消息到網格(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));
}
該消息包含“Hi from node
1”內容,及開毃板的晶片ID。
String msg = "Hi from node 1";
msg += mesh.getNodeId();
廣播消息,很簡單地,只需使用mesh 物件上的方法 sendBroadcast(),並將您要發送消息(msg)作為參數傳遞。
mesh.sendBroadcast(msg);
每次發送新消息時,程式碼都會更改消息之間的間隔(一到五秒)。
taskSendMessage.setInterval(random(TASK_SECOND * 1, TASK_SECOND * 5));
Mesh Callback Functions
接下來,建立多個callback函數,當特定事件在網格上發生時將被調用。
receiveCallback() 函數印出消息發件人(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);
選擇所需的debug消息類型:
//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);
將所有回調函數分配給它們對應的事件。
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();
}
範例
將提供的程式碼上傳到所有開發板(ESP8266及ESP32)。不要忘記修改消息以輕鬆識別發送者節點
將開發板連接到電腦後,打開每個板的串列連接。您可以使用串列監視器,也可以使用類似PuTTY的軟件並為所有板打開多個窗口。
您應該看到所有板都收到彼此的消息。例如,下面這些是節點1收到的消息。它從節點2、3和4接收消息。
當網格上發生變改時,您還可以看到其他消息:開發板離開或加入網絡時。