Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

重设参数无法让设备WiFi重连,回调函数无响应 (IDFGH-13868) #14713

Closed
3 tasks done
cannnnnnnnnnnn opened this issue Oct 12, 2024 · 10 comments
Closed
3 tasks done
Assignees
Labels
Resolution: Done Issue is done internally Status: Done Issue is done internally

Comments

@cannnnnnnnnnnn
Copy link

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

General issue report

逻辑代码如下:

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_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        if (s_retry_num < MAXIMUM_RETRY) {
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        } else {
            s_retry_num = 0;
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
        }
        ESP_LOGI(TAG,"connect to the AP fail");
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}

// STA模式初始化
esp_err_t wifi_init_sta(void)
{
    sta_netif = esp_netif_create_default_wifi_sta();
    assert(sta_netif);

    // 注册回调函数
    s_wifi_event_group = xEventGroupCreate();
    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));
    // 设置日志级别,屏蔽日志输出
    esp_log_level_set("wifi", ESP_LOG_WARN);

    return ESP_OK;
}

// WIFI连接
esp_err_t wifi_connect(const char *ssid, const char *passwd)
{
    wifi_config_t wifi_sta_config = {
        .sta = {
            .ssid = {0},
            .password = {0},
            .threshold.authmode = WIFI_AUTH_WPA2_PSK,
            .sae_pwe_h2e = WPA3_SAE_PWE_BOTH,
        }};

    // 显式地复制字符串到结构体成员
    strlcpy((char *)wifi_sta_config.sta.ssid, (const char *)ssid, sizeof(wifi_sta_config.sta.ssid));
    strlcpy((char *)wifi_sta_config.sta.password, (const char *)passwd, sizeof(wifi_sta_config.sta.password));

    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_sta_config));

    /* 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) */
    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",ssid, passwd);
    } else {
        // 清除标志位
        xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT);
        ESP_LOGI(TAG, "Failed to connect to SSID:%s password:%s", ssid, passwd);
    }

    return ESP_OK;
}
void app_main(void)
{
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    //Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    /*Initialize WiFi */
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));

    // 检查AP模式下是否初始化成功
    ESP_ERROR_CHECK(wifi_init_softap());

    // 检查STA模式下是否初始化成功
    ESP_ERROR_CHECK(wifi_init_sta());

    /* Start WiFi */
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_ERROR_CHECK(wifi_connect("Xiaomi_76E5","123456"));

    ESP_ERROR_CHECK(wifi_connect("Xiaomi_76E5","123456"));

    start_http_server();
}

我希望在不影响AP工作状态的情况下去配置连接另一个WiFi应如何操作呢?

@espressif-bot espressif-bot added the Status: Opened Issue is new label Oct 12, 2024
@github-actions github-actions bot changed the title 重设参数无法让设备WiFi重连,回调函数无响应 重设参数无法让设备WiFi重连,回调函数无响应 (IDFGH-13868) Oct 12, 2024
@cannnnnnnnnnnn
Copy link
Author

很奇怪的一点就是在wifi_connect函数里面,开头添加ESP_ERROR_CHECK(esp_wifi_connect());,这样虽然会报错,但是不会影响底层函数的重连,而且在第二次使用该函数时会有回调函数的响应

@cannnnnnnnnnnn
Copy link
Author

在优化加入判断逻辑后,就没有出现这样的问题,但是我还是不能理解,如果在下一次连接WiFi前,我并没有调用esp_wifi_disconnect()函数,在重新设置参数后调用esp_wifi_set_config(WIFI_IF_STA, &wifi_sta_config)函数后,回调函数为什么无法响应呢?

@cannnnnnnnnnnn
Copy link
Author

// 判断重连标志
EventBits_t current_bits = xEventGroupGetBits(s_wifi_event_group);
if (current_bits & WIFI_RESET_BIT) {
    ESP_ERROR_CHECK(esp_wifi_connect());
    ESP_LOGI(TAG, "WIFI_RESET_BIT is set, indicating a reset is needed.");
}

@hansw123
Copy link
Collaborator

@cannnnnnnnnnnn
如果想正常使用apsta模式,可以参考我们的example 的写法
https://github.com/espressif/esp-idf/blob/master/examples/wifi/softap_sta/main/softap_sta.c

@cannnnnnnnnnnn
Copy link
Author

Hi @hansw123

感谢你的解答,我是参考的官方例程去实现的功能,但是我在该功能的基础上修改成了需要多次连接和当设备连接该网络的情况下可以连接其他网络的需求,我现在的实际问题已经解决,但是在回调函数的响应问题上我还是疑惑

@cannnnnnnnnnnn
Copy link
Author

我通过实际的测试发现函数esp_netif_create_default_wifi_sta();esp_netif_set_default_netif(sta_netif);会触发回调函数中的WIFI_EVENT_STA_START,而在示例程序中这个回调会调用esp_wifi_connect();,就像我在之前留言说的那样在这段代码里

// WIFI连接
esp_err_t wifi_connect(const char *ssid, const char *passwd)
{
    wifi_config_t wifi_sta_config = {
        .sta = {
            .ssid = {0},
            .password = {0},
            .threshold.authmode = WIFI_AUTH_WPA2_PSK,
            .sae_pwe_h2e = WPA3_SAE_PWE_BOTH,
        }};

    // 显式地复制字符串到结构体成员
    strlcpy((char *)wifi_sta_config.sta.ssid, (const char *)ssid, sizeof(wifi_sta_config.sta.ssid));
    strlcpy((char *)wifi_sta_config.sta.password, (const char *)passwd, sizeof(wifi_sta_config.sta.password));

    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_sta_config));

    /* 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) */
    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",ssid, passwd);
    } else {
        // 清除标志位
        xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT);
        ESP_LOGI(TAG, "Failed to connect to SSID:%s password:%s", ssid, passwd);
    }

    return ESP_OK;
}

我在初始化完成后第一次使用,连接错误的WiFi密码我在回调函数里面设置的五次回调都有信息输出,但是我在第二次调用设置错误的WiFi名称和密码回调函数就没有响应,起初我还以为是标志位设置的有问题,但是在调试中发现不是这样的问题。

当我在后面的调试解决问题的过程中发现,在调用esp_wifi_set_config(WIFI_IF_STA, &wifi_sta_config)函数前,必须调用esp_wifi_connect();这样回调函数才会正确的响应,这个我就不是很理解,为什么esp_wifi_set_config函数为什么调用后在底层的控制中为什么不会自动的去连接然后回调,而是必须要调用esp_wifi_connect才能够正常的回调,那如果我在WIFI_EVENT_STA_DISCONNECTED的会调用加入判断逻辑,如果达到回调的最大次数,我就调用esp_wifi_disconnect,在下一次连接时我再调用esp_wifi_connect这样的话有助于设备节能吗?

@hansw123
Copy link
Collaborator

hansw123 commented Oct 18, 2024

if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();

因为这边wifi 连接操作是看到WIFI_EVENT_STA_START 事件,这个事件要esp_wifi_start() 触发
如果只是set config 是不会触发WIFI_EVENT_STA_START事件的

@hansw123
Copy link
Collaborator

hansw123 commented Oct 18, 2024

https://github.com/espressif/esp-idf/blob/master/examples/wifi/getting_started/station/main/station_example_main.c
还可以再看看 only station mode 的example ,对比一下自己的应用代码,特别是事件处理和 整个wifi 启动连接的流程
你可以看到station 的重新连接是根据WIFI_EVENT_STA_DISCONNECTED 事件,这个事件不需要任何操作,当sta的wifi连接断开 就会触发

@hansw123
Copy link
Collaborator

@cannnnnnnnnnnn
Copy link
Author

Hi @hansw123

好的,感谢你的解答

@espressif-bot espressif-bot added Status: Done Issue is done internally Resolution: Done Issue is done internally and removed Status: Opened Issue is new labels Oct 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: Done Issue is done internally Status: Done Issue is done internally
Projects
None yet
Development

No branches or pull requests

4 participants