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:
Serial.println("SUCCESS");
break;
case WifiEspNowSendStatus::FAIL:
Serial.println("FAILED");
break;
case WifiEspNowSendStatus::NONE:
Serial.println("PENDING");
break;
}
}
void setup() {
Serial.begin(115200);
Serial.println("ESP-NOW Unicast Example (Encrypted)");
// 设置为 STA 模式(单播通信推荐)
WiFi.mode(WIFI_STA);
WiFi.disconnect();
// 打印本机 MAC 地址
Serial.print("My MAC address: ");
Serial.println(WiFi.macAddress());
// 设置加密密钥(必须在 begin() 之前调用)
bool keySet = WifiEspNow.setPrimaryKey(ENCRYPTION_KEY);
if (!keySet) {
Serial.println("Failed to set encryption key!");
ESP.restart();
} else {
Serial.println("Encryption key set successfully");
}
// 初始化 ESP-NOW
if (!WifiEspNow.begin()) {
Serial.println("ESP-NOW initialization failed");
ESP.restart();
}
// 添加对等节点
if (!WifiEspNow.addPeer(PEER_MAC)) {
Serial.println("Failed to add peer");
ESP.restart();
} else {
Serial.println("Peer added successfully");
}
// 设置接收回调
WifiEspNow.onReceive(onReceive, nullptr);
Serial.println("Ready to send/receive messages");
}
void loop() {
// 每 5 秒发送一条消息
static unsigned long lastSendTime = 0;
if (millis() - lastSendTime > 5000) {
sendMessage("Hello from encrypted ESP-NOW!");
lastSendTime = millis();
}
// 处理其他任务
delay(10);
}
伪广播.ino
#include <WifiEspNowBroadcast.h>
// 定义加密密钥(16 字节 = 128 位)
// 注意:所有设备必须使用相同的密钥!
static const uint8_t ENCRYPTION_KEY[WIFIESPNOW_KEYLEN] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10
};
static const int BUTTON_PIN = 0; // 默认使用 GPIO0(Flash 按钮)
static const int LED_PIN = 2; // 默认使用 GPIO2(板载 LED)
int ledState = HIGH; // LED 初始状态(HIGH 通常为熄灭)
/**
* 接收消息回调函数
* 当接收到伪广播消息时被调用
*/
void processRx(const uint8_t mac[WIFIESPNOW_ALEN], const uint8_t* buf, size_t count, void* arg) {
// 打印发送方 MAC 地址
Serial.printf("Message from %02X:%02X:%02X:%02X:%02X:%02X\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
// 打印接收到的消息内容
for (size_t i = 0; i < count; ++i) {
Serial.print(static_cast<char>(buf[i]));
}
Serial.println();
// 切换 LED 状态
digitalWrite(LED_PIN, ledState);
ledState = 1 - ledState;
}
void setup() {
Serial.begin(115200);
Serial.println();
WiFi.persistent(false);
// 初始化伪广播功能
bool ok = WifiEspNowBroadcast.begin("ESPNOW", 3);
if (!ok) {
Serial.println("WifiEspNowBroadcast.begin() failed");
ESP.restart();
}
// 设置加密密钥(使用 WifiEspNowBroadcast 类的方法)
bool keySet = WifiEspNowBroadcast.setPrimaryKey(ENCRYPTION_KEY);
if (!keySet) {
Serial.println("Failed to set encryption key!");
ESP.restart();
} else {
Serial.println("Encryption key set successfully");
}
// 设置接收回调函数
WifiEspNowBroadcast.onReceive(processRx, nullptr);
// 初始化按钮和 LED 引脚
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, ledState);
// 打印设备 MAC 地址(用于识别不同设备)
Serial.print("MAC address of this node is ");
Serial.println(WiFi.softAPmacAddress());
Serial.println("Press the button to send a message");
}
/**
* 发送消息函数
* 向所有已知的对等设备发送消息(伪广播)
*/
void sendMessage() {
// 准备包含设备信息和时间戳的消息
char msg[60];
int len = snprintf(msg, sizeof(msg), "ESP-NOW encrypted broadcast from %s at %lu",
WiFi.softAPmacAddress().c_str(), millis());
// 发送消息到所有已知对等设备
WifiEspNowBroadcast.send(reinterpret_cast<const uint8_t*>(msg), len);
// 打印发送信息和已知对等设备列表
Serial.println("Sending encrypted message");
Serial.println(msg);
// 打印已知对等设备列表
Serial.print("Known peers: ");
const int MAX_PEERS = 20;
WifiEspNowPeerInfo peers[MAX_PEERS];
int nPeers = std::min(WifiEspNow.listPeers(peers, MAX_PEERS), MAX_PEERS);
for (int i = 0; i < nPeers; ++i) {
Serial.printf(" %02X:%02X:%02X:%02X:%02X:%02X",
peers[i].mac[0], peers[i].mac[1],
peers[i].mac[2], peers[i].mac[3],
peers[i].mac[4], peers[i].mac[5]);
}
Serial.println();
}
void loop() {
// 检测按钮是否按下(LOW 表示按下)
if (digitalRead(BUTTON_PIN) == LOW) {
// 发送消息
sendMessage();
// 等待按钮释放,避免重复触发
while (digitalRead(BUTTON_PIN) == LOW);
}
// 处理伪广播库的循环逻辑(必须调用)
WifiEspNowBroadcast.loop();
// 短暂延时,避免过于频繁地扫描
delay(10);
}
对等设备管理函数
int listPeers(WifiEspNowPeerInfo\* peers, int maxPeers) const
:
- 功能:列出当前的对等设备信息。
- 参数:
peers
为存储对等设备信息的缓冲区,maxPeers
为缓冲区大小。 - 返回值:返回对等设备的总数,实际写入
peers
的数量为std::min(retval, maxPeers)
。
bool hasPeer(const uint8_t mac[WIFIESPNOW_ALEN]) const
:
- 功能:检查指定 MAC 地址的对等设备是否存在。
- 参数:
mac
为对等设备的 MAC 地址。 - 返回值:存在返回
true
,否则返回false
。
bool addPeer(const uint8_t mac[WIFIESPNOW_ALEN], int channel = 0, const uint8_t key[WIFIESPNOW_KEYLEN] = nullptr, int netif = ESP_IF_WIFI_AP)
:
- 功能:添加一个对等设备或更改对等设备的通道。
- 参数:
mac
为对等设备的 MAC 地址,channel
为对等设备的通道,key
为加密密钥,netif
为 WiFi 接口(仅 ESP32)。 - 返回值:操作成功返回
true
,否则返回false
。
bool removePeer(const uint8_t mac[WIFIESPNOW_ALEN])
:
- 功能:移除指定 MAC 地址的对等设备。
- 参数:
mac
为对等设备的 MAC 地址。 - 返回值:移除成功返回
true
,否则返回false
。
接收和发送函数
void onReceive(RxCallback cb, void\* arg)
:
- 功能:设置接收回调函数。
- 参数:
cb
为回调函数指针,arg
为传递给回调函数的参数。 - 返回值:无
bool send(const uint8_t mac[WIFIESPNOW_ALEN], const uint8_t\* buf, size_t count)
:
- 功能:发送消息。
- 参数:
mac
为目标 MAC 地址,nullptr
表示所有对等设备;buf
为消息缓冲区,count
为消息大小。 - 返回值:消息成功入队发送返回
true
,否则返回false
。
WifiEspNowSendStatus getSendStatus() const
:
- 功能:获取最后一次发送消息的状态。
- 返回值:返回发送状态,枚举类型
WifiEspNowSendStatus
,可能值为NONE
、OK
或FAIL
。
// 获取发送状态
WifiEspNowSendStatus status = WifiEspNow.getSendStatus();
switch (status) {
case WifiEspNowSendStatus::OK:
Serial.println("Message sent successfully");
break;
case WifiEspNowSendStatus::FAIL:
Serial.println("Message sending failed");
break;
case WifiEspNowSendStatus::NONE:
Serial.println("Message status unknown, still sending");
break;
WifiEspNowBroadcast 函数
初始化和终止函数
bool begin(const char\* ssid, int channel = 1, int scanFreq = 15000)
:
-
功能:初始化 ESP - NOW 并启动伪广播功能。
-
参数:
ssid
为用于宣告和发现对等设备的 AP SSID,channel
指的是接入点(AP)所使用的 WiFi 通道。在 WiFi 网络里,不同的通道代表着不同的频段,设备要在相同的通道上才能实现相互通信。scanFreq
为扫描对等设备的频率(毫秒)。所有设备都要使用相同的网络名称和通道,以此保证能相互通信。 -
返回值:初始化成功返回
true
,否则返回false
。
void end()
:
- 功能:停止 ESP - NOW 和伪广播功能。
- 返回值:无
扫描和循环函数
void loop()
:
- 功能:在 Arduino 的
loop()
函数中调用,用于定期扫描对等设备。 - 返回值:无
密钥设置函数
bool setKey(const uint8_t primary[WIFIESPNOW_KEYLEN], const uint8_t peer[WIFIESPNOW_KEYLEN] = nullptr)
:
- 功能:设置加密密钥。
- 参数:
primary
为主密钥,peer
为对等设备密钥,nullptr
表示禁用加密。 - 返回值:设置成功返回
true
,否则返回false
。
使用 setKey()
的加密伪广播代码
#include <WifiEspNowBroadcast.h>
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WiFi.h>
#elif defined(ARDUINO_ARCH_ESP32)
#include <WiFi.h>
#endif
// 定义主加密密钥(16 字节 = 128 位)
// 注意:所有设备必须使用相同的主密钥!
static const uint8_t PRIMARY_KEY[WIFIESPNOW_KEYLEN] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10
};
// 可选:定义对等设备特定密钥(用于特定设备间的额外加密)
static const uint8_t PEER_KEY[WIFIESPNOW_KEYLEN] = {
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20
};
static const int BUTTON_PIN = 0; // 默认使用 GPIO0(Flash 按钮)
static const int LED_PIN = 2; // 默认使用 GPIO2(板载 LED)
int ledState = HIGH; // LED 初始状态(HIGH 通常为熄灭)
/**
* 接收消息回调函数
* 当接收到伪广播消息时被调用
*/
void processRx(const uint8_t mac[WIFIESPNOW_ALEN], const uint8_t* buf, size_t count, void* arg) {
// 打印发送方 MAC 地址
Serial.printf("Message from %02X:%02X:%02X:%02X:%02X:%02X\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
// 打印接收到的消息内容
for (size_t i = 0; i < count; ++i) {
Serial.print(static_cast<char>(buf[i]));
}
Serial.println();
// 切换 LED 状态
digitalWrite(LED_PIN, ledState);
ledState = 1 - ledState;
}
void setup() {
Serial.begin(115200);
Serial.println();
WiFi.persistent(false);
// 初始化伪广播功能
bool ok = WifiEspNowBroadcast.begin("ESPNOW", 3);
if (!ok) {
Serial.println("WifiEspNowBroadcast.begin() failed");
ESP.restart();
}
// 设置加密密钥(使用 setKey 函数)
// 第一个参数为主密钥,第二个参数为可选的对等设备特定密钥
bool keySet = WifiEspNowBroadcast.setKey(PRIMARY_KEY, PEER_KEY);
if (!keySet) {
Serial.println("Failed to set encryption key!");
ESP.restart();
} else {
Serial.println("Encryption key set successfully");
}
// 设置接收回调函数
WifiEspNowBroadcast.onReceive(processRx, nullptr);
// 初始化按钮和 LED 引脚
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, ledState);
// 打印设备 MAC 地址(用于识别不同设备)
Serial.print("MAC address of this node is ");
Serial.println(WiFi.softAPmacAddress());
Serial.println("Press the button to send a message");
}
/**
* 发送消息函数
* 向所有已知的对等设备发送消息(伪广播)
*/
void sendMessage() {
// 准备包含设备信息和时间戳的消息
char msg[60];
int len = snprintf(msg, sizeof(msg), "ESP-NOW encrypted broadcast from %s at %lu",
WiFi.softAPmacAddress().c_str(), millis());
// 发送消息到所有已知对等设备
WifiEspNowBroadcast.send(reinterpret_cast<const uint8_t*>(msg), len);
// 打印发送信息和已知对等设备列表
Serial.println("Sending encrypted message");
Serial.println(msg);
// 打印已知对等设备列表
Serial.print("Known peers: ");
const int MAX_PEERS = 20;
WifiEspNowPeerInfo peers[MAX_PEERS];
int nPeers = std::min(WifiEspNow.listPeers(peers, MAX_PEERS), MAX_PEERS);
for (int i = 0; i < nPeers; ++i) {
Serial.printf(" %02X:%02X:%02X:%02X:%02X:%02X",
peers[i].mac[0], peers[i].mac[1],
peers[i].mac[2], peers[i].mac[3],
peers[i].mac[4], peers[i].mac[5]);
}
Serial.println();
}
void loop() {
// 检测按钮是否按下(LOW 表示按下)
if (digitalRead(BUTTON_PIN) == LOW) {
// 发送消息
sendMessage();
// 等待按钮释放,避免重复触发
while (digitalRead(BUTTON_PIN) == LOW);
}
// 处理伪广播库的循环逻辑(必须调用)
WifiEspNowBroadcast.loop();
// 短暂延时,避免过于频繁地扫描
delay(10);
}
密钥配置:
- 所有设备必须使用相同的主密钥
PRIMARY_KEY
- 对等设备特定密钥
PEER_KEY
可以为nullptr
(如果不需要)或所有设备相同
接收和发送函数
void onReceive(WifiEspNowClass::RxCallback cb, void\* arg)
:
- 功能:设置接收回调函数。
- 参数:
cb
为回调函数指针,arg
为传递给回调函数的参数。 - 返回值:无
bool send(const uint8_t\* buf, size_t count)
:
- 功能:广播消息。
- 参数:
buf
为消息缓冲区,count
为消息大小。 - 返回值:消息成功入队发送返回
true
,否则返回false
。
setKey() 和 setPrimaryKey() 的区别
在 ESP-NOW 通信中,setKey()
和 setPrimaryKey()
的区别涉及到加密的粒度和应用场景。
setPrimaryKey()
bool setPrimaryKey(const uint8_t key[WIFIESPNOW_KEYLEN]);
- 功能:设置一个全局主密钥,所有对等设备必须使用相同的主密钥才能通信。
- 应用范围:整个 ESP-NOW 网络的所有设备共享同一个密钥。
- 使用场景:简单的加密通信,所有设备使用相同的安全级别。
setKey()
bool setKey(const uint8_t primary[WIFIESPNOW_KEYLEN],
const uint8_t peer[WIFIESPNOW_KEYLEN] = nullptr);
- 功能:设置两个密钥
- 主密钥(Primary Key):与
setPrimaryKey()
类似,所有设备必须相同。 - 对等设备特定密钥(Peer Key):可选,用于特定设备间的额外加密。
- 主密钥(Primary Key):与
- 应用范围:主密钥用于全局加密,对等密钥用于特定设备对之间的通信。
- 使用场景:需要更细粒度安全控制的场景(如不同设备组使用不同密钥)。
为什么需要两个密钥?
多层安全保护
- 主密钥:确保整个网络的基本安全性,所有设备必须共享。
- 对等密钥:为特定设备对提供额外的安全层,例如:
- 管理员设备与普通设备之间使用不同的对等密钥。
- 关键设备之间使用更高级别的加密。
灵活的安全策略
通过组合使用两个密钥,可以实现:
- 分层安全:不同类型的设备使用不同的安全级别。
- 设备身份验证:特定设备对之间使用专用密钥,防止中间人攻击。
应用场景对比
场景 | 推荐方法 | 说明 |
---|---|---|
所有设备使用相同的加密密钥 | setPrimaryKey() | 简单、统一的加密,所有设备共享一个密钥。 |
不同设备组使用不同的安全级别 | setKey(主密钥, 组特定密钥) | 主密钥确保基本安全,组特定密钥区分不同设备组(如管理员组与普通用户组)。 |
特定设备对之间需要更高的安全性 | setKey(主密钥, 设备对密钥) | 主密钥用于全局通信,设备对密钥用于敏感通信(如控制指令)。 |
示例
获取MAC地址
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WiFi.h>
#elif defined(ARDUINO_ARCH_ESP32)
#include <WiFi.h>
#endif
void setup() {
Serial.begin(115200);
// 设置WiFi模式为STA(站点模式)
WiFi.mode(WIFI_STA);
// 获取并打印MAC地址
Serial.print("MAC address of this node is ");
Serial.println(WiFi.macAddress());
}
void loop() {
// 主循环可以留空,因为我们只需要在启动时获取一次MAC地址
}
单播
fa.ino
#include <WifiEspNow.h>
// 定义接收端的 MAC 地址
const uint8_t receiverMac[WIFIESPNOW_ALEN] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
void setup() {
Serial.begin(115200);
// 初始化 ESP-NOW
if (WifiEspNow.begin()) {
Serial.println("ESP-NOW 初始化成功");
} else {
Serial.println("ESP-NOW 初始化失败");
return;
}
// 添加接收端为对等设备
if (WifiEspNow.addPeer(receiverMac)) {
Serial.println("对等设备添加成功");
} else {
Serial.println("对等设备添加失败");
}
}
void loop() {
const char* message = "Hello, Receiver!";
size_t messageLength = strlen(message);
// 向接收端发送消息
if (WifiEspNow.send(receiverMac, (const uint8_t*)message, messageLength)) {
Serial.println("消息已发送");
} else {
Serial.println("消息发送失败");
}
delay(5000); // 每 5 秒发送一次消息
}
shou.ino
#include <WifiEspNow.h>
// 定义控制灯的引脚
const int ledPin = 2;
// 接收回调函数,当接收到消息时会被调用
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, size_t data_len) {
Serial.print("Received data from MAC address: ");
// 打印发送端的 MAC 地址
for (int i = 0; i < WIFIESPNOW_ALEN; i++) {
Serial.printf("%02X", mac_addr[i]);
if (i < WIFIESPNOW_ALEN - 1) {
Serial.print(":");
}
}
Serial.print(", Data: ");
// 打印接收到的数据
for (size_t i = 0; i < data_len; i++) {
Serial.print((char)data[i]);
}
Serial.println();
// 将接收到的数据转换为字符串
String receivedData = "";
for (size_t i = 0; i < data_len; i++) {
receivedData += (char)data[i];
}
// 根据接收到的数据控制灯的开关
if (receivedData == "ON") {
digitalWrite(ledPin, HIGH);
Serial.println("Light turned on");
} else if (receivedData == "OFF") {
digitalWrite(ledPin, LOW);
Serial.println("Light turned off");
}
}
void setup() {
Serial.begin(115200);
// 初始化控制灯的引脚
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
// 初始化 ESP-NOW
if (WifiEspNow.begin()) {
Serial.println("ESP-NOW initialized successfully");
} else {
Serial.println("ESP-NOW initialization failed");
return;
}
// 设置接收回调函数
WifiEspNow.onReceive(OnDataRecv, nullptr);
}
void loop() {
// 可以在这里添加其他的循环逻辑
delay(100);
}
发送端,点击按钮发送ON
#include <WifiEspNow.h>
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WiFi.h>
#elif defined(ARDUINO_ARCH_ESP32)
#include <WiFi.h>
#endif
// 定义接收方的 MAC 地址
static uint8_t PEER[] {0x02, 0x00, 0x00, 0x45, 0x53, 0x50};
// 定义按钮引脚
const int buttonPin = 4;
// 上一次按钮状态
int lastButtonState = HIGH;
void setup() {
Serial.begin(115200);
Serial.println();
// 初始化按钮引脚为输入模式
pinMode(buttonPin, INPUT_PULLUP);
bool ok = WifiEspNow.begin();
if (!ok) {
Serial.println("WifiEspNow.begin() failed");
ESP.restart();
}
ok = WifiEspNow.addPeer(PEER);
if (!ok) {
Serial.println("WifiEspNow.addPeer() failed");
ESP.restart();
}
}
void loop() {
// 读取按钮状态
int buttonState = digitalRead(buttonPin);
// 检测按钮是否按下
if (buttonState == LOW && lastButtonState == HIGH) {
// 按钮按下,发送 "ON" 消息
const char* msg = "ON";
size_t len = strlen(msg);
bool sent = WifiEspNow.send(PEER, reinterpret_cast<const uint8_t*>(msg), len);
if (sent) {
Serial.println("Message 'ON' sent successfully");
} else {
Serial.println("Failed to send message 'ON'");
}
}
// 更新上一次按钮状态
lastButtonState = buttonState;
// 短暂延迟以避免抖动
delay(50);
}
发送端,点击按钮发送ON,再点击发送OFF
#include <WifiEspNow.h>
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WiFi.h>
#elif defined(ARDUINO_ARCH_ESP32)
#include <WiFi.h>
#endif
// 定义接收方的 MAC 地址
static uint8_t PEER[] {0x02, 0x00, 0x00, 0x45, 0x53, 0x50};
// 定义按钮引脚
const int buttonPin = 4;
// 上一次按钮状态
int lastButtonState = HIGH;
// 消息状态,用于交替发送 "ON" 和 "OFF"
bool isOn = false;
void setup() {
Serial.begin(115200);
Serial.println();
// 初始化按钮引脚为输入模式
pinMode(buttonPin, INPUT_PULLUP);
bool ok = WifiEspNow.begin();
if (!ok) {
Serial.println("WifiEspNow.begin() failed");
ESP.restart();
}
ok = WifiEspNow.addPeer(PEER);
if (!ok) {
Serial.println("WifiEspNow.addPeer() failed");
ESP.restart();
}
}
void loop() {
// 读取按钮状态
int buttonState = digitalRead(buttonPin);
// 检测按钮是否按下
if (buttonState == LOW && lastButtonState == HIGH) {
const char* msg;
if (isOn) {
msg = "OFF";
} else {
msg = "ON";
}
size_t len = strlen(msg);
bool sent = WifiEspNow.send(PEER, reinterpret_cast<const uint8_t*>(msg), len);
if (sent) {
Serial.printf("Message '%s' sent successfully\n", msg);
} else {
Serial.printf("Failed to send message '%s'\n", msg);
}
// 切换消息状态
isOn = !isOn;
}
// 更新上一次按钮状态
lastButtonState = buttonState;
// 短暂延迟以避免抖动
delay(50);
}
一对多
ESP - NOW支持多播,但WifiEspNow库中似乎并没有特殊函数来支持多播
通过单播,依次向两个mac地址发送信息,实现多播效果
fa.ino
#include <WifiEspNow.h>
// 定义两个目标设备的 MAC 地址
const uint8_t macAddress1[WIFIESPNOW_ALEN] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
const uint8_t macAddress2[WIFIESPNOW_ALEN] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
void setup() {
Serial.begin(115200);
// 初始化 ESP-NOW
if (WifiEspNow.begin()) {
Serial.println("ESP-NOW 初始化成功");
} else {
Serial.println("ESP-NOW 初始化失败");
return;
}
// 添加两个对等设备
if (WifiEspNow.addPeer(macAddress1) && WifiEspNow.addPeer(macAddress2)) {
Serial.println("对等设备添加成功");
} else {
Serial.println("对等设备添加失败");
}
}
void loop() {
const char* message = "Hello, ESP-NOW!";
size_t messageLength = strlen(message);
// 向第一个 MAC 地址发送消息
if (WifiEspNow.send(macAddress1, (const uint8_t*)message, messageLength)) {
Serial.println("消息已发送到第一个设备");
} else {
Serial.println("消息发送到第一个设备失败");
}
// 向第二个 MAC 地址发送消息
if (WifiEspNow.send(macAddress2, (const uint8_t*)message, messageLength)) {
Serial.println("消息已发送到第二个设备");
} else {
Serial.println("消息发送到第二个设备失败");
}
delay(5000); // 每 5 秒发送一次消息
}
shou.ino
#include <WifiEspNow.h>
// 接收回调函数,当接收到消息时会被调用
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, size_t data_len) {
Serial.print("Received data from MAC address: ");
// 打印发送端的 MAC 地址
for (int i = 0; i < WIFIESPNOW_ALEN; i++) {
Serial.printf("%02X", mac_addr[i]);
if (i < WIFIESPNOW_ALEN - 1) {
Serial.print(":");
}
}
Serial.print(", Data: ");
// 打印接收到的数据
for (size_t i = 0; i < data_len; i++) {
Serial.print((char)data[i]);
}
Serial.println();
}
void setup() {
Serial.begin(115200);
// 初始化 ESP-NOW
if (WifiEspNow.begin()) {
Serial.println("ESP-NOW initialized successfully");
} else {
Serial.println("ESP-NOW initialization failed");
return;
}
// 设置接收回调函数
WifiEspNow.onReceive(OnDataRecv, nullptr);
}
void loop() {
// 可以在这里添加其他的循环逻辑
delay(100);
}
伪广播
// 实现 ESP-NOW 广播发送和接收消息,收到 'ON' 点亮 LED 的示例代码
#include <WifiEspNowBroadcast.h>
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WiFi.h>
#elif defined(ARDUINO_ARCH_ESP32)
#include <WiFi.h>
#endif
// 定义 LED 引脚
#ifdef ARDUINO_ARCH_ESP8266
const int LED_PIN = 2;
#else
const int LED_PIN = LED_BUILTIN;
#endif
// 处理接收到的消息的函数
void processRx(const uint8_t mac[WIFIESPNOW_ALEN], const uint8_t* buf, size_t count, void* arg) {
Serial.print("Received message from ");
for (int i = 0; i < WIFIESPNOW_ALEN; i++) {
Serial.printf("%02X", mac[i]);
if (i < WIFIESPNOW_ALEN - 1) {
Serial.print(":");
}
}
Serial.print(": ");
for (size_t i = 0; i < count; i++) {
Serial.print((char)buf[i]);
}
Serial.println();
// 检查是否收到 "ON" 消息
if (count == 2 && buf[0] == 'O' && buf[1] == 'N') {
digitalWrite(LED_PIN, HIGH);
Serial.println("Received 'ON', LED is turned on.");
}
}
// 发送消息的函数
void sendMessage() {
const char* msg = "hello";
size_t len = strlen(msg);
WifiEspNowBroadcast.send(reinterpret_cast<const uint8_t*>(msg), len);
Serial.println("Message sent: hello");
// 获取并打印已知对等设备列表
const int MAX_PEERS = 20;
WifiEspNowPeerInfo peers[MAX_PEERS];
int nPeers = std::min(WifiEspNow.listPeers(peers, MAX_PEERS), MAX_PEERS);
for (int i = 0; i < nPeers; ++i) {
Serial.printf(" %02X:%02X:%02X:%02X:%02X:%02X", peers[i].mac[0], peers[i].mac[1],
peers[i].mac[2], peers[i].mac[3], peers[i].mac[4], peers[i].mac[5]);
}
Serial.println();
}
void setup() {
Serial.begin(115200);
Serial.println();
WiFi.persistent(false); // 禁用 WiFi 配置持久化存储
bool ok = WifiEspNowBroadcast.begin("ESPNOW", 3);
if (!ok) {
Serial.println("WifiEspNowBroadcast.begin() failed");
ESP.restart();
}
WifiEspNowBroadcast.onReceive(processRx, nullptr);
// 初始化 LED 引脚
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
Serial.print("MAC address of this node is ");
Serial.println(WiFi.softAPmacAddress());
}
void loop() {
// 每5秒发送一次消息
static unsigned long lastSendTime = 0;
if (millis() - lastSendTime >= 5000) {
sendMessage();
lastSendTime = millis();
}
WifiEspNowBroadcast.loop();
delay(10);
}
伪广播认证
#include <WifiEspNowBroadcast.h>
// 合法设备的 MAC 地址列表
uint8_t allowedMacs[][WIFIESPNOW_ALEN] = {
{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
// 可以添加更多合法 MAC 地址
};
int numAllowedMacs = sizeof(allowedMacs) / sizeof(allowedMacs[0]);
bool isMacAllowed(const uint8_t mac[WIFIESPNOW_ALEN]) {
for (int i = 0; i < numAllowedMacs; i++) {
if (memcmp(mac, allowedMacs[i], WIFIESPNOW_ALEN) == 0) {
return true;
}
}
return false;
}
void processRx(const uint8_t mac[WIFIESPNOW_ALEN], const uint8_t* buf, size_t count, void* arg) {
if (isMacAllowed(mac)) {
// 处理合法设备发送的消息
for (size_t i = 0; i < count; i++) {
Serial.print((char)buf[i]);
}
Serial.println();
} else {
// 忽略非法设备发送的消息
Serial.println("Received message from unauthorized device");
}
}
void setup() {
Serial.begin(115200);
WiFi.persistent(false);
bool ok = WifiEspNowBroadcast.begin("ESPNOW", 3);
if (!ok) {
Serial.println("WifiEspNowBroadcast.begin() failed");
ESP.restart();
}
WifiEspNowBroadcast.onReceive(processRx, nullptr);
}
void loop() {
WifiEspNowBroadcast.loop();
delay(10);
}