1ESP-NOW
2========
3
4:link_to_translation:`en:[英文]`
5
6概述
7--------
8
9ESP-NOW 是一种由乐鑫公司定义的无连接 Wi-Fi 通信协议。在 ESP-NOW 中,应用程序数据被封装在各个供应商的动作帧中,然后在无连接的情况下,从一个 Wi-Fi 设备传输到另一个 Wi-Fi 设备。
10CTR 与 CBC-MAC 协议 (CCMP) 可用来保护动作帧的安全。ESP-NOW 广泛应用于智能照明、远程控制、传感器等领域。
11
12帧格式
13------------
14
15ESP-NOW 使用各个供应商的动作帧传输数据,默认比特率为 1 Mbps。各个供应商的动作帧格式为:
16
17.. highlight:: none
18
19::
20
21    -----------------------------------------------------------------------------------------
22    |   MAC 报头   |  分类代码  |  组织标识符  |  随机值  |  供应商特定内容  |   FCS   |
23    -----------------------------------------------------------------------------------------
24       24 字节        1 字节        3 字节      4 字节      7~255 字节       4 字节
25
26- 分类代码:分类代码字段可用于指示各个供应商的类别(比如 127)。
27- 组织标识符:组织标识符包含一个唯一标识符 (比如 0x18fe34),为乐鑫指定的 MAC 地址的前三个字节。
28- 随机值:防止重放攻击。
29- 供应商特定内容:供应商特定内容包含供应商特定字段,如下所示:
30
31.. highlight:: none
32
33::
34
35    ----------------------------------------------------------------------------------------
36    |  元素 ID  |  长度  |  组织标识符  |  类型  |  版本  |     正文     |
37    ----------------------------------------------------------------------------------------
38       1 字节     1 字节     3 字节      1 字节   1 字节    0~250 字节
39
40- 元素 ID:元素 ID 字段可用于指示特定于供应商的元素。
41- 长度:长度是组织标识符、类型、版本和正文的总长度。
42- 组织标识符:组织标识符包含一个唯一标识符 (比如 0x18fe34),为乐鑫指定的 MAC 地址的前三个字节。
43- 类型:类型字段设置为 4,代表 ESP-NOW。
44- 版本:版本字段设置为 ESP-NOW 的版本。
45- 正文:正文包含 ESP-NOW 数据。
46
47由于 ESP-NOW 是无连接的,因此 MAC 报头与标准帧略有不同。FrameControl 字段的 FromDS 和 ToDS 位均为 0。第一个地址字段用于配置目标地址。第二个地址字段用于配置源地址。第三个地址字段用于配置广播地址 (0xff:0xff:0xff:0xff:0xff:0xff)。
48
49安全
50--------
51
52ESP-NOW 采用 CCMP 方法保护供应商特定动作帧的安全,具体可参考 IEEE Std. 802.11-2012。Wi-Fi 设备维护一个初始主密钥 (PMK) 和若干本地主密钥 (LMK),长度均为 16 个字节。
53    * PMK 可使用 AES-128 算法加密 LMK。请调用 ``esp_now_set_pmk()`` 设置 PMK。如果未设置 PMK,将使用默认 PMK。
54    * LMK 可通过 CCMP 方法对供应商特定的动作帧进行加密,最多拥有 6 个不同的 LMK。如果未设置配对设备的 LMK,则动作帧不进行加密。
55
56目前,不支持加密组播供应商特定的动作帧。
57
58初始化和反初始化
59------------------------------------
60
61调用 ``esp_now_init()`` 初始化 ESP-NOW,调用  ``esp_now_deinit()`` 反初始化 ESP-NOW。ESP-NOW 数据必须在 Wi-Fi 启动后传输,因此建议在初始化 ESP-NOW 之前启动 Wi-Fi,并在反初始化 ESP-NOW 之后停止 Wi-Fi。
62当调用 ``esp_now_deinit()`` 时,配对设备的所有信息都将被删除。
63
64添加配对设备
65-----------------
66
67在将数据发送到其他设备之前,请先调用  ``esp_now_add_peer()`` 将其添加到配对设备列表中。配对设备的最大数量是 20。如果启用了加密,则必须设置 LMK。ESP-NOW 数据可以从 Station 或 Softap 接口发送。
68确保在发送 ESP-NOW 数据之前已启用该接口。在发送广播数据之前必须添加具有广播 MAC 地址的设备。配对设备的信道范围是从 0 ~14。如果信道设置为 0,数据将在当前信道上发送。否则,必须使用本地设备所在的通道。
69
70发送 ESP-NOW 数据
71-----------------
72
73调用 ``esp_now_send()`` 发送 ESP-NOW 数据,调用  ``esp_now_register_send_cb`` 注册发送回调函数。如果 MAC 层成功接收到数据,则该函数将返回 `ESP_NOW_SEND_SUCCESS` 事件。否则,它将返回  `ESP_NOW_SEND_FAIL`。ESP-NOW 数据发送失败可能有几种原因,比如目标设备不存在、设备的信道不相同、动作帧在传输过程中丢失等。应用层并不一定可以总能接收到数据。如果需要,应用层可在接收 ESP-NOW 数据时发回一个应答 (ACK) 数据。如果接收 ACK 数据超时,则将重新传输 ESP-NOW 数据。可以为 ESP-NOW 数据设置序列号,从而删除重复的数据。
74
75如果有大量 ESP-NOW 数据要发送,则调用 ``esp_now_send()`` 一次性发送不大于 250 字节的数据。
76请注意,两个 ESP-NOW 数据包的发送间隔太短可能导致回调函数返回混乱。因此,建议在等到上一次回调函数返回 ACK 后再发送下一个 ESP-NOW 数据。发送回调函数从高优先级的 Wi-Fi 任务中运行。因此,不要在回调函数中执行冗长的操作。相反,将必要的数据发布到队列,并交给优先级较低的任务处理。
77
78接收 ESP-NOW 数据
79----------------------
80
81调用 ``esp_now_register_recv_cb`` 注册接收回调函数。当接收 ESP-NOW 数据时,需要调用接收回调函数。接收回调函数也在 Wi-Fi 任务任务中运行。因此,不要在回调函数中执行冗长的操作。
82相反,将必要的数据发布到队列,并交给优先级较低的任务处理。
83
84API 参考
85-------------
86
87.. include-build-file:: inc/esp_now.inc
88
89