WifiEspNow库函数详解
WifiEspNow库
项目地址https://github.com/yoursunny/WifiEspNow
WifiEspNow 是 ESP-NOW 的 Arduino 库,ESP-NOW 是乐鑫定义的无连接 WiFi 通信协议。 有关 ESP-NOW 工作原理及其限制的更多信息,请参阅 ESP-NOW 参考。
WifiEspNow是 ESP-IDF 中 ESP-NOW 函数的简单包装器。 在 ESP8266 上,它仅支持单播。 在 ESP32 上,它支持单播和多播。ESP-NOW支持多播,但WifiEspNow库中似乎并没有特殊函数来支持多播
WifiEspNowBroadcast 通过 ESP-NOW 实现伪广播。 每个设备通告一个特定的 WiFi SSID,并通过 BSSID 扫描发现彼此。 然后,消息通过 ESP-NOW 单播分别传输到每个对等体。
ESP - NOW 的伪广播机制是基于设备之间的对等连接。当设备调用 WifiEspNowBroadcast.begin()
初始化后,它会自动搜索同一通道上的其他 ESP - NOW 设备,并建立对等连接。这些连接会在后台自动管理,所以无需显式设置目标设备的 MAC 地址。所有设备都要使用相同的网络名称和通道,以此保证能相互通信。
ESP32 和 ESP8266 可以一起组网进行伪广播通信。因为伪广播是基于单播实现的,而 ESP8266 支持单播通信,ESP32 也支持单播通信,它们可以通过伪广播机制进行组网
单播和多播
在 ESP-NOW 通信中,单播(Unicast) 和多播(Multicast) 是两种不同的数据传输方式,它们在目标地址、通信模式和应用场景上有明显区别。
特性 | 单播(Unicast) | 多播(Multicast) |
---|---|---|
目标地址 | 单个接收方的 MAC 地址 | 预定义的多播组 MAC 地址(例如以 01:00:5E 开头) |
接收方数量 | 1 个设备 | 加入同一多播组的所有设备 |
可靠性 | 高(有 ACK 确认) | 低(无 ACK 确认,不保证所有接收方收到) |
效率 | 每次发送到一个设备,开销较大 | 单次发送到多个设备,效率高 |
应用场景 | 一对一通信(如控制指令、私密数据) | 一对多通信(如系统广播、配置更新) |
场景 | 选择多播 | 选择单播 |
---|---|---|
同时向多个设备发送相同数据 | ✅ 高效(一次发送) | ❌ 需多次发送,效率低 |
需要确认消息是否送达 | ❌ 无 ACK 机制 | ✅ 有 ACK 机制,可靠性高 |
系统配置更新 | ✅ 简单直接 | ❌ 需要逐个确认 |
私密数据传输 | ❌ 所有组成员可见 | ✅ 仅目标设备可见 |
网络负载 | ✅ 低(单次传输) | ❌ 高(多次传输) |
WifiEspNow 函数
初始化和终止函数
bool begin()
:
- 功能:初始化 ESP - NOW。设置 ESP - NOW 角色、注册接收和发送回调函数。
- 返回值:初始化成功返回
true
,否则返回false
。
void end()
:
- 功能:停止 ESP - NOW,释放相关资源。
- 返回值:无
密钥设置函数
bool setPrimaryKey(const uint8_t key[WIFIESPNOW_KEYLEN])
:
- 功能:设置主加密密钥(KOK 或 PMK)。
- 参数:
key
是一个长度为WIFIESPNOW_KEYLEN
(通常为 16 字节)的字节数组,表示加密密钥。 - 返回值:设置成功返回
true
,否则返回false
。
加密密钥必须是 16 字节(128 位) 的随机字节数组。
python小工具:
import secrets# 生成一个长度为16的随机字节数组
key = secrets.token_bytes(16)# 打印生成的密钥数组
print("static const uint8_t ENCRYPTION_KEY[WIFIESPNOW_KEYLEN] = {", end="")
for i, byte in enumerate(key):if i < 15:print(f"0x{byte:02X}, ", end="")else:print(f"0x{byte:02X}", end="")
print("};")
在调用 WifiEspNow.begin()
之前设置密钥,确保所有设备使用相同的密钥。
所有参与通信的设备必须使用相同的密钥,否则无法解密消息。
单播.ino
#include <WifiEspNow.h>// 定义加密密钥(所有设备必须使用相同的密钥)
static const uint8_t ENCRYPTION_KEY[WIFIESPNOW_KEYLEN] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10
};// 接收方 MAC 地址(需要替换为实际接收方的 MAC 地址)
static uint8_t PEER_MAC[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};// 发送状态变量
WifiEspNowSendStatus lastSendStatus = WifiEspNowSendStatus::NONE;// 接收回调函数
void onReceive(const uint8_t* mac, const uint8_t* data, size_t len, void* arg) {Serial.print("Received from: ");for (int i = 0; i < 6; i++) {Serial.printf("%02X:", mac[i]);}Serial.print(" Data: ");for (size_t i = 0; i < len; i++) {Serial.print((char)data[i]);}Serial.println();
}// 发送消息函数
void sendMessage(const char* message) {size_t len = strlen(message);bool result = WifiEspNow.send(PEER_MAC, (const uint8_t*)message, len);if (result) {Serial.print("Message sent: ");Serial.println(message);} else {Serial.println("Failed to send message");}// 等待一段时间获取发送状态delay(100);lastSendStatus = WifiEspNow.getSendStatus();Serial.print("Send status: ");switch (lastSendStatus) {case WifiEspNowSendStatus::OK: