MESH组网技术在IOT领域具有非常大的作用,应用非常广泛,主流的无线技术从最开始的Zigbee,到蓝牙,到这里的WIFI都实现了MESH组网技术。在这里使用零知开源平台演示wifi 组网的使用。
硬件我们本次使用零知-ESP8266;
软件使用零知开发工具,自带示例:
(1)先在零知开发工具中打开HelloMesh示例,或者复制下面的代码到零知开发工具中:
/**************************************************************************************
* 文件: \HelloMesh(基础示例)\HelloMesh.ino
* 作者:零知实验室
* -^^- 零知开源,让电子制作变得更简单! -^^-
* 时间: 2019-11-20 19:01:25
* 说明: MESH:无线网络网格
****************************************************************************************/
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMesh.h>
#include <TypeConversionFunctions.h>
#include <assert.h>
const char exampleMeshName[] PROGMEM = "MeshNode_"; //填写WiFi的名称
const char exampleWiFiPassword[] PROGMEM = "123456789";//填写WiFi密码
unsigned int requestNumber = 0;
unsigned int responseNumber = 0;
String manageRequest(const String &request, ESP8266WiFiMesh &meshInstance);
transmission_status_t manageResponse(const String &response, ESP8266WiFiMesh &meshInstance);
void networkFilter(int numberOfNetworks, ESP8266WiFiMesh &meshInstance);
/* 创建网格节点对象 */
ESP8266WiFiMesh meshNode = ESP8266WiFiMesh(manageRequest, manageResponse, networkFilter, FPSTR(exampleWiFiPassword), FPSTR(exampleMeshName), "", true);
/**************************************************************************************
* 描述: 当其他节点向您发送请求时的回调
* 参数: 请求从网格中的另一个节点接收的请求字符串 用函数的ESP8266WiFiMesh实例。
* 返回值: 要发送回另一个节点的字符串
****************************************************************************************/
String manageRequest(const String &request, ESP8266WiFiMesh &meshInstance) {
//在这个函数中,我们不在flash中存储字符串(通过F())。
//原因是另一个节点将等待我们的响应,
//因此,将字符串保存在RAM中会给响应时间带来(小的)改进。
//当然,建议根据RAM要求调整这种方法。
/* 打印收到的消息 */
Serial.print("Request received: ");
Serial.println(request);
/*返回要发回的字符串 */
return ("Hello world response #" + String(responseNumber++) + " from " + meshInstance.getMeshName() + meshInstance.getNodeID() + ".");
}
/**************************************************************************************
* 描述: 从其他节点获取响应时的回调
* 参数: 响应从网格中的另一个节点接收的响应字符串 调用函数的ESP8266WiFiMesh实例。
* 返回值: 响应产生的状态代码,作为int
****************************************************************************************/
transmission_status_t manageResponse(const String &response, ESP8266WiFiMesh &meshInstance) {
transmission_status_t statusCode = TS_TRANSMISSION_COMPLETE;
/* 打印收到的消息 */
Serial.print(F("Request sent: "));
Serial.println(meshInstance.getMessage());
Serial.print(F("Response received: "));
Serial.println(response);
// 我们的最后一个请求得到了响应,所以是时候创建一个新请求了。
meshInstance.setMessage(String(F("Hello world request #")) + String(++requestNumber) + String(F(" from "))
+ meshInstance.getMeshName() + meshInstance.getNodeID() + String(F(".")));
// (void)meshInstance;
//这对于删除“未使用的参数”编译器警告很有用。什么都不做。
return statusCode;
}
/**************************************************************************************
* 描述: 回拨用于决定在完成WiFi扫描后连接到哪个网络。
* 参数: 网络数WiFi扫描中找到的网络数 调用函数的ESP8266WiFiMesh实例。
* 返回值: 无
****************************************************************************************/
void networkFilter(int numberOfNetworks, ESP8266WiFiMesh &meshInstance) {
for (int networkIndex = 0; networkIndex < numberOfNetworks; ++networkIndex) {
String currentSSID = WiFi.SSID(networkIndex);
int meshNameIndex = currentSSID.indexOf(meshInstance.getMeshName());
/* 连接到包含meshInstance.getMeshName()的任何合适的热点*/
if (meshNameIndex >= 0) {
uint64_t targetNodeID = stringToUint64(currentSSID.substring(meshNameIndex + meshInstance.getMeshName().length()));
if (targetNodeID < stringToUint64(meshInstance.getNodeID())) {
ESP8266WiFiMesh::connectionQueue.push_back(NetworkInfo(networkIndex));
}
}
}
}
void setup() {
// 防止闪存磨损,请参阅:https://github.com/esp8266/Arduino/issues/1054。
//但是,这将延迟节点WiFi启动约700毫秒。如果我们没有存储要连接的WiFi网络,则延迟为900毫秒。
WiFi.persistent(false);
Serial.begin(115200); //设置打印串口波特率
delay(50); // 等待序列号。
//yield();
//如果不想等待Serial,请使用此命令。
//WiFi.disconnect()确保WiFi正常工作。
//如果在接收WiFi连接之前没有这样做,那么这些WiFi连接将需要很长时间才能建立,或者有时根本不起作用。
WiFi.disconnect();
Serial.println();
Serial.println();
Serial.println(F("Note that this library can use static IP:s for the nodes to speed up connection times.\n"
"Use the setStaticIP method as shown in this example to enable this.\n"
"Ensure that nodes connecting to the same AP have distinct static IP:s.\n"
"Also, remember to change the default mesh network password!\n\n"));
Serial.println(F("Setting up mesh node..."));
/* 初始化meshNode */
meshNode.begin();
meshNode.activateAP(); // 每个AP都需要一个单独的服务器端口。
// meshNode.setStaticIP(IPAddress(192, 168, 4, 22)); // 激活静态IP模式以加快连接时间。
}
int32_t timeOfLastScan = -10000;
void loop() {
if (millis() - timeOfLastScan > 3000 // 给其他节点一些时间来连接数据传输。
|| (WiFi.status() != WL_CONNECTED && millis() - timeOfLastScan > 2000)) { //在尚未连接时扫描具有两秒间隔的网络。
String request = String(F("Hello world request #")) + String(requestNumber) + String(F(" from ")) + meshNode.getMeshName() + meshNode.getNodeID() + String(F("."));
meshNode.attemptTransmission(request, false);
timeOfLastScan = millis();
//一种检查尝试传输结果的方法
if (ESP8266WiFiMesh::latestTransmissionSuccessful()) {
Serial.println(F("Transmission successful."));
}
// 另一种检查尝试传输结果的方法
if (ESP8266WiFiMesh::latestTransmissionOutcomes.empty()) {
Serial.println(F("No mesh AP found."));
} else {
for (TransmissionResult &transmissionResult : ESP8266WiFiMesh::latestTransmissionOutcomes) {
if (transmissionResult.transmissionStatus == TS_TRANSMISSION_FAILED) {
Serial.println(String(F("Transmission failed to mesh AP ")) + transmissionResult.SSID);
} else if (transmissionResult.transmissionStatus == TS_CONNECTION_FAILED) {
Serial.println(String(F("Connection failed to mesh AP ")) + transmissionResult.SSID);
} else if (transmissionResult.transmissionStatus == TS_TRANSMISSION_COMPLETE) {
// 不需要做任何事,传输成功。
} else {
Serial.println(String(F("Invalid transmission status for ")) + transmissionResult.SSID + String(F("!")));
assert(F("Invalid transmission status returned from responseHandler!") && false);
}
}
}
Serial.println();
} else {
/* 接受任何传入连接 */
meshNode.acceptRequest();
}
}
(2)验证并上传上述代码到零知-ESP8266开发板;
(3)测试:分别把上述代码上传到两个零知-ESP8266开发板,然后分别连接两个板子的串口调试窗口,然后就可以看到两个节点数据传输信息了: