ESP-ADF wifi_service子模块wifi_ssid_manager详解
版本信息: v2.7-65-gcf908721
本章节分析的源码位于
/components/wifi_service/src/wifi_ssid_manager.c
文件
子模块概览
基本功能与定位
wifi_ssid_manager模块是ESP-ADF中wifi_service组件的重要组成部分,专门负责WiFi网络凭证(SSID和密码)的存储、管理和检索。该模块使用非易失性存储(NVS)来持久化保存多组WiFi网络凭证,并提供智能的网络选择机制,可以根据信号强度或最近使用情况选择最佳WiFi网络进行连接。
这个图展示了wifi_ssid_manager在wifi_service组件中的关键位置:它与esp_wifi_setting模块并列,共同为WiFi服务核心提供支持。esp_wifi_setting负责配网过程,而wifi_ssid_manager则负责配网后的凭证管理。
工作原理
wifi_ssid_manager模块基于ESP-IDF的NVS(非易失性存储)组件实现WiFi凭证的持久化存储和管理,其工作原理如下:
- 存储结构设计:采用两个独立的NVS命名空间来分别存储配置信息和WiFi凭证
- 配置管理:记录最大SSID数量、已保存SSID数量和最新SSID索引
- 凭证存储:为每个WiFi凭证分配唯一标识符,保存SSID、密码和使用计数
- 智能选择:通过扫描周围网络并与已保存凭证比较,选择信号最强的网络
- 自动更新:在保存新的WiFi凭证时更新配置信息,确保数据一致性
核心特性
- 多网络管理:支持存储多组WiFi凭证,便于设备在不同网络环境中使用
- 智能连接:根据信号强度智能选择最佳网络进行连接
- 存储优化:采用先进先出(FIFO)或使用频率策略管理有限的存储空间
- 安全存储:利用NVS加密特性保护WiFi凭证安全
- 易于集成:提供简洁API,易于与wifi_service和其他组件集成
- 完整生命周期管理:提供创建、保存、检索、显示和销毁等全生命周期管理API
内部实现
数据结构与定义
/**
* @breif Configuration of ssid manager
*/
typedef struct {
uint8_t max_ssid_num; /*!< 可存储的SSID最大数量 */
uint8_t exsit_ssid_num; /*!< 当前已存在的SSID数量 */
uint8_t latest_ssid; /*!< 最近存储的SSID索引 */
} nvs_ssid_conf_t;
/**
* @brief Information for every ssid saved in flash
*/
typedef struct {
bool choosen; /*!< 是否选择该SSID进行连接 */
int cnt; /*!< 存储时间指示器,用于FIFO替换策略 */
char ssid[WIFI_SSID_MAX_LENGTH]; /*!< 保存的SSID */
char pwd[WIFI_PWD_MAX_LENGTH]; /*!< 保存的密码 */
} nvs_stored_info_t;
/**
* @breif Management unit of wifi ssid
*/
struct wifi_ssid_manager {
esp_dispatcher_handle_t dispatcher; /*!< 分发器句柄,用于运行NVS操作 */
nvs_handle conf_nvs; /*!< NVS句柄,保存SSID管理器配置 */
nvs_handle info_nvs; /*!< NVS句柄,保存WiFi凭证信息 */
};
存储结构设计
wifi_ssid_manager使用两个独立的NVS命名空间来组织数据:
- WIFI_CONF_NVS_NAMESPACE:用于存储整体配置信息(nvs_ssid_conf_t)
- WIFI_INFO_NVS_NAMESPACE:用于存储各个WiFi网络的详细信息(nvs_stored_info_t)
这种设计将配置元数据与实际WiFi凭证分离,提高了数据管理的灵活性和安全性。每个WiFi凭证以键值对形式存储,键名为“KEY0”、“KEY1”等递增序号。
公开接口
以下接口定义来自
/components/wifi_service/include/wifi_ssid_manager.h
数据类型与结构体
/**
* @brief WiFi SSID管理器句柄类型
*/
typedef struct wifi_ssid_manager *wifi_ssid_manager_handle_t;
公开函数
1. wifi_ssid_manager_create
/**
* @brief 创建WiFi SSID管理器实例
*
* 该函数用于创建一个新的WiFi SSID管理器实例,分配必要的内存资源,
* 并初始化NVS存储。指定可存储的最大SSID数量。
*
* @param max_ssid_num 可存储的最大SSID数量
*
* @return
* - NULL,失败
* - 其他,成功,返回wifi_ssid_manager_handle_t实例
*/
wifi_ssid_manager_handle_t wifi_ssid_manager_create(uint8_t max_ssid_num);
2. wifi_ssid_manager_get_latest_config
/**
* @brief 获取最新保存的WiFi配置
*
* 该函数用于获取用户最近一次通过wifi_ssid_manager_save函数保存的
* WiFi配置信息,通常用于快速连接最近使用的网络。
*
* @param handle WiFi SSID管理器实例
* @param config[out] 输出参数,用于保存获取到的WiFi配置
*
* @return
* - ESP_FAIL,失败
* - ESP_OK,成功
*/
esp_err_t wifi_ssid_manager_get_latest_config(wifi_ssid_manager_handle_t handle, wifi_config_t *config);
3. wifi_ssid_manager_save
/**
* @brief 保存WiFi SSID和密码到Flash
*
* 该函数将WiFi的SSID和密码保存到Flash中,如果存储已满,
* 会使用先进先出(FIFO)策略替换最早保存的WiFi信息。
* 如果SSID已存在,会更新对应的密码。
*
* @param handle WiFi SSID管理器实例
* @param ssid 要保存的WiFi SSID
* @param pwd 要保存的WiFi密码
*
* @return
* - ESP_FAIL,失败
* - ESP_OK,成功
*/
esp_err_t wifi_ssid_manager_save(wifi_ssid_manager_handle_t handle, const char *ssid, const char *pwd);
4. wifi_ssid_manager_get_best_config
/**
* @brief 获取最佳WiFi配置(基于信号强度)
*
* 该函数会扫描周围的WiFi网络,并与已保存的WiFi信息比较,
* 选择信号最强的且已保存密码的网络作为最佳配置返回。
* 需要注意的是,该函数会触发WiFi扫描过程,可能需要一定时间完成。
*
* @param handle WiFi SSID管理器实例
* @param config[out] 输出参数,用于保存获取到的最佳WiFi配置
*
* @return
* - ESP_FAIL,失败
* - ESP_OK,成功
*/
esp_err_t wifi_ssid_manager_get_best_config(wifi_ssid_manager_handle_t handle, wifi_config_t *config);
5. wifi_ssid_manager_get_ssid_num
/**
* @brief 获取已保存的SSID数量
*
* 该函数返回当前已保存在WiFi SSID管理器中的SSID数量。
*
* @param handle WiFi SSID管理器实例
*
* @return
* - ESP_FAIL,失败
* - 其他,成功,返回已保存的SSID数量
*/
int wifi_ssid_manager_get_ssid_num(wifi_ssid_manager_handle_t handle);
6. wifi_ssid_manager_list_show
/**
* @brief 显示已保存的SSID和密码列表
*
* 该函数用于调试目的,将已保存在Flash中的所有SSID和密码
* 通过ESP_LOGI打印到日志输出中。
*
* @param handle WiFi SSID管理器实例
*
* @return
* - ESP_FAIL,失败
* - ESP_OK,成功
*/
esp_err_t wifi_ssid_manager_list_show(wifi_ssid_manager_handle_t handle);
7. wifi_ssid_manager_erase_all
/**
* @brief 擦除所有保存在Flash中的SSID
*
* 该函数用于清除WiFi SSID管理器中保存的所有WiFi凭证。
* 它会擦除两个NVS命名空间中的所有数据。
*
* @param handle WiFi SSID管理器实例
*
* @return
* - ESP_FAIL,失败
* - ESP_OK,成功
*/
esp_err_t wifi_ssid_manager_erase_all(wifi_ssid_manager_handle_t handle);
8. wifi_ssid_manager_destroy
/**
* @brief 销毁WiFi SSID管理器
*
* 该函数用于销毁WiFi SSID管理器实例,释放相关的内存资源。
* 在不再需要WiFi SSID管理时,应调用此函数进行资源清理。
*
* @param handle WiFi SSID管理器实例
*
* @return
* - ESP_FAIL,失败
* - ESP_OK,成功
*/
esp_err_t wifi_ssid_manager_destroy(wifi_ssid_manager_handle_t handle);
核心流程分析
SSID管理器创建流程
保存WiFi凭证流程
获取最佳配置流程
应用示例
基本使用示例
以下是一个使用wifi_ssid_manager的基本示例,展示了如何创建管理器、保存WiFi凭证、获取最佳配置和销毁管理器:
#include "esp_log.h"
#include "wifi_ssid_manager.h"
static const char *TAG = "SSID_MANAGER_EXAMPLE";
void app_main()
{
// 步骤1: 创建WiFi SSID管理器,最多保存5个SSID
wifi_ssid_manager_handle_t ssid_manager = wifi_ssid_manager_create(5);
if (ssid_manager == NULL) {
ESP_LOGE(TAG, "无法创建WiFi SSID管理器");
return;
}
// 步骤2: 保存多个WiFi凭证
ESP_LOGI(TAG, "保存家庭端WiFi凭证");
esp_err_t ret = wifi_ssid_manager_save(ssid_manager, "Home_WiFi", "home_password");
if (ret != ESP_OK) {
ESP_LOGE(TAG, "保存Home_WiFi失败");
}
ESP_LOGI(TAG, "保存办公室WiFi凭证");
ret = wifi_ssid_manager_save(ssid_manager, "Office_WiFi", "office_password");
if (ret != ESP_OK) {
ESP_LOGE(TAG, "保存Office_WiFi失败");
}
// 步骤3: 显示已保存的WiFi凭证
ESP_LOGI(TAG, "显示所有保存的WiFi凭证:");
wifi_ssid_manager_list_show(ssid_manager);
// 步骤4: 获取最佳WiFi配置
wifi_config_t best_config;
ret = wifi_ssid_manager_get_best_config(ssid_manager, &best_config);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "找到最佳WiFi: %s", best_config.sta.ssid);
// 使用best_config进行WiFi连接...
} else {
ESP_LOGW(TAG, "未找到匹配的WiFi网络");
// 步骤5: 如果没有找到最佳配置,使用最新配置
ret = wifi_ssid_manager_get_latest_config(ssid_manager, &best_config);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "使用最新保存的WiFi: %s", best_config.sta.ssid);
// 使用best_config进行WiFi连接...
}
}
// 步骤6: 清理资源
wifi_ssid_manager_destroy(ssid_manager);
}
与WiFi服务集成示例
以下示例展示了如何将wifi_ssid_manager与wifi_service集成使用:
#include "esp_log.h"
#include "audio_element.h"
#include "periph_service.h"
#include "wifi_service.h"
#include "smart_config.h"
#include "wifi_ssid_manager.h"
static const char *TAG = "WIFI_SERVICE_EXAMPLE";
// WiFi事件回调函数
static esp_err_t wifi_service_cb(periph_service_handle_t handle, periph_service_event_t *evt, void *ctx)
{
wifi_ssid_manager_handle_t ssid_manager = (wifi_ssid_manager_handle_t)ctx;
if (evt->type == WIFI_SERV_EVENT_CONNECTED) {
ESP_LOGI(TAG, "WiFi已连接");
// 获取当前连接的WiFi信息
wifi_ap_record_t ap_info;
esp_wifi_sta_get_ap_info(&ap_info);
// 保存成功连接的WiFi凭证
wifi_config_t wifi_cfg;
esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg);
ESP_LOGI(TAG, "保存成功连接的WiFi: %s", ap_info.ssid);
wifi_ssid_manager_save(ssid_manager, (char *)wifi_cfg.sta.ssid, (char *)wifi_cfg.sta.password);
} else if (evt->type == WIFI_SERV_EVENT_DISCONNECTED) {
ESP_LOGW(TAG, "WiFi已断开");
} else if (evt->type == WIFI_SERV_EVENT_SETTING_FINISHED) {
ESP_LOGI(TAG, "WiFi配网成功完成");
}
return ESP_OK;
}
void app_main()
{
// 步骤1: 创建WiFi SSID管理器
wifi_ssid_manager_handle_t ssid_manager = wifi_ssid_manager_create(10);
if (ssid_manager == NULL) {
ESP_LOGE(TAG, "无法创建WiFi SSID管理器");
return;
}
// 步骤2: 创建WiFi服务
wifi_service_config_t wifi_cfg = WIFI_SERVICE_DEFAULT_CONFIG();
wifi_cfg.evt_cb = wifi_service_cb;
wifi_cfg.cb_ctx = ssid_manager; // 传递SSID管理器作为上下文
wifi_cfg.setting_timeout_s = 60;
periph_service_handle_t wifi_handle = wifi_service_create(&wifi_cfg);
if (wifi_handle == NULL) {
ESP_LOGE(TAG, "无法创建WiFi服务");
wifi_ssid_manager_destroy(ssid_manager);
return;
}
// 步骤3: 尝试加载最佳WiFi配置
wifi_config_t best_config;
if (wifi_ssid_manager_get_best_config(ssid_manager, &best_config) == ESP_OK) {
ESP_LOGI(TAG, "找到最佳WiFi: %s,尝试连接", best_config.sta.ssid);
// 使用找到的最佳配置设置WiFi
esp_wifi_set_config(WIFI_IF_STA, &best_config);
esp_wifi_connect();
} else if (wifi_ssid_manager_get_latest_config(ssid_manager, &best_config) == ESP_OK) {
ESP_LOGI(TAG, "使用最新保存的WiFi: %s,尝试连接", best_config.sta.ssid);
// 使用最新保存的配置设置WiFi
esp_wifi_set_config(WIFI_IF_STA, &best_config);
esp_wifi_connect();
} else {
// 步骤4: 如果没有保存的配置,启动配网
ESP_LOGI(TAG, "没有找到已保存的WiFi,启动配网流程");
smart_config_config_t sc_cfg = SMART_CONFIG_DEFAULT_CONFIG();
esp_wifi_setting_handle_t sc_handle = smart_config_create(&sc_cfg);
int setting_index = 0;
wifi_service_register_setting_handle(wifi_handle, sc_handle, &setting_index);
wifi_service_setting_start(wifi_handle, setting_index);
}
// 应用程序主循环...
}
接口总结
概述
ESP-ADF的wifi_ssid_manager模块提供了一种高效管理多个WiFi网络凭证的解决方案,具有以下技术特点:
- 持久化存储:利用NVS存储WiFi凭证,支持设备重启后恢复
- 多网络管理:支持存储和管理多个WiFi网络的凭证
- 智能选择:基于信号强度选择最佳网络连接
- 资源管理:提供完整的生命周期管理,避免资源泄漏
- 存储优化:采用FIFO策略管理有限的存储空间
- 调试支持:提供便捷的列表显示功能,便于调试
函数分类
根据功能,wifi_ssid_manager模块的公开函数可以分为以下几类:
1. 生命周期管理函数
函数名 | 功能描述 |
---|---|
wifi_ssid_manager_create | 创建WiFi SSID管理器实例 |
wifi_ssid_manager_destroy | 销毁WiFi SSID管理器实例 |
2. 凭证管理函数
函数名 | 功能描述 |
---|---|
wifi_ssid_manager_save | 保存WiFi SSID和密码 |
wifi_ssid_manager_erase_all | 擦除所有保存的SSID |
3. 凭证检索函数
函数名 | 功能描述 |
---|---|
wifi_ssid_manager_get_latest_config | 获取最新保存的WiFi配置 |
wifi_ssid_manager_get_best_config | 获取最佳WiFi配置(基于信号强度) |
4. 状态和调试函数
函数名 | 功能描述 |
---|---|
wifi_ssid_manager_get_ssid_num | 获取已保存的SSID数量 |
wifi_ssid_manager_list_show | 显示已保存的SSID和密码列表 |
使用场景
wifi_ssid_manager模块适用于以下场景:
- 多环境部署:设备需要在多个WiFi环境中工作(如家庭、办公室、公共场所等)
- 自动选网:需要自动选择最佳网络进行连接的应用
- 记忆连接:需要记忆曾经连接过的网络以便快速重连
- 备份恢复:配网信息需要持久化保存,避免设备重启后丢失
- 智能家居:智能家居设备需要在不同环境中灵活连接不同网络
与其他模块的关系
wifi_ssid_manager模块在ESP-ADF中主要与以下模块协同工作:
- 与wifi_service的关系:提供WiFi凭证的存储和检索服务,支持WiFi连接管理
- 与esp_wifi_setting的关系:esp_wifi_setting负责配网获取凭证,wifi_ssid_manager负责存储这些凭证
- 与NVS的关系:依赖NVS组件实现数据持久化存储
- 与esp_wifi的关系:提供WiFi配置信息,支持esp_wifi进行网络连接
通过这种模块化设计,ESP-ADF实现了WiFi凭证管理的高效存储、智能选择和完整生命周期管理,大大简化了开发者在多网络环境下的WiFi连接管理工作。