fix(wifi): send http response before channel switch and prevent reconnect race
All checks were successful
ESP32 Build & Release / build (push) Successful in 1m11s
All checks were successful
ESP32 Build & Release / build (push) Successful in 1m11s
This commit is contained in:
@@ -239,7 +239,10 @@ static const char SPA_PAGE[] =
|
||||
" }else{"
|
||||
" showWf('bad','Failed to connect: '+(j.error||'unknown'));"
|
||||
" }"
|
||||
" }).catch(function(e){showWf('bad','Network error: '+e);});"
|
||||
" }).catch(function(e){"
|
||||
" showWf('ok','Connection initiated to '+s+'. Device is connecting...');"
|
||||
" setTimeout(function(){refreshWifiStatus();loadSavedWifi();},6000);"
|
||||
" });"
|
||||
"}"
|
||||
"function loadSavedWifi(){"
|
||||
" fetch('/api/wifi/saved').then(function(r){return r.json();}).then(function(list){"
|
||||
@@ -671,6 +674,24 @@ static esp_err_t handle_wifi_saved(httpd_req_t *req)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char ssid[WIFI_SSID_MAX_LEN + 1];
|
||||
char pass[65];
|
||||
} async_wifi_connect_args_t;
|
||||
|
||||
static void async_wifi_connect_task(void *pvParameters)
|
||||
{
|
||||
async_wifi_connect_args_t *args = (async_wifi_connect_args_t *)pvParameters;
|
||||
if (args) {
|
||||
/* Wait 500ms to allow the HTTP 200 response to be cleanly transmitted and ACKed */
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
ESP_LOGI(TAG, "Executing deferred connection to '%s'", args->ssid);
|
||||
wifi_manager_connect_new(args->ssid, args->pass, true);
|
||||
free(args);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static esp_err_t handle_wifi_connect(httpd_req_t *req)
|
||||
{
|
||||
if (req->content_len <= 0 || req->content_len >= HTTPD_BODY_MAX) {
|
||||
@@ -710,12 +731,28 @@ static esp_err_t handle_wifi_connect(httpd_req_t *req)
|
||||
}
|
||||
|
||||
const char *p = pass ? pass : "";
|
||||
wifi_manager_connect_new(ssid, p, true);
|
||||
|
||||
/* Send HTTP 200 OK FIRST before the Wi-Fi stack switches channels or disconnects */
|
||||
char ok[128];
|
||||
snprintf(ok, sizeof(ok), "{\"ok\":true,\"ssid\":\"%s\"}\n", ssid);
|
||||
send_json(req, 200, ok);
|
||||
|
||||
/* Defer the actual connection to a background task so the current socket is not interrupted */
|
||||
async_wifi_connect_args_t *args = malloc(sizeof(async_wifi_connect_args_t));
|
||||
if (args) {
|
||||
strncpy(args->ssid, ssid, sizeof(args->ssid) - 1);
|
||||
args->ssid[sizeof(args->ssid) - 1] = '\0';
|
||||
strncpy(args->pass, p, sizeof(args->pass) - 1);
|
||||
args->pass[sizeof(args->pass) - 1] = '\0';
|
||||
if (xTaskCreate(async_wifi_connect_task, "wf_conn_async", 4096, args, 5, NULL) != pdPASS) {
|
||||
ESP_LOGE(TAG, "Failed to create async_wifi_connect_task, connecting synchronously");
|
||||
wifi_manager_connect_new(ssid, p, true);
|
||||
free(args);
|
||||
}
|
||||
} else {
|
||||
wifi_manager_connect_new(ssid, p, true);
|
||||
}
|
||||
|
||||
free(ssid);
|
||||
free(pass);
|
||||
return ESP_OK;
|
||||
|
||||
@@ -32,6 +32,7 @@ static char s_sta_ip[20] = "No Wi-Fi";
|
||||
static char s_active_ssid[WIFI_SSID_MAX_LEN + 1] = {0};
|
||||
static SemaphoreHandle_t s_wifi_mux = NULL;
|
||||
static SemaphoreHandle_t s_net_lock = NULL;
|
||||
static bool s_manual_disconnect = false;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
@@ -184,7 +185,7 @@ static void wifi_event_handler(void *arg, esp_event_base_t base, int32_t id, voi
|
||||
if (s_wifi_group) {
|
||||
xEventGroupClearBits(s_wifi_group, WIFI_CONNECTED_BIT);
|
||||
}
|
||||
if (s_active_ssid[0] != '\0' && s_retry_count < WIFI_RETRY_MAX) {
|
||||
if (!s_manual_disconnect && s_active_ssid[0] != '\0' && s_retry_count < WIFI_RETRY_MAX) {
|
||||
ESP_LOGW(TAG, "disconnected from '%s' (attempt %d), reconnecting...", s_active_ssid, s_retry_count);
|
||||
esp_wifi_connect();
|
||||
s_retry_count++;
|
||||
@@ -329,10 +330,14 @@ esp_err_t wifi_manager_connect_new(const char *ssid, const char *password, bool
|
||||
|
||||
strncpy(s_active_ssid, ssid, sizeof(s_active_ssid) - 1);
|
||||
s_active_ssid[sizeof(s_active_ssid) - 1] = '\0';
|
||||
s_retry_count = 0;
|
||||
|
||||
s_manual_disconnect = true;
|
||||
esp_wifi_disconnect();
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg));
|
||||
s_manual_disconnect = false;
|
||||
esp_err_t set_err = esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg);
|
||||
if (set_err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_wifi_set_config failed: %s", esp_err_to_name(set_err));
|
||||
return set_err;
|
||||
}
|
||||
esp_err_t ret = esp_wifi_connect();
|
||||
|
||||
if (save_to_nvs) {
|
||||
@@ -481,9 +486,9 @@ esp_err_t wifi_manager_start(void)
|
||||
|
||||
strncpy(s_active_ssid, target_ssid, sizeof(s_active_ssid) - 1);
|
||||
s_active_ssid[sizeof(s_active_ssid) - 1] = '\0';
|
||||
s_retry_count = 0;
|
||||
|
||||
s_manual_disconnect = true;
|
||||
esp_wifi_disconnect();
|
||||
s_manual_disconnect = false;
|
||||
esp_err_t err = esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_wifi_set_config failed: %s", esp_err_to_name(err));
|
||||
|
||||
Reference in New Issue
Block a user