From ee473945bc55b34c1f7eabe2e0d1de8fb7472ad2 Mon Sep 17 00:00:00 2001 From: "tarun.kumar" Date: Wed, 12 Aug 2026 15:29:10 +0530 Subject: [PATCH 1/3] fix(wifi): Require RSSI gain before low-RSSI roam Low-RSSI roaming used determine_best_ap(0), so a 1 dB better AP was enough and nearby APs could ping-pong. Add ESP_WIFI_ROAMING_LOW_RSSI_ROAM_DIFF (default 5 dB) as hysteresis for that path. --- .../wifi_apps/roaming_app/include/esp_roaming.h | 1 + .../wifi_apps/roaming_app/src/Kconfig.roaming | 12 ++++++++++++ .../wifi_apps/roaming_app/src/esp_roaming_i.h | 1 + .../wifi_apps/roaming_app/src/roaming_app.c | 15 ++++++++++----- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/components/esp_wifi/wifi_apps/roaming_app/include/esp_roaming.h b/components/esp_wifi/wifi_apps/roaming_app/include/esp_roaming.h index d3d7acc4daa..cf974c306bc 100644 --- a/components/esp_wifi/wifi_apps/roaming_app/include/esp_roaming.h +++ b/components/esp_wifi/wifi_apps/roaming_app/include/esp_roaming.h @@ -20,6 +20,7 @@ struct roam_config { bool low_rssi_roam_trigger; int8_t low_rssi_threshold; uint8_t rssi_threshold_reduction_offset; + uint8_t low_rssi_roam_diff; bool scan_monitor; #if CONFIG_ESP_WIFI_ROAMING_PERIODIC_SCAN_MONITOR uint8_t scan_interval; diff --git a/components/esp_wifi/wifi_apps/roaming_app/src/Kconfig.roaming b/components/esp_wifi/wifi_apps/roaming_app/src/Kconfig.roaming index d566a902360..22bbd47029c 100644 --- a/components/esp_wifi/wifi_apps/roaming_app/src/Kconfig.roaming +++ b/components/esp_wifi/wifi_apps/roaming_app/src/Kconfig.roaming @@ -29,6 +29,18 @@ menu "Roaming triggers" Setting 0 here may cause station to be flooded with low rssi events, therefore that's not recommended to be kept. + config ESP_WIFI_ROAMING_LOW_RSSI_ROAM_DIFF + depends on ESP_WIFI_ROAMING_LOW_RSSI_ROAMING + int "RSSI difference b/w current AP and candidate AP for low RSSI roam" + range 1 99 + default 5 + help + Minimum RSSI improvement (in dB) required of a candidate AP before roaming + when triggered by the low RSSI event. A value of 1 keeps the previous behavior + (any strictly better AP). Higher values add hysteresis and reduce ping-pong + between nearby APs with similar RSSI. Prefer a small value here (e.g. 3-5); + use ESP_WIFI_ROAMING_SCAN_ROAM_RSSI_DIFF for larger proactive improvements. + config ESP_WIFI_ROAMING_PERIODIC_SCAN_MONITOR bool "Conduct periodic scans to check if a better AP is available" default y diff --git a/components/esp_wifi/wifi_apps/roaming_app/src/esp_roaming_i.h b/components/esp_wifi/wifi_apps/roaming_app/src/esp_roaming_i.h index 71e589cb40d..f66f1b7e135 100644 --- a/components/esp_wifi/wifi_apps/roaming_app/src/esp_roaming_i.h +++ b/components/esp_wifi/wifi_apps/roaming_app/src/esp_roaming_i.h @@ -29,6 +29,7 @@ extern "C" { #if LOW_RSSI_ROAMING_ENABLED #define ROAMING_LOW_RSSI_THRESHOLD CONFIG_ESP_WIFI_ROAMING_LOW_RSSI_THRESHOLD #define RSSI_THRESHOLD_REDUCTION_OFFSET CONFIG_ESP_WIFI_ROAMING_LOW_RSSI_OFFSET +#define LOW_RSSI_ROAM_DIFF CONFIG_ESP_WIFI_ROAMING_LOW_RSSI_ROAM_DIFF #endif /*LOW_RSSI_ROAMING_ENABLED*/ #ifndef CONFIG_ESP_WIFI_ROAMING_PERIODIC_SCAN_MONITOR diff --git a/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c b/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c index c774d69e692..ec077ddf0df 100644 --- a/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c +++ b/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c @@ -1342,7 +1342,7 @@ static void roaming_app_rssi_low_internal_handler(void *ctx, void *data) if (!roaming_app_get_ap_info(&g_roaming_app.current_bss.ap)) { g_roaming_app.current_bss.ap.rssi = event->rssi; } - determine_best_ap(0); + determine_best_ap(g_roaming_app.config.low_rssi_roam_diff - 1); int32_t next_threshold = g_roaming_app.current_low_rssi_threshold - g_roaming_app.config.rssi_threshold_reduction_offset; next_threshold = roaming_app_clamp_rssi_threshold(next_threshold); @@ -2097,8 +2097,11 @@ static esp_err_t init_config_params(void) g_roaming_app.config.backoff_time = ROAMING_BACKOFF_TIME; g_roaming_app.config.low_rssi_roam_trigger = LOW_RSSI_ROAMING_ENABLED; +#if LOW_RSSI_ROAMING_ENABLED g_roaming_app.config.low_rssi_threshold = ROAMING_LOW_RSSI_THRESHOLD; g_roaming_app.config.rssi_threshold_reduction_offset = RSSI_THRESHOLD_REDUCTION_OFFSET; + g_roaming_app.config.low_rssi_roam_diff = LOW_RSSI_ROAM_DIFF; +#endif /* LOW_RSSI_ROAMING_ENABLED */ g_roaming_app.config.scan_monitor = PERIODIC_SCAN_MONITORING; #if PERIODIC_SCAN_MONITORING @@ -2117,9 +2120,10 @@ static esp_err_t init_config_params(void) ESP_LOGD(ROAMING_TAG, "Roaming app config :"); - ESP_LOGD(ROAMING_TAG, "backoff time=%d low_rssi_roam_trigger=%d low_rssi_threshold=%d rssi_threshold_reduction_offset=%d", + ESP_LOGD(ROAMING_TAG, "backoff time=%d low_rssi_roam_trigger=%d low_rssi_threshold=%d rssi_threshold_reduction_offset=%d low_rssi_roam_diff=%d", g_roaming_app.config.backoff_time, g_roaming_app.config.low_rssi_roam_trigger, - g_roaming_app.config.low_rssi_threshold, g_roaming_app.config.rssi_threshold_reduction_offset); + g_roaming_app.config.low_rssi_threshold, g_roaming_app.config.rssi_threshold_reduction_offset, + g_roaming_app.config.low_rssi_roam_diff); #if PERIODIC_SCAN_MONITORING ESP_LOGD(ROAMING_TAG, "scan_monitor=%d scan_interval=%d scan_rssi_threshold=%d scan_rssi_diff=%d", @@ -2421,9 +2425,10 @@ static int update_config_params(void *data) ESP_LOGI(ROAMING_TAG, "Updated Roaming app config :"); - ESP_LOGI(ROAMING_TAG, "backoff time=%d low_rssi_roam_trigger=%d low_rssi_threshold=%d rssi_threshold_reduction_offset=%d", + ESP_LOGI(ROAMING_TAG, "backoff time=%d low_rssi_roam_trigger=%d low_rssi_threshold=%d rssi_threshold_reduction_offset=%d low_rssi_roam_diff=%d", g_roaming_app.config.backoff_time, g_roaming_app.config.low_rssi_roam_trigger, - g_roaming_app.config.low_rssi_threshold, g_roaming_app.config.rssi_threshold_reduction_offset); + g_roaming_app.config.low_rssi_threshold, g_roaming_app.config.rssi_threshold_reduction_offset, + g_roaming_app.config.low_rssi_roam_diff); #if PERIODIC_SCAN_MONITORING ESP_LOGI(ROAMING_TAG, "scan_monitor=%d scan_interval=%d scan_rssi_threshold=%d scan_rssi_diff=%d", From a4a66a059de95a69a0dc3b680dcba1b10ffe7a13 Mon Sep 17 00:00:00 2001 From: "tarun.kumar" Date: Tue, 18 Aug 2026 15:39:53 +0530 Subject: [PATCH 2/3] fix(wifi): Preserve roam_config ABI and clamp roam diff Append low_rssi_roam_diff so existing struct members keep their offsets, and clamp runtime values to 1-99 so determine_best_ap() cannot see 0 or wrap. --- .../wifi_apps/roaming_app/include/esp_roaming.h | 2 +- .../wifi_apps/roaming_app/src/roaming_app.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/components/esp_wifi/wifi_apps/roaming_app/include/esp_roaming.h b/components/esp_wifi/wifi_apps/roaming_app/include/esp_roaming.h index cf974c306bc..25850f56f46 100644 --- a/components/esp_wifi/wifi_apps/roaming_app/include/esp_roaming.h +++ b/components/esp_wifi/wifi_apps/roaming_app/include/esp_roaming.h @@ -20,7 +20,6 @@ struct roam_config { bool low_rssi_roam_trigger; int8_t low_rssi_threshold; uint8_t rssi_threshold_reduction_offset; - uint8_t low_rssi_roam_diff; bool scan_monitor; #if CONFIG_ESP_WIFI_ROAMING_PERIODIC_SCAN_MONITOR uint8_t scan_interval; @@ -37,6 +36,7 @@ struct roam_config { uint8_t scan_filter_ssid[ROAM_SCAN_FILTER_SSID_LEN]; uint8_t scan_filter_bssid[ROAM_SCAN_FILTER_BSSID_LEN]; bool scan_filter_bssid_set; + uint8_t low_rssi_roam_diff; }; void roam_init_app(void); diff --git a/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c b/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c index ec077ddf0df..0e75d68222c 100644 --- a/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c +++ b/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c @@ -70,6 +70,8 @@ static const char *ROAMING_TAG = "ROAM"; #define RSSI_THRESHOLD_DISABLED -100 #define RSSI_THRESHOLD_MAX 10 +#define LOW_RSSI_ROAM_DIFF_MIN 1 +#define LOW_RSSI_ROAM_DIFF_MAX 99 #define BTM_QUERY_LIST_MAX_LEN (MAX_NEIGHBOR_LEN + 96) #define ROAMING_PENDING_TIMEOUT_USER_DATA_MAX 16 @@ -160,6 +162,19 @@ static int32_t roaming_app_clamp_rssi_threshold(int threshold) return threshold; } +static uint8_t roaming_app_clamp_low_rssi_roam_diff(uint8_t diff) +{ + if (diff < LOW_RSSI_ROAM_DIFF_MIN) { + return LOW_RSSI_ROAM_DIFF_MIN; + } + + if (diff > LOW_RSSI_ROAM_DIFF_MAX) { + return LOW_RSSI_ROAM_DIFF_MAX; + } + + return diff; +} + static bool roaming_app_scan_cache_is_valid(const struct timeval *now) { if (g_roaming_app.scanned_aps.time.tv_sec == 0 && g_roaming_app.scanned_aps.time.tv_usec == 0) { @@ -2400,6 +2415,8 @@ static int update_config_params(void *data) sizeof(next_scan_filter_bssid)) != 0); g_roaming_app.config = *config; + g_roaming_app.config.low_rssi_roam_diff = + roaming_app_clamp_low_rssi_roam_diff(g_roaming_app.config.low_rssi_roam_diff); memset(g_roaming_app.config.scan_filter_ssid, 0, sizeof(g_roaming_app.config.scan_filter_ssid)); memset(g_roaming_app.config.scan_filter_bssid, 0, sizeof(g_roaming_app.config.scan_filter_bssid)); g_roaming_app.config.scan_filter_bssid_set = false; From b232f8aaa33bfdb1f48d736fadbd092f4b7bcc19 Mon Sep 17 00:00:00 2001 From: "tarun.kumar" Date: Fri, 17 Jul 2026 13:36:35 +0530 Subject: [PATCH 3/3] fix(wifi) : Added more reason codes for blacklist roam --- .../wifi_apps/roaming_app/src/roaming_app.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c b/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c index 0e75d68222c..29b331a464e 100644 --- a/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c +++ b/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c @@ -868,6 +868,23 @@ static bool roaming_app_add_manual_blacklist_entry(const uint8_t *bssid) return true; } +#if CONFIG_ESP_WIFI_ROAMING_AUTO_BLACKLISTING +static bool roaming_app_reason_is_connection_failure(uint8_t reason) +{ + switch (reason) { + case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: + case WIFI_REASON_INVALID_PMKID: + case WIFI_REASON_AUTH_FAIL: + case WIFI_REASON_ASSOC_FAIL: + case WIFI_REASON_HANDSHAKE_TIMEOUT: + case WIFI_REASON_CONNECTION_FAIL: + return true; + default: + return false; + } +} +#endif + static void roaming_app_record_connection_failure(const uint8_t *bssid) { #if CONFIG_ESP_WIFI_ROAMING_AUTO_BLACKLISTING @@ -1035,7 +1052,7 @@ static void roaming_app_disconnected_event_handler(void *ctx, void *data) ESP_LOGD(ROAMING_TAG, "station got disconnected reason=%d, rssi =%d", disconn->reason, disconn->rssi); #if CONFIG_ESP_WIFI_ROAMING_AUTO_BLACKLISTING - if (disconn->reason == WIFI_REASON_CONNECTION_FAIL || disconn->reason == WIFI_REASON_AUTH_FAIL) { + if (roaming_app_reason_is_connection_failure(disconn->reason)) { roaming_app_record_connection_failure(g_roaming_app.current_bss.ap.bssid); } #endif