feat(wifi): retain multiple network credentials

This commit is contained in:
chenjintao
2026-08-24 16:16:16 +08:00
parent 23f4969404
commit ae27d5bbaa
6 changed files with 67 additions and 29 deletions
@@ -22,6 +22,10 @@
#define CONFIG_TQ_BOOT_SOUND_TIMEOUT_MS 3000
#endif
#ifndef CONFIG_TQ_WIFI_CONNECT_CYCLE_TIMEOUT_MS
#define CONFIG_TQ_WIFI_CONNECT_CYCLE_TIMEOUT_MS 20000
#endif
static const char *TAG = "app_comp_boot";
typedef enum {
@@ -194,7 +198,7 @@ static esp_err_t app_composition_run_plan_a_boot_sequence(void)
"control_plane_bootstrap_connectivity");
esp_err_t wifi_err = control_plane_bootstrap_connectivity(CONFIG_MULTIMODAL_WIFI_SSID,
CONFIG_MULTIMODAL_WIFI_PASSWORD,
CONFIG_MULTIMODAL_CONNECT_TIMEOUT_MS);
CONFIG_TQ_WIFI_CONNECT_CYCLE_TIMEOUT_MS);
if (wifi_err != ESP_OK) {
ESP_LOGW(TAG, "Connectivity bootstrap failed: %s", esp_err_to_name(wifi_err));
}
@@ -39,7 +39,7 @@
#define CONTROL_PLANE_PTT_ACTIVE_POLL_INTERVAL_MS 80
#define CONTROL_PLANE_WIFI_DISCONNECTED_REFRESH_MS 5000
#define CONTROL_PLANE_WIFI_DISCONNECT_GRACE_MS 3000
#define CONTROL_PLANE_WIFI_RECONNECT_TIMEOUT_MS 10000
#define CONTROL_PLANE_WIFI_REASSOCIATION_TIMEOUT_MS 10000
#define CONTROL_PLANE_WIFI_RECONNECT_BASE_DELAY_MS 5000
#define CONTROL_PLANE_WIFI_RECONNECT_MAX_DELAY_MS 60000
#define CONTROL_PLANE_USER_WEB_RETRY_MS 5000
@@ -128,6 +128,10 @@
#define CONFIG_TQ_MINI_PROGRAM_PROVISIONING_RECONNECT_FAILURES 2
#endif
#ifndef CONFIG_TQ_WIFI_CONNECT_CYCLE_TIMEOUT_MS
#define CONFIG_TQ_WIFI_CONNECT_CYCLE_TIMEOUT_MS 20000
#endif
#ifndef CONFIG_TQ_MINI_PROGRAM_PROVISIONING_ENABLE
#define CONFIG_TQ_MINI_PROGRAM_PROVISIONING_ENABLE 0
#endif
@@ -1618,7 +1622,8 @@ static esp_err_t control_plane_attempt_wifi_reconnect(void)
ESP_LOGI(TAG, "Attempting Wi-Fi STA reconnect");
domain_runtime_behavior_set_keep_awake(true);
esp_err_t err = domain_runtime_wifi_portal_connect_sta(CONTROL_PLANE_WIFI_RECONNECT_TIMEOUT_MS);
esp_err_t err = domain_runtime_wifi_portal_connect_sta(
CONFIG_TQ_WIFI_CONNECT_CYCLE_TIMEOUT_MS);
domain_runtime_behavior_set_keep_awake(false);
if (err == ESP_OK) {
@@ -2195,7 +2200,7 @@ static void control_plane_wifi_state_task(void *arg)
(unsigned)CONTROL_PLANE_NETWORK_FAILURE_REASSOC_THRESHOLD);
domain_runtime_behavior_set_keep_awake(true);
esp_err_t reassoc_err = domain_runtime_wifi_portal_reconnect_sta(
CONTROL_PLANE_WIFI_RECONNECT_TIMEOUT_MS);
CONTROL_PLANE_WIFI_REASSOCIATION_TIMEOUT_MS);
domain_runtime_behavior_set_keep_awake(false);
connected = control_plane_is_sta_connected();
ESP_LOGW(TAG,
+6 -4
View File
@@ -15,8 +15,9 @@ typedef struct {
/**
* @brief Initialize Wi-Fi portal defaults and seed credentials.
*
* This writes the provided SSID/password into NVS if no credentials exist yet.
* The underlying Wi-Fi manager is initialized lazily when starting STA or AP.
* This saves the provided SSID/password as the highest-priority entry while
* retaining existing credentials. The underlying Wi-Fi manager is initialized
* lazily when starting STA or AP.
*/
esp_err_t wifi_portal_init_defaults(const char *seed_ssid, const char *seed_password);
@@ -50,8 +51,9 @@ esp_err_t wifi_portal_connect_sta(int timeout_ms);
/**
* @brief Trial-connect with credentials without persisting them first.
*
* On success, the trial credentials atomically replace the saved credential
* list. On failure, the previous in-memory and NVS credentials remain intact.
* On success, the trial credentials are saved as the highest-priority entry
* while older credentials are retained. On failure, the previous in-memory
* and NVS credentials remain intact.
*/
esp_err_t wifi_portal_connect_sta_with_credentials(const char *ssid,
const char *password,
+36 -19
View File
@@ -125,6 +125,35 @@ static esp_err_t wifi_portal_lock(void)
return ESP_OK;
}
static void promote_saved_wifi(const std::string &ssid)
{
if (ssid.empty()) {
return;
}
if (wifi_portal_lock() != ESP_OK) {
ESP_LOGW(TAG, "Could not promote connected Wi-Fi \"%s\": portal lock timed out",
ssid.c_str());
return;
}
PortalUnlockGuard guard;
install_wifi_storage_hooks();
auto &credentials = SsidManager::GetInstance();
const auto &ssid_list = credentials.GetSsidList();
for (size_t i = 0; i < ssid_list.size(); ++i) {
if (ssid_list[i].ssid != ssid) {
continue;
}
if (i > 0U) {
credentials.SetDefaultSsid((int)i);
ESP_LOGI(TAG, "Promoted connected Wi-Fi \"%s\" to highest priority",
ssid.c_str());
}
return;
}
}
static wifi_portal_behavior_hooks_t snapshot_behavior_hooks(void)
{
wifi_portal_behavior_hooks_t hooks = {};
@@ -153,6 +182,7 @@ static void wifi_manager_event_callback(WifiEvent event, const std::string &data
break;
case WifiEvent::Connected:
ESP_LOGI(TAG, "Connected to \"%s\"", data.c_str());
promote_saved_wifi(data);
(void)apply_sta_stability_policy();
break;
case WifiEvent::Disconnected:
@@ -209,24 +239,10 @@ static void seed_default_credentials(const char *ssid, const char *password)
return;
}
bool configured_ssid_saved = false;
for (const auto &item : manager.GetSsidList()) {
if (item.ssid == ssid) {
configured_ssid_saved = true;
break;
}
}
if (saved_count > 0U && !configured_ssid_saved) {
ESP_LOGI(TAG,
"Configured seed SSID changed to \"%s\"; replacing %u stale credential candidate(s)",
ssid,
(unsigned)saved_count);
manager.Clear();
}
manager.AddSsid(ssid, password != NULL ? password : "");
promote_saved_wifi(ssid);
ESP_LOGI(TAG,
"Ensured configured Wi-Fi credentials for SSID \"%s\" with %u previous candidate(s)",
"Ensured configured Wi-Fi credentials for SSID \"%s\" while preserving %u previous candidate(s)",
ssid,
(unsigned)saved_count);
}
@@ -456,10 +472,10 @@ esp_err_t wifi_portal_connect_sta_with_credentials(const char *ssid,
ESP_RETURN_ON_ERROR(wifi_portal_lock(), TAG, "Failed to lock Wi-Fi portal");
PortalUnlockGuard guard;
auto &credentials = SsidManager::GetInstance();
credentials.Clear();
credentials.AddSsid(ssid, password != NULL ? password : "");
promote_saved_wifi(ssid);
ESP_LOGI(TAG,
"Credential trial succeeded and replaced saved Wi-Fi for SSID \"%s\"",
"Credential trial succeeded and saved Wi-Fi \"%s\" as highest priority",
ssid);
}
@@ -558,7 +574,8 @@ esp_err_t wifi_portal_save_credentials(const char *ssid, const char *password)
"Password too long");
SsidManager::GetInstance().AddSsid(ssid, password != NULL ? password : "");
ESP_LOGI(TAG, "Saved Wi-Fi credentials for SSID \"%s\"", ssid);
promote_saved_wifi(ssid);
ESP_LOGI(TAG, "Saved Wi-Fi credentials for SSID \"%s\" as highest priority", ssid);
return ESP_OK;
}
+11 -2
View File
@@ -1090,10 +1090,19 @@ menu "Example Configuration"
Password for the seed SSID.
config MULTIMODAL_CONNECT_TIMEOUT_MS
int "Wi-Fi connect timeout (ms)"
int "Cloud transport connect timeout (ms)"
default 10000
help
Timeout for Wi-Fi STA connection attempts in milliseconds.
Timeout for multimodal HTTP and WebSocket connection attempts.
config TQ_WIFI_CONNECT_CYCLE_TIMEOUT_MS
int "Wi-Fi candidate connection cycle timeout (ms)"
default 20000
range 5000 120000
help
Total time allowed for one scan and connection cycle across
visible saved Wi-Fi candidates. Failed cycles continue through
the runtime reconnect backoff policy.
config VOICE_PROMPT_WIFI_SUCCESS_FILE
string "Wi-Fi success prompt file"
+1
View File
@@ -19,6 +19,7 @@ CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL=y
CONFIG_TQ_MINI_PROGRAM_PROVISIONING_ENABLE=y
CONFIG_TQ_MINI_PROGRAM_PROVISIONING_CONNECT_TIMEOUT_MS=30000
CONFIG_TQ_MINI_PROGRAM_PROVISIONING_RECONNECT_FAILURES=2
CONFIG_TQ_WIFI_CONNECT_CYCLE_TIMEOUT_MS=20000
# External PSRAM (ESP32-S3 octal mode)
CONFIG_SPIRAM=y