網狀網路(Mesh Network)在wiki上有了很詳細的介紹,其特點可以簡單描述為:
對於esp8266來說,網狀網路的意義是什麼呢?官方有個簡單的介紹:
隨著物聯網的發展,物聯網節點規模迅速擴張,但路由器可供直接接入的節點數有限(通常少於 32 個)。針對此問題,樂鑫開發了 ESP-MESH 協議。在 Mesh 網路中,節點之間可以組成網路並轉發數據包。這樣不需要改變路由即可實現大量節點連接到網路。
在網狀網路中,每個節點都是一個AP(AccessPopint),可以被其他節點連接,也可以連接一個其他的節點;ESP8266單個節點最多支持4個連接,ESP32可以支持到10個。
1、既然這麼厲害,來看看示例代碼的效果
ESP8266示例: HelloMesh
#include <ESP8266WiFi.h> #include <ESP8266WiFiMesh.h>
unsigned int request_i = 0; unsigned int response_i = 0;
String manageRequest(String request);
/* Create the mesh node object */ ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(ESP.getChipId(), manageRequest);
/** * Callback for when other nodes send you data * * @request The string received from another node in the mesh * @returns The string to send back to the other node */ String manageRequest(String request) { /* Print out received message */ Serial.print("received: "); Serial.println(request);
/* return a string to send back */ char response[60]; sprintf(response, "Hello world response #%d from Mesh_Node%d.", response_i++, ESP.getChipId()); return response; }
void setup() { Serial.begin(115200); delay(10);
Serial.println(); Serial.println(); Serial.println("Setting up mesh node...");
/* Initialise the mesh node */ mesh_node.begin(); }
void loop() { /* Accept any incoming connections */ mesh_node.acceptRequest();
/* Scan for other nodes and send them a message */ char request[60]; sprintf(request, "Hello world request #%d from Mesh_Node%d.", request_i++, ESP.getChipId()); mesh_node.attemptScan(request); delay(1000); }
把上面的示例分別寫入兩臺ESP8266設備,打開串口監視器可以看到設備先是各自設置好mesh網路,然後嘗試連接,連接上了之後分別列印出"Hello world request #1 from Mesh_Node 12312312.",這樣就已經成功建立了一個Mesh網路並相互通信了。
2、在這個基礎上進行修改,實現從在A發出控制信息到B,B接收後做出相應的控制響應
#define LED_PIN = D2 // 定義LED燈輸出引腳 #define SW_PIN = D0 // 定義開關控制輸入引腳
String manageRequest(String request); ESP8266WiFiMesh mesh_node = ESP8266WiFiMesh(ESP.getChipId(), manageRequest);
String manageRequest(String request) { Serial.print("received: "); Serial.println(request);
char response[60]; sprintf(response, "Hello world response #%d from Mesh_Node%d.", response_i++, ESP.getChipId()); if (request == "ON") { // 收到的消息是"ON" digitalWrite(LED_PIN, HIGH); // 打開LED delay(500); // 延遲500毫秒 } digitalWrite(LED_PIN, LOW); // 關閉LED return response; }
pinMode(LED_PIN, OUTPUT); pinMode(SW_PIN, INPUT);
mesh_node.begin(); }
void loop() { mesh_node.acceptRequest();
int ledStatus = digitalRead(SW_PIN); // 讀取開關的狀態 if (ledStatus == 1) { char request[2]; sprintf(request, "ON"); mesh_node.attemptScan(request); // 發送打開LED燈的消息:"ON" } else { char request[60]; sprintf(request, "Hello world request #%d from Mesh_Node%d.", request_i++, ESP.getChipId()); mesh_node.attemptScan(request); } delay(1000); }
上述程序分別寫入到兩個ESP8266設備(設備A/設別B);設備A的D0上連接一個控制開關,設備B的D2上連接一個輸入LED燈。成功建立連接後,在A上打開開關(digitalRead(SW_PIN) == 1),發送打開的消息給B,B成功收到後打開D2的led燈。
如果把開關常開的話,B設備表現為間隔若干秒後LED燈打開。預期應該是每次打開LED燈的間隔都是一樣的了;基於這個情況,記錄了連續十次LED打開的時間間隔(手動計時,誤差±1s):
可以看到#1和#9的時間是明顯大於其他的。出現這樣的情況主要有以下兩個原因:
3、藉助painlessMesh實現控制LED燈
painlessMesh(gitlab / github)是一個包,用來創建一個基於ESP8266/ESP32的簡單網狀網路。
The goal is to allow the programmer to work with a mesh network without having to worry about how the network is structured or managed.
簡單看下幾個常用的api:
明白了主要的api的作用,再來看給出的示例代碼就很簡單了
控制端設備A:
#include "painlessMesh.h"
#define MESH_PREFIX "ESPMESH" // 設置當前MESH網路的名稱 #define MESH_PASSWORD "mypassword" // 密碼 #define MESH_PORT 5555 // 埠
painlessMesh mesh;
void receivedCallback( uint32_t from, String &msg );
void sendMsg(int lesStatus) { // 以json的形式進行包裝數據 // 為什麼用json: // https://gitlab.com/painlessMesh/painlessMesh#json-based DynamicJsonBuffer jsonBuffer; JsonObject& msg = jsonBuffer.createObject(); msg["msgId"] = millis(); msg["topic"] = "ledStatus"; msg["status"] = lesStatus; msg["nodeId"] = mesh.getNodeId();
String str; msg.printTo(str); // 把json轉成string mesh.sendBroadcast(str); // 發送廣播消息
msg.printTo(Serial); Serial.printf(" "); }
void setup() { Serial.begin(115200); mesh.setDebugMsgTypes( ERROR | CONNECTION | S_TIME ); // 設置需要展示的debug信息(列印到串口監視器) mesh.init( MESH_PREFIX, MESH_PASSWORD, MESH_PORT, WIFI_AP_STA, 6 ); // 初始化mesh網路
mesh.onNewConnection([](size_t nodeId) { // 新節點接入的時候 Serial.printf("New Connection %u ", nodeId); // 列印節點唯一id });
mesh.onDroppedConnection([](size_t nodeId) { // 節點連接丟失的時候 Serial.printf("Dropped Connection %u ", nodeId); // 列印丟失的節點id });
mesh.onReceive(&receivedCallback); // 收到消息的時候,執行receivedCallback() }
void loop() { int lesStatus = digitalRead(D0); // 獲取開關狀態 if (lesStatus == 1) { // 狀態是1 sendMsg(lesStatus); // 把狀態消息發送出去 } else { Serial.println("status 0"); } mesh.update(); // 更新mesh網路 delay(1000); }
void receivedCallback( uint32_t from, String &msg ) { // 收到消息的時候,執行該回調方法,列印收到的消息 Serial.printf("control server: Received from %u msg=%s ", from, msg.c_str()); }
被控制端設備B:
#define MESH_PREFIX "ESPMESH" // 名稱/密碼/埠一致才能連接到同一個mesh網路 #define MESH_PASSWORD "mypassword" #define MESH_PORT 5555
void setup() { Serial.begin(115200); pinMode(D2, OUTPUT);
mesh.setDebugMsgTypes( ERROR | STARTUP | CONNECTION );
mesh.init( MESH_PREFIX, MESH_PASSWORD, MESH_PORT ); mesh.onReceive(&receivedCallback); }
void loop() { mesh.update(); }
void receivedCallback( uint32_t from, String &msg ) { // 被控制設備接收到消息,執行該回調 Serial.printf("echoNode: Received from %u msg=%s ", from, msg.c_str()); mesh.sendSingle(from, msg);
// 重新把string轉化成json進行解析 DynamicJsonBuffer jsonBuffer; JsonObject& root = jsonBuffer.parseObject(msg); if (root.containsKey("topic")) { if (String("ledStatus").equals(root["topic"].as<String>())) { digitalWrite(D2, root["status"].as<uint32_t>()); // 打開D2引腳控制的led delay(500); } } digitalWrite(D2, LOW); } 開關用了一個循跡感測器,原理是一樣的
兩段程序分別寫入到兩個ESP8266設備(設備A/設別B);效果同[2]中的一樣,在設備A控制設備B的LED燈。打開串口監視器,會列印了很多的調試信息,簡單分析之後,同樣可以得出[2]中說的兩點信息:
TIPS:
例子視頻
4、EasyMesh
這個庫跟painlessMesh很像,但是作者沒有維護了,不建議使用。但是作者做了一個很酷的demoToy,不過很複雜-_-||
Examples demoToy is currently the only example. It is kind of complex, uses a web server, web sockets, and neopixel animations, so it is not really a great entry level example. That said, it does some pretty cools stuff… here is a video of the demo.-- easyMesh
Examples demoToy is currently the only example. It is kind of complex, uses a web server, web sockets, and neopixel animations, so it is not really a great entry level example. That said, it does some pretty cools stuff… here is a video of the demo.
為了demoToy,作者寫了一個easyWebServer + easyWebSocket。能翻牆的可以在YouTube上看,或者下面??
源碼地址: