ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

ESP-WIFI-MESH 编程指南:基于 esp-idf 的 Mesh 组网 API 详解与实战

2026/9/18 17:28:14 拓冰建站 浏览量
ESP-WIFI-MESH 编程指南:基于 esp-idf 的 Mesh 组网 API 详解与实战 ESP-WIFI-MESH 编程指南基于 esp-idf 的 Mesh 组网 API 详解与实战【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idfESP-WIFI-MESH 是乐鑫在 ESP-IDF 中提供的一套基于 Wi-Fi 的网状网络Mesh Network协议栈它让大量节点能够自动组网、多跳转发并连接外部路由器。本文以 ESP-WIFI-MESH 编程指南 为主体结合components/esp_wifi/include/esp_mesh.h头文件与 examples/mesh 目录下的官方示例源码系统讲解 ESP-WIFI-MESH 的编程模型、初始化配置流程、自组网机制、数据收发 API 以及官方应用示例。读完本文你将能够独立完成一个 ESP-WIFI-MESH 节点的初始化、组网、事件处理和消息收发。关于 ESP-WIFI-MESH 协议的底层设计细节可进一步阅读 ESP-WIFI-MESH API 指南协议篇。引言ESP-WIFI-MESH 编程指南面向需要在 ESP32 系列芯片上构建网状网络的开发者内容涵盖编程模型、应用编写步骤、自组网行为和 API 参考。其配套协议文档位于 docs/zh_CN/api-guides/esp-wifi-mesh.rst而本文聚焦“如何用代码把 Mesh 跑起来”。ESP-WIFI-MESH 所有公共接口都定义在 components/esp_wifi/include/esp_mesh.h共 1694 行这是理解本指南的最佳源码依据。ESP-WIFI-MESH 编程模型软件栈ESP-WIFI-MESH 软件栈构建在 Wi-Fi 驱动程序和 FreeRTOS 之上某些场景如根节点访问外部网络还会用到 LwIP 软件栈。图中从上到下依次是应用程序Application、ESP-WIFI-MESH 栈、Wi-Fi 驱动Wi-Fi Driver、Wi-Fi MAC/PHY 层以及底层硬件Baseband/RF整个栈运行在 FreeRTOS 之上。从源码结构看Mesh 栈的主体实现位于 components/esp_wifi 组件中公共头文件 esp_mesh.h 通过ESP_EVENT_DECLARE_BASE(MESH_EVENT)声明了独立的 Mesh 事件基与 Wi-Fi 事件WIFI_EVENT和 IP 事件IP_EVENT并行但运行在同一套 esp_event 事件循环之上。系统事件应用程序通过ESP-WIFI-MESH 事件与 Mesh 栈交互同时也可通过Wi-Fi 事件任务与 Wi-Fi 驱动交互。下图为 ESP-WIFI-MESH 应用程序中各类系统事件的交付路径Wi-Fi 驱动把事件投递给 Wi-Fi 事件任务Mesh 栈把事件投递给 Mesh 事件任务两者共同驱动上层应用逻辑。mesh_event_id_t枚举见 esp_mesh.h定义了所有可能的 Mesh 事件涵盖父节点/子节点连接与断开、路由表变化、层数变化、根节点选举等。开发者需通过esp_event_handler_register将Mesh 事件处理程序注册到默认事件循环中注册后即可收到全部相关事件。mesh_event_id_t中的关键事件包括MESH_EVENT_STARTED/MESH_EVENT_STOPPEDMesh 启动/停止。MESH_EVENT_PARENT_CONNECTED/MESH_EVENT_PARENT_DISCONNECTED在 STA 接口上连接/断开父节点。MESH_EVENT_CHILD_CONNECTED/MESH_EVENT_CHILD_DISCONNECTED在 softAP 接口上连接/断开子节点。MESH_EVENT_ROUTING_TABLE_ADD/MESH_EVENT_ROUTING_TABLE_REMOVE路由表因子节点加入/离开而变化。MESH_EVENT_LAYER_CHANGE节点在网络中的层数变化。MESH_EVENT_NO_PARENT_FOUND未找到可连接的父节点。MESH_EVENT_TODS_STATE根节点是否能够访问外部 IP 网络需通过esp_mesh_post_toDS_state()手动触发。MESH_EVENT_VOTE_STARTED/MESH_EVENT_VOTE_STOPPED/MESH_EVENT_ROOT_ADDRESS/MESH_EVENT_ROOT_SWITCH_REQ/MESH_EVENT_ROOT_SWITCH_ACK根节点投票与切换流程。MESH_EVENT_ROOT_ASKED_YIELD当前根被更强的新根要求让位。MESH_EVENT_ROOT_FIXED固定根设置更新。MESH_EVENT_SCAN_DONE禁用自组网后用户调用esp_wifi_scan_start()触发的扫描完成事件。MESH_EVENT_NETWORK_STATE网络状态当前网络是否有根。MESH_EVENT_STOP_RECONNECTION根停止重连路由器、非根设备停止重连父节点。MESH_EVENT_FIND_NETWORK当配置中信道字段为 0 时Mesh 栈执行全信道扫描找到可加入的网络并返回信道值。MESH_EVENT_ROUTER_SWITCH指定路由器 BSSID 后根切换到同 SSID 的另一路由器时上报新路由器信息。MESH_EVENT_PS_PARENT_DUTY/MESH_EVENT_PS_CHILD_DUTY/MESH_EVENT_PS_DEVICE_DUTYMesh 节能PS相关占空比信息。事件所携带的数据统一封装在mesh_event_info_t联合体中见 esp_mesh.h例如MESH_EVENT_PARENT_CONNECTED对应mesh_event_connected_t含父节点信息、自身层数self_layer、父节点 dutyMESH_EVENT_NO_PARENT_FOUND对应mesh_event_no_parent_found_t含扫描次数scan_times。典型事件使用场景用MESH_EVENT_PARENT_CONNECTED和MESH_EVENT_CHILD_CONNECTED判断节点何时可以开始上行/下行数据传输用IP_EVENT_STA_GOT_IP和IP_EVENT_STA_LOST_IP判断根节点何时可以向外部 IP 网络收发数据。警告务必遵守在自组网模式下使用 ESP-WIFI-MESH 时不得调用 Wi-Fi API。自组网模式会在内部调用 Wi-Fi API 完成连接/断开/扫描等操作此时若应用程序包括回调函数和 Wi-Fi 事件处理程序再调用 Wi-Fi API会干扰自组网行为。因此用户不应在esp_mesh_start()与esp_mesh_stop()之间调用 Wi-Fi API。LwIP 与 ESP-WIFI-MESH应用程序可以不经过 LwIP 层直接访问 Mesh 软件栈LwIP 仅在根节点与外部 IP 网络之间收发数据时才使用。但由于每个节点都有可能因自动根节点选择而成为根节点每个节点都必须初始化 LwIP所有可能成为根节点的节点都要调用esp_netif_init()初始化 LwIP为防止非根节点访问 LwIP应用程序不应通过 esp_netif API 创建或注册任何网络接口当一个节点成为根节点时其事件处理程序必须启动 DHCP 客户端服务并立即获取 IP 地址这样其他节点才能开始向/从外部 IP 网络收发数据包若使用静态 IP 设置则无需此步骤。编写 ESP-WIFI-MESH 应用程序ESP-WIFI-MESH 启动前必须先初始化 LwIP 和 Wi-Fi 软件栈。以下代码是 Mesh 开始自身初始化前必须完成的步骤ESP_ERROR_CHECK(esp_netif_init()); /* 事件初始化 */ ESP_ERROR_CHECK(esp_event_loop_create_default()); /* Wi-Fi 初始化 */ wifi_init_config_t config WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(config)); /* 注册 IP 事件处理程序 */ ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, ip_event_handler, NULL)); ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH)); ESP_ERROR_CHECK(esp_wifi_start());完成 LwIP 与 Wi-Fi 初始化后按以下三步启动并运行 Mesh初始化 Meshesp_mesh_init配置 Mesh 网络esp_mesh_set_config启动 Meshesp_mesh_start初始化 Mesh/* Mesh 初始化 */ ESP_ERROR_CHECK(esp_mesh_init()); /* 注册 mesh 事件处理程序 */ ESP_ERROR_CHECK(esp_event_handler_register(MESH_EVENT, ESP_EVENT_ANY_ID, mesh_event_handler, NULL));根据 esp_mesh.h 的注释esp_mesh_init()会检查 Wi-Fi 是否已启动并以默认值初始化 Mesh 全局变量因此必须在esp_wifi_start()之后调用。事件注册使用ESP_EVENT_ANY_ID即可收到全部 Mesh 事件mesh_event_id_t的所有取值在回调内再按event_id分发处理。配置 ESP-WIFI-MESH 网络Mesh 网络通过esp_mesh_set_config()配置参数由mesh_cfg_t结构体承载定义见 esp_mesh.h。该结构体包含以下配置项参数描述Channel信道Mesh 网络所在信道1 到 14设为 0 时 Mesh 栈会执行全信道扫描寻找可加入的网络配合MESH_EVENT_FIND_NETWORK事件allow_channel_switch置位后当重连尝试达到上限时设备会切换为全信道扫描以寻找可加入的网络默认 falseMesh IDESP-WIFI-MESH 网络的标识类型mesh_addr_t6 字节 MAC 地址联合体Router路由器路由器配置类型mesh_router_tMesh APMesh softAP 配置类型mesh_ap_cfg_tCrypto Functions加密函数Mesh IE 的加密函数类型mesh_crypto_funcs_tmesh_router_t字段esp_mesh.hssid32 字节、ssid_len、bssid6 字节、password64 字节以及allow_router_switch。若指定了 BSSID 且allow_router_switch为 true当该 BSSID 的路由器多次连接失败后整个网络允许切换到同 SSID 的另一路由器可能在不同信道默认值为 false。需注意若新路由器密码与旧路由器不同Mesh 网络可能建立成功但根节点永远连不上新路由器。mesh_ap_cfg_t字段esp_mesh.hpasswordMesh softAP 密码64 字节、max_connectionMesh 最大连接数默认 6最大 10、nonmesh_max_connection非 Mesh 连接数。softAP 总可连接数 max_connection nonmesh_max_connection且受 Wi-Fi softAP 最大支持数10限制。默认配置宏MESH_INIT_CONFIG_DEFAULT()esp_mesh.h只设置crypto_funcs g_wifi_default_mesh_crypto_funcs即Mesh IE 默认启用加密其余字段为零值需按下面示例逐项填充/* 默认启用 MESH IE 加密 */ mesh_cfg_t cfg MESH_INIT_CONFIG_DEFAULT(); /* Mesh ID */ memcpy((uint8_t *) cfg.mesh_id, MESH_ID, 6); /* 信道需与路由器信道匹配*/ cfg.channel CONFIG_MESH_CHANNEL; /* 路由器 */ cfg.router.ssid_len strlen(CONFIG_MESH_ROUTER_SSID); memcpy((uint8_t *) cfg.router.ssid, CONFIG_MESH_ROUTER_SSID, cfg.router.ssid_len); memcpy((uint8_t *) cfg.router.password, CONFIG_MESH_ROUTER_PASSWD, strlen(CONFIG_MESH_ROUTER_PASSWD)); /* Mesh softAP */ cfg.mesh_ap.max_connection CONFIG_MESH_AP_CONNECTIONS; memcpy((uint8_t *) cfg.mesh_ap.password, CONFIG_MESH_AP_PASSWD, strlen(CONFIG_MESH_AP_PASSWD)); ESP_ERROR_CHECK(esp_mesh_set_config(cfg));几点来自源码注释的补充说明esp_mesh.hMesh 网络建立在固定信道1–14上Mesh ID 是 MBSS 的标识相同 Mesh ID 的节点才能互相通信Mesh 事件回调是必需的若路由器是隐藏 SSID则router.bssid字段必须填写若未填写 BSSID 且存在多个同 SSID 路由器可能出现多个根连接不同 BSSID、从而建立多个同 Mesh ID 的 Mesh 网络——根冲突root conflict功能只能消除连接同一 BSSID 的冗余根无法处理不同 BSSID 的情况此时需要应用在根节点上自行实现跨网络转发esp_mesh_set_config()必须在esp_mesh_init()之后、esp_mesh_start()之前调用。配置还可通过esp_mesh_get_config()读取并可在运行期用esp_mesh_set_router()/esp_mesh_set_id()动态修改路由器配置与网络 ID。启动 Mesh/* 启动 Mesh */ ESP_ERROR_CHECK(esp_mesh_start());esp_mesh_start()esp_mesh.h会初始化 Mesh IE、启动网络管理服务、按配置创建 TX/RX 队列并注册 Mesh 数据包接收回调。若未初始化或未配置分别返回ESP_ERR_MESH_NOT_INIT、ESP_ERR_MESH_NOT_CONFIG。对应地esp_mesh_stop()esp_mesh.h会反初始化 IE、断开当前父节点、去关联所有子节点、删除队列并将 Wi-Fi 省电模式设为WIFI_PS_NONE。启动后应用应通过 Mesh 事件判断何时入网入网后即可用esp_mesh_send()/esp_mesh_recv()在 Mesh 网络中收发数据包。数据收发 API 要点esp_mesh_send(const mesh_addr_t *to, const mesh_data_t *data, int flag, const mesh_opt_t opt[], int opt_count)esp_mesh.hto为目标地址发给根节点时置NULL发给外部 IP 网络时填IPv4:PORT组合数据先送达根节点根再调用esp_mesh_recv_toDS()转发到最终服务器data为mesh_data_t含data、size、proto、tos字段。单包大小不能超过MESH_MTUproto默认MESH_PROTO_BINtos默认MESH_TOS_P2P点对点可靠重传阻塞式即使带MESH_DATA_NONBLOCK也阻塞MESH_TOS_DEF则为非阻塞flag至少包含MESH_DATA_P2P/MESH_DATA_FROMDS/MESH_DATA_TODS之一以标明方向发给网络内部设备用MESH_DATA_P2P发给根或外部网络用MESH_DATA_TODS根发给内部设备用MESH_DATA_FROMDS根节点切换场景可附加MESH_DATA_DROP允许新根丢弃上行包该 API 不可重入。esp_mesh_recv()esp_mesh.h接收发往自身的数据包from为原始源地址timeout_ms支持 0不等待与portMAX_DELAY永久等待应定期用esp_mesh_get_rx_pending()检查 RX 队列避免内存耗尽。esp_mesh_recv_toDS()esp_mesh.h仅根节点调用接收发往外部 IP 网络的包并通过 socket 转发RX 队列默认大小 32可用esp_mesh_set_xon_qsize()配置最小 16队列过大且不及时读取会占用大量内存过小则影响上行效率。配套工具 APIesp_mesh_get_routing_table()获取本节点子网路由表、esp_mesh_get_routing_table_size()获取子网设备数、esp_mesh_get_total_node_num()获取全网设备数、esp_mesh_get_layer()获取当前层数、esp_mesh_is_root()判断是否根节点、esp_mesh_available_txupQ_num()查询指定地址的上行队列余量等。自组网Self-Organized Networking自组网是 ESP-WIFI-MESH 的核心功能它允许节点自动扫描/选择/连接/重连其他节点与路由器使网络能自主适应动态拓扑和环境变化。启用自组网后节点可自主完成选择或选举根节点协议篇中的自动根节点选择选择首选父节点协议篇中的父节点选择网络断开时自动重新连接协议篇中的中间父节点失败。自组网默认启用见esp_mesh_set_self_organized()注释esp_mesh.h。启用期间 Mesh 栈内部会调用 Wi-Fi API因此应用层不得调用 Wi-Fi API否则会干扰 Mesh 工作。开关自组网运行时可通过esp_mesh_set_self_organized(bool enable, bool select_parent)启用或禁用自组网enable启用或禁用自组网select_parent仅在启用自组网时有效指定是否选择新的父节点作用随节点类型和当前状态而异禁用自组网时该参数不使用。禁用自组网//禁用自组网 esp_mesh_set_self_organized(false, false);禁用时 Mesh 会尽量维持节点当前 Wi-Fi 状态若节点已连接其他节点则保持连接若节点正扫描父节点或路由器则停止扫描若节点正尝试重连父节点或路由器则停止重连。启用自组网//启用自组网并选择一个新的父节点 esp_mesh_set_self_organized(true, true); ... //启用自组网并手动重新连接 esp_mesh_set_self_organized(true, false); esp_mesh_connect();启用时 Mesh 同样会尽量维持节点当前 Wi-Fi 状态但根据节点类型与是否选择新父节点状态可能发生变化见下表是否选择父节点是否为根节点作用NN已连接到父节点的节点将保持连接。之前扫描父节点的节点将停止扫描调用esp_mesh_connect()重新启动。NY已连接到路由器的根节点将保持连接。从路由器断开的根节点需调用esp_mesh_connect()进行重连。YN没有父节点的节点将自动选择首选父节点并连接。已连接到父节点的节点将断开连接重新选择首选父节点并进行重连。YY根节点在连接至父节点前必须放弃“根节点”的角色。因此根节点将断开与路由器和所有子节点的连接选择首选父节点并进行连接。当select_parent为 true 时根节点会放弃根角色、像普通节点一样寻找新父节点这也是根节点让位root switch的一种触发方式更精细的根切换可调用esp_mesh_waive_root()esp_mesh.h通过投票默认 15 次尝试、percentage阈值默认 0.9选举更优根并以最小网络扰动完成切换。若禁用自组网用户需自行用esp_mesh_set_parent()esp_mesh.h为设备指定父节点父节点的 SSID 与信道为必填项若同时指定 BSSID 则必须与 SSID 指向同一父节点。在 Mesh 运行期间调用 Wi-Fi API某些场景下应用希望在使用 Mesh 期间调用 Wi-Fi API例如手动扫描邻近 AP。调用任何 Wi-Fi API 之前必须先禁用自组网否则 Mesh 栈可能同时调用 Wi-Fi API 造成冲突。安全调用esp_wifi_scan_start()的完整流程//禁用自组网 esp_mesh_set_self_organized(0, 0); //停止任何正在进行的扫描 esp_wifi_scan_stop(); //手动启动扫描运行完成时自动停止 esp_wifi_scan_start(); //进程扫描结果 ... //如果仍为连接状态则重新启用自组网 esp_mesh_set_self_organized(1, 0); ... //如果不为根节点且未连接则重新启用自组网 esp_mesh_set_self_organized(1, 1); ... //如果为根节点且未连接则重新启用 esp_mesh_set_self_organized(1, 0); //不选择新的父节点 esp_mesh_connect(); //手动重新连接到路由器需要说明的是esp_mesh_set_self_organized(0, 0)与示例中的(0, 0)写法等价int 隐式转 bool。上述代码展示了三种恢复自组网的情形已连接节点直接恢复非根未连接节点恢复并选择新父节点根节点未连接时恢复但不选父节点、再手动esp_mesh_connect()重连路由器。扫描结果可通过MESH_EVENT_SCAN_DONE事件接收esp_mesh.h配合esp_mesh_scan_get_ap_ie_len()等接口解析 Mesh 网络的 IE 信息。官方应用示例仓库 examples/mesh 目录下提供了三个可直接构建运行的官方示例examples/mesh/internal_communication展示如何使用 Mesh API 建立网络、配置、启动、处理事件并在网络中收发消息。其主程序 mesh_main.c 演示了核心流程初始化 netif 与 Wi-Fi →esp_mesh_init()→ 用MESH_INIT_CONFIG_DEFAULT()配置 Mesh ID、路由器、softAP →esp_mesh_start()。运行后根节点线程esp_mesh_p2p_tx_main通过esp_mesh_get_routing_table()获取全网节点并用esp_mesh_send(route_table[i], data, MESH_DATA_P2P, NULL, 0)向每个节点单播开关灯控制报文mesh_light_ctl_tproto MESH_PROTO_BINtos MESH_TOS_P2P非根节点每 10 秒打印层数mesh_layer与路由表大小。示例还通过Kconfig.projbuild暴露了拓扑选择树形MESH_TOPO_TREE/ 链形MESH_TOPO_CHAIN与 Mesh 省电PS占空比类型等配置选项。examples/mesh/ip_internal_network展示如何使用 Mesh 创建支持 IP 的子网络。所有节点将自身的 IP 与内部 Mesh 层信息发布到 MQTT broker同时进行内部通信。该示例引入了 mesh_netif.c 的自定义 netif 封装mesh 内部 IP 网络和 mqtt_app.c 的 MQTT 应用需要在 idf_component.yml 中声明 MQTT 依赖并借助partitions.csv划分分区。examples/mesh/manual_networking演示如何手动配置 Mesh 网络扫描父节点候选、为节点选择合适的父节点、配置网络参数。这是自组网被禁用的典型场景——应用自己完成父节点选择对应前文esp_mesh_set_parent()与MESH_EVENT_SCAN_DONE的用法适合需要完全掌控拓扑连接关系的场景。三个示例均提供sdkconfig.defaults与README.md其中internal_communication的sdkconfig.ci.esp32c5还展示了针对具体芯片ESP32-C5的 CI 配置方式。构建与烧录方法与 ESP-IDF 标准流程一致在示例目录执行idf.py set-target target、idf.py build、idf.py flash monitor。注意同一 Mesh 网络中所有节点必须使用相同的 Mesh ID 与信道并保持路由器配置一致。API 参考速查mesh_event_id_t、mesh_cfg_t、mesh_router_t、mesh_ap_cfg_t、mesh_crypto_funcs_t、mesh_data_t、mesh_type_t、mesh_tos_t、mesh_proto_t等类型以及上述全部 API 的完整定义与返回值说明均可在 components/esp_wifi/include/esp_mesh.h 中查阅包括 Mesh 错误码ESP_ERR_MESH_*如ESP_ERR_MESH_NO_ROUTE_FOUND、ESP_ERR_MESH_QUEUE_FULL、ESP_ERR_MESH_EXCEED_MTU等与发送标志位MESH_DATA_P2P、MESH_DATA_TODS、MESH_DATA_FROMDS、MESH_DATA_NONBLOCK、MESH_DATA_GROUP等。协议层面的组网细节根选举、父节点选择、路由、节能、网络安全请参阅 docs/zh_CN/api-guides/esp-wifi-mesh.rst。【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考