ESP-ADF wifi_service子模块wifi_ssid_manager详解

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_service组件架构
esp_wifi_setting
(配网接口抽象层)
wifi_service
(WiFi服务核心)
wifi_ssid_manager
(SSID管理器)
smart_config
(ESP Touch配网)
blufi_config
(蓝牙配网)
airkiss_config
(微信配网)
softap_config
(软AP配网)
NVS存储
(永久保存WiFi信息)
智能选择
(最佳网络选择算法)

这个图展示了wifi_ssid_manager在wifi_service组件中的关键位置:它与esp_wifi_setting模块并列,共同为WiFi服务核心提供支持。esp_wifi_setting负责配网过程,而wifi_ssid_manager则负责配网后的凭证管理。

工作原理

wifi_ssid_manager模块基于ESP-IDF的NVS(非易失性存储)组件实现WiFi凭证的持久化存储和管理,其工作原理如下:

  1. 存储结构设计:采用两个独立的NVS命名空间来分别存储配置信息和WiFi凭证
  2. 配置管理:记录最大SSID数量、已保存SSID数量和最新SSID索引
  3. 凭证存储:为每个WiFi凭证分配唯一标识符,保存SSID、密码和使用计数
  4. 智能选择:通过扫描周围网络并与已保存凭证比较,选择信号最强的网络
  5. 自动更新:在保存新的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命名空间来组织数据:

  1. WIFI_CONF_NVS_NAMESPACE:用于存储整体配置信息(nvs_ssid_conf_t)
  2. 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_ssid_manager_create(max_ssid_num)
分配wifi_ssid_manager结构体内存
创建NVS分发器
初始化NVS存储
打开WIFI_CONF_NVS和WIFI_INFO_NVS两个命名空间
检查配置是否存在
创建初始配置
max_ssid_num=输入值
exsit_ssid_num=0
latest_ssid=0xFF
加载现有配置
保存配置到NVS
返回wifi_ssid_manager_handle_t实例

保存WiFi凭证流程

已存在
不存在
调用wifi_ssid_manager_save(handle, ssid, pwd)
获取当前管理器配置
检查SSID是否已存在
更新现有SSID的密码
已达到最大SSID数?
使用FIFO策略
找到最早保存的条目
使用exsit_ssid_num
作为新条目索引
准备保存新凭证
更新计数器和状态标记
设置choosen=false
保存WiFi凭证到NVS
更新latest_ssid指向新条目
更新并保存管理器配置
返回ESP_OK

获取最佳配置流程

调用wifi_ssid_manager_get_best_config(handle, config)
获取管理器配置
检查是否有保存的SSID
返回ESP_FAIL
启动WiFi扫描
等待扫描完成
获取扫描结果
重置已保存SSID的choosen标记
遍历扫描结果和保存的SSID比较
找出共同的且信号最强的SSID
是否找到匹配?
将最佳SSID标记为choosen
构建WiFi配置并返回
返回ESP_OK

应用示例

基本使用示例

以下是一个使用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网络凭证的解决方案,具有以下技术特点:

  1. 持久化存储:利用NVS存储WiFi凭证,支持设备重启后恢复
  2. 多网络管理:支持存储和管理多个WiFi网络的凭证
  3. 智能选择:基于信号强度选择最佳网络连接
  4. 资源管理:提供完整的生命周期管理,避免资源泄漏
  5. 存储优化:采用FIFO策略管理有限的存储空间
  6. 调试支持:提供便捷的列表显示功能,便于调试

函数分类

根据功能,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模块适用于以下场景:

  1. 多环境部署:设备需要在多个WiFi环境中工作(如家庭、办公室、公共场所等)
  2. 自动选网:需要自动选择最佳网络进行连接的应用
  3. 记忆连接:需要记忆曾经连接过的网络以便快速重连
  4. 备份恢复:配网信息需要持久化保存,避免设备重启后丢失
  5. 智能家居:智能家居设备需要在不同环境中灵活连接不同网络

与其他模块的关系

wifi_ssid_manager模块在ESP-ADF中主要与以下模块协同工作:

  1. 与wifi_service的关系:提供WiFi凭证的存储和检索服务,支持WiFi连接管理
  2. 与esp_wifi_setting的关系:esp_wifi_setting负责配网获取凭证,wifi_ssid_manager负责存储这些凭证
  3. 与NVS的关系:依赖NVS组件实现数据持久化存储
  4. 与esp_wifi的关系:提供WiFi配置信息,支持esp_wifi进行网络连接

通过这种模块化设计,ESP-ADF实现了WiFi凭证管理的高效存储、智能选择和完整生命周期管理,大大简化了开发者在多网络环境下的WiFi连接管理工作。

当在运行命令`npm install`时,可能会遇到错误信息"Command failed",具体错误信息可能是`node-sass: Command failed.`。这个错误通常与`node-sass`模块有关。根据引用中的解决方法,你可以尝试执行以下命令来解决这个问题1. 首先,运行命令`npm uninstall node-sass`,这将卸载当前安装的`node-sass`模块。 2. 然后,运行命令`npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/`,这将重新安装`node-sass`模块,并使用淘宝镜像加速下载。 3. 最后,运行命令`npm install`,这将重新安装所有依赖。 通过执行上述命令,你可以尝试解决`node-sass: Command failed`错误。希望对你有帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [安装vue项目依赖 node_modules目录 npm install (npm i) 时报错:ERR ***\node_modules\node-sass command ...](https://blog.csdn.net/weixin_45417815/article/details/121977354)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [package.json 封装 vue模块_vue仿小米商城 -- 我知道的都在这里了](https://blog.csdn.net/weixin_39521651/article/details/109916394)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

omnibots

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值