ESP32S3 + IDF 5.2.2 扫描WiFi
目录
1 资料
2 通过Wi-Fi库扫描附近的网络
2.1 通过idf命令创建工程
2.2 编写测试用例
2.3 优化测试用例
3 小结
1 资料
ESP-IDF 编程指南 » API 参考 » 连网 API » Wi-Fi 库
2 通过Wi-Fi库扫描附近的网络
2.1 通过idf命令创建工程
idf.py create-project wifi_scan_test
cd wifi_scan_test/
idf.py set-target esp32s3
执行menuconfig命令,配置工程(这里博主使用的是N8R8 版本的ESP32-S3-WROOM-1):
idf.py menuconfig
这里主要需要配置的是Flash和RAM,使其和你的模组、板级匹配。
配置完成后,保存配置,然后执行build:
idf.py save-defconfig
idf.py build
2.2 编写测试用例
完善wifi_scan.h头文件,申明一个wifi_scan()接口,供外部调用。
#ifndef _WIFI_SCAN_H_
#define __WIFI_SCAN_H_
#ifdef __cplusplus
extern "C" {
#endif
void wifi_scan(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
在wifi_scan_test.c源文件的app_main()中调用wifi_scan()接口。
在wifi_scan.c源文件中实现wifi_scan()接口。主要需要进行的操作包括:网络接口初始化、配置设备wifi工作在STA模式、启动wifi、扫描附近wifi、获取扫描结果。
网络接口初始化已经在 app_main()中处理了,这里就不用再处理。
/**
* @brief 将Wi-Fi初始化为sta并设置扫描方法
* @param 无
* @retval 无
*/
void wifi_scan(void)
{
/* 用户初始化STA模式 */
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);
/* wifi配置初始化 */
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
memset(ap_info, 0, sizeof(ap_info));
/* 设置WIFI为STA模式 */
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
/* 启动WIFI */
ESP_ERROR_CHECK(esp_wifi_start());
/* 开始扫描附件的WIFI, 并等待扫描结束 */
esp_wifi_scan_start(NULL, true);
/* 获取扫描结果 */
get_wifi_scan_result();
return;
}
实现get_wifi_scan_result()接口。这里需要注意esp_wifi_scan_get_ap_num()需要在esp_wifi_scan_get_ap_records()之前调用,否则无法获取到正确的ap_count值。
/**
* @brief 获取Wi-Fi扫描结果
* @param 无
* @retval 无
*/
static void get_wifi_scan_result(void)
{
number = DEFAULT_SCAN_LIST_SIZE;
ap_count = 0;
/* 获取上次扫描中找到的AP数量 */
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));
/* 获取上次扫描中找到的AP列表 */
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));
/* 打印WIFI扫描结果 */
print_wifi_scan_result(ap_count, number);
return;
}
实现print_wifi_scan_result()接口。
/**
* @brief 身份认证模式
* @param authmode :身份验证模式
* @retval 无
*/
static void print_auth_mode(int authmode)
{
switch (authmode) {
case WIFI_AUTH_OPEN:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_OPEN");
break;
case WIFI_AUTH_OWE:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_OWE");
break;
case WIFI_AUTH_WEP:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WEP");
break;
case WIFI_AUTH_WPA_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA_PSK");
break;
case WIFI_AUTH_WPA2_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_PSK");
break;
case WIFI_AUTH_WPA_WPA2_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA_WPA2_PSK");
break;
case WIFI_AUTH_WPA2_ENTERPRISE:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_ENTERPRISE");
break;
case WIFI_AUTH_WPA3_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA3_PSK");
break;
case WIFI_AUTH_WPA2_WPA3_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_WPA3_PSK");
break;
default:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_UNKNOWN");
break;
}
}
/**
* @brief 打印WIFI密码类型
* @param pairwise_cipher :密码类型
* @param group_cipher :群密码类型
* @retval 无
*/
static void print_cipher_type(int pairwise_cipher, int group_cipher)
{
switch (pairwise_cipher) {
case WIFI_CIPHER_TYPE_NONE:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_NONE");
break;
case WIFI_CIPHER_TYPE_WEP40:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP40");
break;
case WIFI_CIPHER_TYPE_WEP104:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP104");
break;
case WIFI_CIPHER_TYPE_TKIP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP");
break;
case WIFI_CIPHER_TYPE_CCMP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_CCMP");
break;
case WIFI_CIPHER_TYPE_TKIP_CCMP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP");
break;
default:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_UNKNOWN");
break;
}
switch (group_cipher) {
case WIFI_CIPHER_TYPE_NONE:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_NONE");
break;
case WIFI_CIPHER_TYPE_WEP40:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP40");
break;
case WIFI_CIPHER_TYPE_WEP104:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP104");
break;
case WIFI_CIPHER_TYPE_TKIP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP");
break;
case WIFI_CIPHER_TYPE_CCMP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_CCMP");
break;
case WIFI_CIPHER_TYPE_TKIP_CCMP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP");
break;
default:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_UNKNOWN");
break;
}
}
/**
* @brief 打印Wi-Fi扫描结果
* @param ap_count :实际扫描出的AP数量
* @param number :可打印输出的AP信息数量
* @retval 无
*/
static void print_wifi_scan_result(uint16_t ap_count, uint16_t number)
{
/* 打印附件的WIFI信息 */
ESP_LOGI(TAG, "wifi scan result, ap_count = %u, number = %u", ap_count, number);
for (int i = 0; (i < DEFAULT_SCAN_LIST_SIZE) && (i < ap_count); i++) {
ESP_LOGI(TAG, "SSID \t\t%s", ap_info[i].ssid);
ESP_LOGI(TAG, "RSSI \t\t%d(level:%d)", ap_info[i].rssi, rssi_to_5_level(ap_info[i].rssi));
/* 加密方式 */
print_auth_mode(ap_info[i].authmode);
/* 密码类型 */
if (ap_info[i].authmode != WIFI_AUTH_WEP) {
print_cipher_type(ap_info[i].pairwise_cipher, ap_info[i].group_cipher);
}
ESP_LOGI(TAG, "Channel \t\t%d\n", ap_info[i].primary);
}
return;
}
2.3 优化测试用例
esp_wifi_scan_start(NULL, true),方式会等到扫描完成后才返回,这样会导致wifi_scan()长时间不返回,更好的处理方式是在这里不等待扫描完成,发起了扫描后就返回调用,在真实的扫描完成事件发生后再去打印扫描结果。这就需要用到IDF的WiFi框架,主要是在默认事件循环中注册相关的事件处理函数 。
/**
* @brief Wi-Fi扫描完成事件 处理函数
* @param 默认事件处理标准参数列表
* @retval 无
*/
static void wifi_scan_completed_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_SCAN_DONE)) {
wifi_event_sta_scan_done_t* scan_done = (wifi_event_sta_scan_done_t*) event_data;
ESP_LOGI(TAG, "wifi scan done, status:%lu, number:%u", scan_done->status, scan_done->number);
/* 获取wifi扫描结果 */
get_wifi_scan_result();
}
return;
}
/**
* @brief 将Wi-Fi初始化为sta并设置扫描方法
* @param 无
* @retval 无
*/
void wifi_scan(void)
{
/* 用户初始化STA模式 */
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);
/* wifi配置初始化 */
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
memset(ap_info, 0, sizeof(ap_info));
/* 设置WIFI为STA模式 */
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
/* 根据ESP32 Wi-Fi 编程模型, 向 默认事件循环 注册事件处理函数 */
esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&wifi_scan_completed_event_handler,
NULL,
NULL);
/* 启动WIFI */
ESP_ERROR_CHECK(esp_wifi_start());
/* 开始扫描附件的WIFI, 不等待扫描结束 */
esp_wifi_scan_start(NULL, false);
/* 扫描结果处理在 wifi_scan_completed_event_handler() 中进行 */
return;
}
3 烧录、测试
工程完整代码,可自行下载、测试:
ESP32S3 + IDF5.2.2 wifi扫描 Demo