2

我一直在使用带有 ESP-IDF 的 ESP32 进行一个项目,该项目将在启动网络堆栈之前检查其 NVS 内存中的 wifi 凭据。如果它有说凭据,它将以 STA 模式连接到 wifi 网络,如果它缺少它们,它将作为它自己的 AP 启动,以允许用户通过 HTTP 向它发送凭据。

在手动将我的测试凭据放入 NVS 后,我开始编写 AP 代码。完成所有 AP 代码和逻辑后,我使用 esptool 手动擦除闪存以强制开发板以该模式启动。这样做效果很好,我能够通过 HTTP 向它发送更新的凭据。

此时,板子在复位时尝试作为 STA 连接,但是,该SYSTEM_EVENT_STA_WPS_ER_PIN事件一直被 wifi 事件循环捕获。此后董事会仅经历过此事件,并且此后完全无法连接到wifi。更奇怪的是,即使使用 git 回滚到以前的版本,问题仍然存在。

主程序

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();
}

wifi控制器.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 的凭据,如果找到它们,它会返回一个包含它们的结构以及ESP_OK. 如果未找到其中之一,则该结构将包含ESP_ERR_NVS_NOT_FOUND. wifiController.c然后接收这个creds结构并调用beginWifi(),然后调用connectSTA()connectAP()基于status结构的。当凭证存在时,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是或可能导致我的问题,我将非常感激。如果您认为更多细节对解决此问题有用,请告诉我,我将非常乐意提供。

4

2 回答 2

1

对解决问题很有用。我正在学习使用 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 配置设置。

于 2021-05-21T07:57:58.340 回答
0

我已经研究这个问题好几天了,我还没有找到根本原因,但设法找到了解决方法和有关该问题的一些细节。不断出现的SYSTEM_EVENT_STA_WPS_ER_PIN事件实际上是由于芯片尝试使用WPS Enrolle Pin模式连接路由器引起的。假设这会生成一个八位数的长针脚,可以将其放入路由器中,该针脚应该允许连接。我真的不知道为什么会这样,但我相信这可能与我如何设置 AP 模式有关。我现在主要的困惑是为什么回滚代码没有修复它。

对于“解决方法”,我发现闪烁 Espressif 的示例 STA wifi 连接代码可以解决它。芯片在刷新后正确连接到我的网络,并且我能够重新刷新自己的代码而不会出现任何问题。这对我来说似乎非常奇怪,所以我的一部分人认为也许芯片由于某种原因无法连接到我的网络,并且代码中的边缘情况导致它进入登记者模式。

这是我用来“修复”问题的代码的链接:https ://github.com/espressif/esp-idf/blob/master/examples/wifi/getting_started/station/main/station_example_main.c

我会将此答案标记为正确并继续寻找根本问题。如果其他人知道实际可能导致此问题的原因,请随时发布,我将更新正确答案。如果我发现根本问题是什么,我也会更新这个答案。

编辑:继续挖掘后,我相信问题实际上是由于我的代码中的大量错误造成的。特别是,我打电话esp_netif_create_default_wifi_sta()然后没有设置 WI-FI 模式。我需要添加esp_wifi_set_mode(WIFI_MODE_STA),我的程序中没有。我相信在不更改 wifi 模式的情况下将网络堆栈设置为 sta 是导致我的问题的原因。

于 2021-05-21T19:22:39.007 回答