ESP-MESH與ESP32和ESP8266:入門

了解如何使用ESP-MESH網路協議通過ESP32和ESP8266 NodeMCU板建立網狀網路。ESP-MESH允許多個設備(節點)在單個無線區域網下相互通信。ESP32和ESP8266板均支持該功能。在本指南中,我們將向您展示如何使用Arduino內核開始使用ESP-MESH。

本文涵蓋以下主題:

Arduino IDE

如果要使用Arduino IDE對 ESP32和ESP8266開發板進行編程,則應安裝ESP32或ESP8266插件。請遵循以下指南:

介紹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 ESP8266i

painlessMesh庫

painlessMesh庫使我們能夠在一個簡單的方法建立一個網狀網路與ESP8266或ESP32開發板。

painlessMesh是真正的自組織網路,這意味著不需要計劃、中央控制器或路由器。任何由1個或多個節點組成的系統都將自組織成功能齊全的網路。網路的最大大小受heap中可分配給子連接緩衝區的記憶體的限制(我們認為),所以確實真的很高。有關painlessMesh庫的更多信息

安裝painlessMesh庫

您可以通過Arduino庫管理器安裝painlessMesh,轉到工具>管理程式庫,程式庫管理員打開。

搜索“ painlessmesh ”並安裝該庫。我們使用1.4.5版

該庫還需要依賴其他一些庫。應該會彈出一個新窗口,要求您安裝所有缺少的依賴庫。選擇“全部安裝”。

安裝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前,我們先嘗試該庫的基本範例。本範例建立一個網狀網路,其中所有開發板均向所有其他開發板廣播消息。

我們已經用四個板(兩個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 node1”內容,及開毃板的晶片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接收消息。

當網格上發生變改時,您還可以看到其他消息:開發板離開或加入網絡時。

發佈留言