一、SmartConfig配网
- SmartConfig配网,这是由TI研发的一种配网方式,手机发出一组特殊长度编码的带WIFI信息的UDP包,设备循环在每一个通道上监听UDP包,当监听到符合长度规则的UDP包时,获取UDP包中的SSID和Password,然后配置WIFI芯片为STA模式去连接WIFI,如果没有监听到UDP包则切换至下一个通道,如此往复。
本文通过调用ESP32-IDF的smartconfig模块,模块协议使用AirKiss,参考ESP历程:examples/wifi/smart_config
二、具体过程
1、初始化WIFI协议栈
- 初始化WIFI配置,设定WIFI为STA模式,配置使用默认配置
- 绑定事件回调,将WIFI的全部事件、获取到IP事件与smartconfig的全部事件绑定到回调函数中
static void initialise_wifi(void)
{
ESP_ERROR_CHECK(esp_netif_init());
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_create_default());
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) );
ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
2、设置smartconfig
- 设定Smartconfig的模式,协议使用AirKiss,其他默认
static void smartconfig_example_task(void * parm)
{
EventBits_t uxBits;
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS) );
smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) );
while (1) {
uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY);
if(uxBits & CONNECTED_BIT) {
ESP_LOGI(TAG, "WiFi Connected to ap");
}
if(uxBits & ESPTOUCH_DONE_BIT) {
ESP_LOGI(TAG, "smartconfig over");
esp_smartconfig_stop();
vTaskDelete(NULL);
}
}
}
3、掉电存储
- 在第一次成功配网时,将Wifi的数据保存至Flash中,后续上电时,检测是否有wifi信息,如果有wifi信息则直接读取wifi信息进行连接,如果没有wifi信息,则开启Smartconfig配网
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
ESP_LOGI(TAG, "STA start ");
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
esp_wifi_connect();
xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {
ESP_LOGI(TAG, "Scan done");
} else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {
ESP_LOGI(TAG, "Found channel");
}
//在成功获取WiFi信息事件的回调处理中,将wifi信息保存至flash中
else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {
ESP_LOGI(TAG, "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 };
uint8_t rvd_data[33] = { 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(TAG, "SSID:%s", ssid);
ESP_LOGI(TAG, "PASSWORD:%s", password);
/* save wifi info to flash */
ESP_ERROR_CHECK(nvs_open("wifi_info",NVS_READWRITE,&Set_Wifi_handle));
ESP_ERROR_CHECK(nvs_set_str(Set_Wifi_handle,"wifi_ssid",(const char*)ssid));
ESP_ERROR_CHECK(nvs_set_str(Set_Wifi_handle,"wifi_pswd",(const char*)password));
ESP_ERROR_CHECK(nvs_set_u8(Set_Wifi_handle,"wifi_info_flag",wifi_configed));
ESP_ERROR_CHECK(nvs_commit(Set_Wifi_handle));
nvs_close(Set_Wifi_handle);
if (evt->type == SC_TYPE_ESPTOUCH_V2) {
ESP_ERROR_CHECK( esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)) );
ESP_LOGI(TAG, "RVD_DATA:");
for (int i=0; i<33; i++) {
printf("%02x ", rvd_data[i]);
}
printf("\n");
}
ESP_ERROR_CHECK( esp_wifi_disconnect() );
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
esp_wifi_connect();
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {
xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);
}
}
- 检测Flash中是否存在wifi信息
static void check_wifi_info(void)
{
esp_err_t err;
uint8_t wifi_ssid[33] = { 0 };
uint8_t wifi_passwd[65] = { 0 };
size_t len;
nvs_handle_t Get_Wifi_handle;
uint8_t flag;
wifi_config_t wifi_config;
nvs_open("wifi_info",NVS_READONLY,&Get_Wifi_handle);
nvs_get_u8(Get_Wifi_handle,"wifi_info_flag",&flag);
if(flag == 1)
{
ESP_LOGI(TAG,"flash hava wifi Info");
len = sizeof(wifi_ssid);
err = nvs_get_str(Get_Wifi_handle,"wifi_ssid",(char *)wifi_ssid,&len);
if(err == ESP_OK)
{
ESP_LOGI(TAG, "Flash SSID = %s",wifi_ssid);
memcpy(wifi_config.sta.ssid,wifi_ssid,sizeof(wifi_config.sta.ssid));
}
len = sizeof(wifi_passwd);
err = nvs_get_str(Get_Wifi_handle,"wifi_pswd",(char *)wifi_passwd,&len);
if(err == ESP_OK)
{
ESP_LOGI(TAG, "Flash pswd = %s",wifi_passwd);
memcpy(wifi_config.sta.password,wifi_passwd,sizeof(wifi_config.sta.password));
}
nvs_close(Get_Wifi_handle);
ESP_LOGI(TAG, "wifi ssid :%s, paws:%s",wifi_config.sta.ssid,wifi_config.sta.password);
ESP_LOGI(TAG,"start wifi connect ....");
esp_wifi_disconnect();
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
esp_wifi_connect();
}
else{
nvs_close(Get_Wifi_handle);
xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);
}
}
三、查看情况
1、首次上电
-
使用微信小程序,一键配网,协议模式使用AirKiss,填入wifi信息
-
观察串口输出信息,已成功配网
-
小程序上显示配网成功
2、非首次上电
四、完整代码
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_wpa2.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_smartconfig.h"
#include "nvs.h"
static EventGroupHandle_t s_wifi_event_group;
static const int CONNECTED_BIT = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;
static const char *TAG = "smartconfig";
static nvs_handle_t Set_Wifi_handle;
typedef enum {
wifi_unconfiged = 0,
wifi_configed,
}wifi_info_storage_t;
static void smartconfig_example_task(void * parm);
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
ESP_LOGI(TAG, "STA start ");
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
esp_wifi_connect();
xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {
ESP_LOGI(TAG, "Scan done");
} else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {
ESP_LOGI(TAG, "Found channel");
} else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {
ESP_LOGI(TAG, "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 };
uint8_t rvd_data[33] = { 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(TAG, "SSID:%s", ssid);
ESP_LOGI(TAG, "PASSWORD:%s", password);
/* save wifi info to flash */
ESP_ERROR_CHECK(nvs_open("wifi_info",NVS_READWRITE,&Set_Wifi_handle));
ESP_ERROR_CHECK(nvs_set_str(Set_Wifi_handle,"wifi_ssid",(const char*)ssid));
ESP_ERROR_CHECK(nvs_set_str(Set_Wifi_handle,"wifi_pswd",(const char*)password));
ESP_ERROR_CHECK(nvs_set_u8(Set_Wifi_handle,"wifi_info_flag",wifi_configed));
ESP_ERROR_CHECK(nvs_commit(Set_Wifi_handle));
nvs_close(Set_Wifi_handle);
if (evt->type == SC_TYPE_ESPTOUCH_V2) {
ESP_ERROR_CHECK( esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)) );
ESP_LOGI(TAG, "RVD_DATA:");
for (int i=0; i<33; i++) {
printf("%02x ", rvd_data[i]);
}
printf("\n");
}
ESP_ERROR_CHECK( esp_wifi_disconnect() );
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
esp_wifi_connect();
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {
xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);
}
}
static void initialise_wifi(void)
{
ESP_ERROR_CHECK(esp_netif_init());
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_create_default());
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) );
ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
static void smartconfig_example_task(void * parm)
{
EventBits_t uxBits;
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS) );
smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) );
while (1) {
uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY);
if(uxBits & CONNECTED_BIT) {
ESP_LOGI(TAG, "WiFi Connected to ap");
}
if(uxBits & ESPTOUCH_DONE_BIT) {
ESP_LOGI(TAG, "smartconfig over");
esp_smartconfig_stop();
vTaskDelete(NULL);
}
}
}
static void check_wifi_info(void)
{
esp_err_t err;
uint8_t wifi_ssid[33] = { 0 };
uint8_t wifi_passwd[65] = { 0 };
size_t len;
nvs_handle_t Get_Wifi_handle;
uint8_t flag;
wifi_config_t wifi_config;
nvs_open("wifi_info",NVS_READONLY,&Get_Wifi_handle);
nvs_get_u8(Get_Wifi_handle,"wifi_info_flag",&flag);
if(flag == 1)
{
ESP_LOGI(TAG,"flash hava wifi Info");
len = sizeof(wifi_ssid);
err = nvs_get_str(Get_Wifi_handle,"wifi_ssid",(char *)wifi_ssid,&len);
if(err == ESP_OK)
{
ESP_LOGI(TAG, "Flash SSID = %s",wifi_ssid);
memcpy(wifi_config.sta.ssid,wifi_ssid,sizeof(wifi_config.sta.ssid));
}
len = sizeof(wifi_passwd);
err = nvs_get_str(Get_Wifi_handle,"wifi_pswd",(char *)wifi_passwd,&len);
if(err == ESP_OK)
{
ESP_LOGI(TAG, "Flash pswd = %s",wifi_passwd);
memcpy(wifi_config.sta.password,wifi_passwd,sizeof(wifi_config.sta.password));
}
nvs_close(Get_Wifi_handle);
ESP_LOGI(TAG, "wifi ssid :%s, paws:%s",wifi_config.sta.ssid,wifi_config.sta.password);
ESP_LOGI(TAG,"start wifi connect ....");
esp_wifi_disconnect();
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
esp_wifi_connect();
}
else{
nvs_close(Get_Wifi_handle);
xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);
}
}
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
initialise_wifi();
check_wifi_info();
}