文章目录
- 一、smartconfig一句话简介
- 二、esp32 nvs_flash
- 我在编写存储wifi配置信息用到这几个API函数,在此列出,其他函数可以到乐鑫官网学习
- **(1)** nvs_flash 初始化
- esp_err_t nvs_flash_init(void);
- (2)从已创建NVS分区打开具有给定名称空间的非易失性存储空间
- esp_err_t nvs_open(const char *name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle);
- (3)为给定的键设置可变长度的二进制值
- **esp_err_t nvs_set_blob(nvs_handle_t handle, const char *key, const void *value, size_t length)**
- (4)将任何挂起的更改写入非易失性存储。
- esp_err_t nvs_commit(nvs_handle_t handle)
- (5)关闭存储句柄并释放所有分配的资源
- void nvs_close(nvs_handle_t handle)
- 二、esp32 smartconfig 源码
- (1)wifi 初始化(这段代码要配合event_handler 一起看,不然不太好理解)
- (2)event_handler wifi回调函数 (smartconfig 过程中将会执行三次
一、smartconfig一句话简介
esp-idf v4.0框架 smartconfig wifi配置信息保存在nvs_flash
smartconfig又称为快连,可以通过一键配置设备连入wifi,esp-idf已经有smartconfig demo 通过手机端ESPTOUCH就可以快速实现设备入网。
二、esp32 nvs_flash
我在编写存储wifi配置信息用到这几个API函数,在此列出,其他函数可以到乐鑫官网学习
(1) nvs_flash 初始化
**
esp_err_t nvs_flash_init(void);
**
初始化默认的NVS分区。
这个API初始化默认的NVS分区。默认的NVS分区是分区表中标记为“NVS”的分区。
调用时将会return一下三种返回值
Return
ESP_OK nvs成功初始化
ESP_ERR_NVS_NO_FREE_PAGES NVS存储不包含空页(如果NVS分区被截断,可能会发生这种情况)
ESP_ERR_NOT_FOUND 在分区表中没有找到带有“nvs”标签的分区
(2)从已创建NVS分区打开具有给定名称空间的非易失性存储空间
**
esp_err_t nvs_open(const char *name, nvs_open_mode_t open_mode, nvs_handle_t *out_handle);
**
多个内部ESP-IDF和第三方应用程序模块可以将它们的键值对存储在NVS模块中。为了减少键名上可能出现的冲突,每个模块都可以使用自己的名称空间。默认的NVS分区是分区表中标记为“NVS”的分区。
调用时将会return一下五种返回值
Return
ESP_OK 成功打开存储句柄
ESP_ERR_NVS_NOT_INITIALIZED 存储驱动程序没有初始化
ESP_ERR_NVS_PART_NOT_FOUND 存储驱动程序没有初始化
ESP_ERR_NVS_NOT_FOUND id名称空间尚不存在,模式为NVS只读
ESP_ERR_NVS_INVALID_NAME 名称空间名称不满足约束,则来自底层存储驱动程序的其他错误代码
(3)为给定的键设置可变长度的二进制值
**esp_err_t nvs_set_blob(nvs_handle_t handle, const char key, const void value, size_t length)
根据键的名称,这个函数族为键设置值。注意,在调用nvs提交函数之前,不会更新实际的存储。
调用时将会return一下七种返回值
Return
ESP_OK 设置成功
ESP_ERR_NVS_INVALID_HANDLE 句柄关闭或者为空
ESP_ERR_NVS_READ_ONLY 存储空间句柄已经被打开,或者被设置为只读
ESP_ERR_NVS_INVALID_NAME 键名不满足约束
ESP_ERR_NVS_NOT_ENOUGH_SPACE 底层存储中没有足够的空间来保存该值
ESP_ERR_NVS_REMOVE_FAILED 值没有更新是因为flash写操作失败。然而,该值是写入的,更新将在重新初始化nvs后完成,前提是flash操作不会再次失败
ESP_ERR_NVS_VALUE_TOO_LONG 值设置太长
(4)将任何挂起的更改写入非易失性存储。
**
esp_err_t nvs_commit(nvs_handle_t handle)
**
在设置任何值之后,必须调用nvs commit()来确保将更改写入非易失性存储。个别实现可能在其他时间写入存储器,但这并不能保证。
调用时将会return一下两种返回值
Return
ESP_OK 写入成功
ESP_ERR_NVS_INVALID_HANDLE 操作句柄被关闭或者为空
(5)关闭存储句柄并释放所有分配的资源
**
void nvs_close(nvs_handle_t handle)
**
当句柄不再使用时,nvs打开的每个句柄都应该调用这个函数。关闭句柄可能不会自动将更改写入非易失性存储。这必须使用nvs提交函数显式地完成。一旦在句柄上调用此函数,就不应该再使用该句柄。
二、esp32 smartconfig 源码
(1)wifi 初始化(这段代码要配合event_handler 一起看,不然不太好理解)
/*初始化 wifi*/
static void initialise_wifi(void)
{
wifi_event_group = xEventGroupCreate();//创建一个事件组 smartconfig 事件组
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());//创建一个事件组 从外部flash读取wifi配置信息 事件组
ESP_ERROR_CHECK(esp_event_loop_create_default());//wifi事件
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );//wifi初始化
ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) ); //获取链接信息 注意这句话回调到event_handler 往下看event_handler函数里面的对是否是第一次配网的判断
ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );//获取链接信息
if(wifi_flag!=1)ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) ); //获取链接信息 外部flash无配置信息,进行smartconfig相关配置
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );//设置模式
if(wifi_flag==1){//flash内有配置信息
nvs_handle handle;
static const char *NVS_CUSTOMER = "customer data";
static const char *DATA1 = "param 1";
wifi_config_t wifi_config_stored;
memset(&wifi_config_stored, 0x0, sizeof(wifi_config_stored));
uint32_t len = sizeof(wifi_config_stored);
ESP_ERROR_CHECK( nvs_open(NVS_CUSTOMER, NVS_READWRITE, &handle) );
ESP_ERROR_CHECK ( nvs_get_blob(handle, DATA1, &wifi_config_stored, &len) );
nvs_close(handle);
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config_stored) );
wifi_flag=1;}
ESP_ERROR_CHECK( esp_wifi_start() );//启动wifi
/*以下为相关配置,不过多讲解了*/
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
ESP_LOGI(TAG, "wifi_init_sta finished.");
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
* happened. */
if (bits & WIFI_CONNECTED_BIT) {
// ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
// EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
} else if (bits & WIFI_FAIL_BIT) {
// ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
// EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
} else {
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler));
ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler));
xTaskCreate(&adc1_get_data_task, "adc1_get_data_task", 8192, NULL, 5, NULL);//创建adc1采集任务
vEventGroupDelete(s_wifi_event_group);
}
(2)event_handler wifi回调函数 (smartconfig 过程中将会执行三次
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{ nvs_handle handle;//定义nv_flash 操作句柄
esp_err_t err;//一个esp_err_t变量
static const char *NVS_CUSTOMER = "customer data";
static const char *DATA1 = "param 1";
wifi_config_t wifi_config_stored;
memset(&wifi_config_stored, 0x0, sizeof(wifi_config_stored));//结构体变量wifi_config_stored,所有变量初始化为 0
uint32_t len = sizeof(wifi_config_stored);
// Open
err =nvs_open(NVS_CUSTOMER, NVS_READWRITE, &handle);//尝试打开外部flash 读取wifi配置信息
if (err != ESP_OK) return err;
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {//第一步执行
err = nvs_get_blob(handle, DATA1, &wifi_config_stored, &len);//读取wifi配置信息
if (err == ESP_ERR_NVS_NOT_FOUND) //读取失败
{wifi_flag=0;// wifi_flag清零,注意这句,很重要,决定是重新通过smartconfig 配网,还是通过从flash读取的信息进行配网
xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);//如果读取失败,创建smartconfig任务,通过esptouch配网
}
else if(err == ESP_OK)//读取成功
{wifi_flag=1;//读取成功wifi_flag=1;
esp_wifi_connect();
nvs_close(handle);//关闭nvs操作句柄
}
//创建smartconfig任务
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if(wifi_flag==1)
{
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {//如果未连上,尝试重新链接
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); }//尝试EXAMPLE_ESP_MAXIMUM_RETRY次后,仍未链接成功,将清除nvs_flash所有信息
/****************清除nvs_flash*************/
ESP_ERROR_CHECK( nvs_open( NVS_CUSTOMER, NVS_READWRITE, &handle) );
ESP_ERROR_CHECK( nvs_erase_key(handle,DATA1));
usleep(5000*1000);
ESP_ERROR_CHECK( nvs_erase_all(handle));
usleep(5000*1000);
ESP_ERROR_CHECK( nvs_commit(handle) );
nvs_close(handle);
esp_restart();//重新启动esp32,等待重新配网
ESP_LOGI(TAG,"connect to the AP fail");
}else{//断线重连
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);//清除标志位
}
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {//获取到wifi信息后,执行, 第七步
if(wifi_flag==1)
{
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG2, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}else{
//sta链接成功,set事件组
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);}
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {//等待配网 第四步,等待手机配网
ESP_LOGI(TAG1, "Scan done");
} else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {//扫描信道 第五步,找到udp广播
ESP_LOGI(TAG1, "Found channel");
} else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) { //获取到ssid和密码 第六步,获取 wifi信息
ESP_LOGI(TAG1, "Got SSID and password");
smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
wifi_config_t wifi_config;
uint8_t ssid[33] = { 0 };
uint8_t password[65] = { 0 };
bzero(&wifi_config, sizeof(wifi_config_t));
memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
wifi_config.sta.bssid_set = evt->bssid_set;
if (wifi_config.sta.bssid_set == true) {
memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
}
memcpy(ssid, evt->ssid, sizeof(evt->ssid));
memcpy(password, evt->password, sizeof(evt->password));
//打印账号密码
ESP_LOGI(TAG1, "SSID:%s", ssid);
ESP_LOGI(TAG1, "PASSWORD:%s", password);
//断开默认的
ESP_ERROR_CHECK( esp_wifi_disconnect() );
//设置获取的ap和密码到寄存器
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
//将获取的密码保存起来 nvs_flash
ESP_ERROR_CHECK( nvs_open( NVS_CUSTOMER, NVS_READWRITE, &handle) );//打开新的nvs_flash
ESP_ERROR_CHECK( nvs_set_blob( handle, DATA1, &wifi_config, sizeof(wifi_config)) );//将smartconfig获取到的wifi配置信息保存到外部flash
ESP_ERROR_CHECK( nvs_commit(handle) );//提交保存信息
nvs_close(handle);
/****************清除nvs_flash*************/
/* ESP_ERROR_CHECK( nvs_open( NVS_CUSTOMER, NVS_READWRITE, &handle) );
ESP_ERROR_CHECK( nvs_erase_key(handle,DATA1));
ESP_ERROR_CHECK( nvs_erase_all(handle));
ESP_ERROR_CHECK( nvs_commit(handle) );
nvs_close(handle);*/
//连接获取的ssid和密码
ESP_ERROR_CHECK( esp_wifi_connect() );
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {
xEventGroupSetBits(wifi_event_group, ESPTOUCH_DONE_BIT);
}
}
以上就是全部内容,如有错误希望各位留言,谢谢各位