ESP-IDF wifi 事件循环即使在代码回滚后仍继续接收 SYSTEM_EVENT_STA_WPS_ER_PIN
ESP-IDF wifi event loop keeps receiving SYSTEM_EVENT_STA_WPS_ER_PIN even after code rollback
我一直在开发一个使用 ESP32 和 ESP-IDF 的项目,该项目将在启动网络堆栈之前检查其 NVS 内存中的 wifi 凭据。如果有凭证,它将以 STA 模式连接到 wifi 网络,如果没有,它将作为自己的 AP 启动,以允许用户通过 HTTP 向其发送凭证。
将我的测试凭据手动放入 NVS 后,我开始处理 AP 代码。所有 AP 代码和逻辑完成后,我用 esptool 手动擦除闪存以强制开发板以该模式启动。这样做效果很好,我能够通过 HTTP 向它发送更新的凭据。
此时,开发板尝试在重置时连接为 STA,但是,SYSTEM_EVENT_STA_WPS_ER_PIN
事件一直被 wifi 事件循环捕获。开发板此后仅经历过此事件,此后完全无法连接到 wifi。更奇怪的是,即使使用 git 回滚到以前的版本后,问题仍然存在。
main.c
void app_main() {
// Start NVS
initNVS();
// Init Wifi Controller
initWifiController();
// Get Credentials to send to wifi
Creds creds = getCreds();
// Start wifi in STA mode with gathered creds
beginWifi(creds);
initializePins();
initializeTimers();
}
wifiController.c
void initWifiController(){
// * NVS must be initialized before wifi work can be done
// Handle when connected to the network
connectionSemaphore = xSemaphoreCreateBinary();
// Begin network stack
ESP_ERROR_CHECK(esp_netif_init());
// Create event loop for handling callbacks
ESP_ERROR_CHECK(esp_event_loop_create_default());
}
void beginWifi(Creds creds){
if(creds.status == ESP_OK){
ESP_LOGI(TAG, "Connection credentials have been found, connecting to network");
connectSTA(creds);
}
else if(creds.status == ESP_ERR_NVS_NOT_FOUND){
ESP_LOGW(TAG, "Missing credentials, starting as AP");
connectAP();
}
else{
ESP_LOGE(TAG, "ESP failed with error %s, not starting wifi", esp_err_to_name(creds.status));
}
void connectSTA(Creds creds){
ESP_LOGI(TAG, "Attempting to connect to wifi with following creds: %s | %s", creds.ssid, creds.pass);
// Set netif to sta
esp_netif_create_default_wifi_sta();
// Prepare and initialize wifi_init_config_t
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
// Register tracked events for event_handler
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));
// TODO: Check if this can be used to avoid havng to use NVS manually
esp_wifi_set_storage(WIFI_STORAGE_RAM);
// Config struct for wifi details
wifi_config_t wifi_config = {};
// Copy casted info into wifi_config
// * https://www.esp32.com/viewtopic.php?f=13&t=14611
// * See above link for details on this
strcpy((char *)wifi_config.sta.ssid, creds.ssid);
strcpy((char *)wifi_config.sta.password, creds.pass);
esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
ESP_ERROR_CHECK(esp_wifi_start());
// ? Is this required to avoid a memory leak?
free(creds.pass);
free(creds.ssid);
}
void connectAP(){
// ? How important is it that these be called in this order?
ESP_LOGI(TAG, "Starting in AP Mode");
esp_netif_create_default_wifi_ap();
// TODO: maybe move this creation to initWifiController to avoid making it twice
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
// TODO: Consider moving this to init Wifi Controller to avoid running it twice as well
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
// Configuration for AP
wifi_config_t wifi_config = {
.ap = {
.ssid = "Grow System",
.password = "Password",
.ssid_len = strlen("Grow System"),
.max_connection = 4,
.authmode = WIFI_AUTH_WPA_WPA2_PSK
}
};
// TODO: Enable password support on AP configuration
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Wifi connectAP finished");
registerEndPoints();
}
该代码实质上是检查 NVS 的凭据,如果找到它们,它 returns 一个包含它们以及 ESP_OK
的结构。如果其中之一未找到,则该结构包含 ESP_ERR_NVS_NOT_FOUND
。 wifiController.c
然后接收此 creds
结构并调用 beginWifi()
,然后根据结构的 status
调用 connectSTA()
或 connectAP()
。当凭据存在时,将调用 connectSTA()
,但由于未知原因,事件循环始终仅接收 SYSTEM_EVENT_STA_WPS_ER_PIN
事件。正如我之前提到的,即使将我的代码回滚到没有 connectAP()
函数的版本后,这种行为仍然存在。
因此,我预感问题可能与我手动擦除闪存有关,而不是代码。
头文件在其 typedef 中包含以下行来定义此事件。
SYSTEM_EVENT_STA_WPS_ER_PIN, /*!< ESP32 station wps pin code in enrollee mode */
我不知道那是什么意思,因为我没有故意在这个项目中包含任何关于 wps 的内容。
到目前为止,我的研究还没有返回任何非常有用的东西,所以如果有人知道 SYSTEM_EVENT_STA_WPS_ER_PIN
是什么或什么可能导致我的问题,我将非常感激。如果您认为更多细节对解决此问题有用,请告诉我,我将非常乐意提供。
对解决问题很有用。
我正在学习使用 ESP32 wifi,阅读你的消息,ESP-idf 和 esp-32 技术手册没有太多信息,我找到了这个 URI
https://www.wi-fi.org/downloads-public/Wi-Fi_Protected_Setup_Best_Practices_v2.0.2.pdf/8188
亲切的问候
更新:检查项目图中的 sdkconfig 文件与示例图中的 wifi 配置设置文件。
我已经研究这个问题好几天了,我还没有找到根本原因,但设法找到了一个解决方法和一些关于这个问题的细节。不断出现的SYSTEM_EVENT_STA_WPS_ER_PIN
事件其实是芯片尝试使用WPS Enrolle Pin模式连接路由器导致的。据推测,这会生成一个八位数的长引脚,可以将其放入您的路由器中,以使其能够连接。我真的不知道为什么会这样,但我相信这可能与我设置 AP 模式的方式有关。我现在主要的困惑是为什么回滚代码没有修复它。
对于“解决方法”,我发现闪烁 Espressif 的示例 STA wifi 连接代码设法解决了这个问题。该芯片在刷新后正确连接到我的网络,我能够重新刷新我自己的代码而没有任何问题。这对我来说似乎非常奇怪,所以我的一部分认为也许芯片由于某种原因无法连接到我的网络,代码中的边缘情况导致它进入注册模式。
这是我用来“解决”问题的代码的 link:https://github.com/espressif/esp-idf/blob/master/examples/wifi/getting_started/station/main/station_example_main.c
我会将此答案标记为正确并继续寻找根本问题。如果其他人知道实际可能导致此问题的原因,请随时 post 我会更新正确答案。如果我发现根本问题是什么,我也会更新这个答案。
编辑: 在继续挖掘之后,我相信问题实际上是我代码中的大量错误造成的。特别是,我正在调用 esp_netif_create_default_wifi_sta()
然后没有设置 WI-FI 模式。我需要添加 esp_wifi_set_mode(WIFI_MODE_STA)
,这在我的程序中是不存在的。我认为在不更改 wifi 模式的情况下将网络堆栈设置为 sta 是导致我出现问题的原因。
我一直在开发一个使用 ESP32 和 ESP-IDF 的项目,该项目将在启动网络堆栈之前检查其 NVS 内存中的 wifi 凭据。如果有凭证,它将以 STA 模式连接到 wifi 网络,如果没有,它将作为自己的 AP 启动,以允许用户通过 HTTP 向其发送凭证。
将我的测试凭据手动放入 NVS 后,我开始处理 AP 代码。所有 AP 代码和逻辑完成后,我用 esptool 手动擦除闪存以强制开发板以该模式启动。这样做效果很好,我能够通过 HTTP 向它发送更新的凭据。
此时,开发板尝试在重置时连接为 STA,但是,SYSTEM_EVENT_STA_WPS_ER_PIN
事件一直被 wifi 事件循环捕获。开发板此后仅经历过此事件,此后完全无法连接到 wifi。更奇怪的是,即使使用 git 回滚到以前的版本后,问题仍然存在。
main.c
void app_main() {
// Start NVS
initNVS();
// Init Wifi Controller
initWifiController();
// Get Credentials to send to wifi
Creds creds = getCreds();
// Start wifi in STA mode with gathered creds
beginWifi(creds);
initializePins();
initializeTimers();
}
wifiController.c
void initWifiController(){
// * NVS must be initialized before wifi work can be done
// Handle when connected to the network
connectionSemaphore = xSemaphoreCreateBinary();
// Begin network stack
ESP_ERROR_CHECK(esp_netif_init());
// Create event loop for handling callbacks
ESP_ERROR_CHECK(esp_event_loop_create_default());
}
void beginWifi(Creds creds){
if(creds.status == ESP_OK){
ESP_LOGI(TAG, "Connection credentials have been found, connecting to network");
connectSTA(creds);
}
else if(creds.status == ESP_ERR_NVS_NOT_FOUND){
ESP_LOGW(TAG, "Missing credentials, starting as AP");
connectAP();
}
else{
ESP_LOGE(TAG, "ESP failed with error %s, not starting wifi", esp_err_to_name(creds.status));
}
void connectSTA(Creds creds){
ESP_LOGI(TAG, "Attempting to connect to wifi with following creds: %s | %s", creds.ssid, creds.pass);
// Set netif to sta
esp_netif_create_default_wifi_sta();
// Prepare and initialize wifi_init_config_t
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
// Register tracked events for event_handler
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));
// TODO: Check if this can be used to avoid havng to use NVS manually
esp_wifi_set_storage(WIFI_STORAGE_RAM);
// Config struct for wifi details
wifi_config_t wifi_config = {};
// Copy casted info into wifi_config
// * https://www.esp32.com/viewtopic.php?f=13&t=14611
// * See above link for details on this
strcpy((char *)wifi_config.sta.ssid, creds.ssid);
strcpy((char *)wifi_config.sta.password, creds.pass);
esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
ESP_ERROR_CHECK(esp_wifi_start());
// ? Is this required to avoid a memory leak?
free(creds.pass);
free(creds.ssid);
}
void connectAP(){
// ? How important is it that these be called in this order?
ESP_LOGI(TAG, "Starting in AP Mode");
esp_netif_create_default_wifi_ap();
// TODO: maybe move this creation to initWifiController to avoid making it twice
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
// TODO: Consider moving this to init Wifi Controller to avoid running it twice as well
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
// Configuration for AP
wifi_config_t wifi_config = {
.ap = {
.ssid = "Grow System",
.password = "Password",
.ssid_len = strlen("Grow System"),
.max_connection = 4,
.authmode = WIFI_AUTH_WPA_WPA2_PSK
}
};
// TODO: Enable password support on AP configuration
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Wifi connectAP finished");
registerEndPoints();
}
该代码实质上是检查 NVS 的凭据,如果找到它们,它 returns 一个包含它们以及 ESP_OK
的结构。如果其中之一未找到,则该结构包含 ESP_ERR_NVS_NOT_FOUND
。 wifiController.c
然后接收此 creds
结构并调用 beginWifi()
,然后根据结构的 status
调用 connectSTA()
或 connectAP()
。当凭据存在时,将调用 connectSTA()
,但由于未知原因,事件循环始终仅接收 SYSTEM_EVENT_STA_WPS_ER_PIN
事件。正如我之前提到的,即使将我的代码回滚到没有 connectAP()
函数的版本后,这种行为仍然存在。
因此,我预感问题可能与我手动擦除闪存有关,而不是代码。
头文件在其 typedef 中包含以下行来定义此事件。
SYSTEM_EVENT_STA_WPS_ER_PIN, /*!< ESP32 station wps pin code in enrollee mode */
我不知道那是什么意思,因为我没有故意在这个项目中包含任何关于 wps 的内容。
到目前为止,我的研究还没有返回任何非常有用的东西,所以如果有人知道 SYSTEM_EVENT_STA_WPS_ER_PIN
是什么或什么可能导致我的问题,我将非常感激。如果您认为更多细节对解决此问题有用,请告诉我,我将非常乐意提供。
对解决问题很有用。 我正在学习使用 ESP32 wifi,阅读你的消息,ESP-idf 和 esp-32 技术手册没有太多信息,我找到了这个 URI https://www.wi-fi.org/downloads-public/Wi-Fi_Protected_Setup_Best_Practices_v2.0.2.pdf/8188
亲切的问候
更新:检查项目图中的 sdkconfig 文件与示例图中的 wifi 配置设置文件。
我已经研究这个问题好几天了,我还没有找到根本原因,但设法找到了一个解决方法和一些关于这个问题的细节。不断出现的SYSTEM_EVENT_STA_WPS_ER_PIN
事件其实是芯片尝试使用WPS Enrolle Pin模式连接路由器导致的。据推测,这会生成一个八位数的长引脚,可以将其放入您的路由器中,以使其能够连接。我真的不知道为什么会这样,但我相信这可能与我设置 AP 模式的方式有关。我现在主要的困惑是为什么回滚代码没有修复它。
对于“解决方法”,我发现闪烁 Espressif 的示例 STA wifi 连接代码设法解决了这个问题。该芯片在刷新后正确连接到我的网络,我能够重新刷新我自己的代码而没有任何问题。这对我来说似乎非常奇怪,所以我的一部分认为也许芯片由于某种原因无法连接到我的网络,代码中的边缘情况导致它进入注册模式。
这是我用来“解决”问题的代码的 link:https://github.com/espressif/esp-idf/blob/master/examples/wifi/getting_started/station/main/station_example_main.c
我会将此答案标记为正确并继续寻找根本问题。如果其他人知道实际可能导致此问题的原因,请随时 post 我会更新正确答案。如果我发现根本问题是什么,我也会更新这个答案。
编辑: 在继续挖掘之后,我相信问题实际上是我代码中的大量错误造成的。特别是,我正在调用 esp_netif_create_default_wifi_sta()
然后没有设置 WI-FI 模式。我需要添加 esp_wifi_set_mode(WIFI_MODE_STA)
,这在我的程序中是不存在的。我认为在不更改 wifi 模式的情况下将网络堆栈设置为 sta 是导致我出现问题的原因。