mirror of
https://github.com/esphome/esphome.git
synced 2025-11-20 00:35:44 +00:00
cleanups
This commit is contained in:
@@ -58,6 +58,21 @@ static const char *const TAG = "wifi";
|
|||||||
/// │ ↓ │
|
/// │ ↓ │
|
||||||
/// │ 2. Cycle through remaining configured APs (1 attempt each) │
|
/// │ 2. Cycle through remaining configured APs (1 attempt each) │
|
||||||
/// │ ↓ │
|
/// │ ↓ │
|
||||||
|
/// │ [All Failed] → Check if first network is explicitly hidden │
|
||||||
|
/// └──────────────────────────────────────────────────────────────────────┘
|
||||||
|
/// ↓
|
||||||
|
/// ┌──────────────────────────────────────────────────────────────────────┐
|
||||||
|
/// │ Explicit Hidden Networks Path (Optional) │
|
||||||
|
/// ├──────────────────────────────────────────────────────────────────────┤
|
||||||
|
/// │ │
|
||||||
|
/// │ If first configured network has 'hidden: true': │
|
||||||
|
/// │ │
|
||||||
|
/// │ 1. EXPLICIT_HIDDEN → Try networks marked hidden: true (1 attempt) │
|
||||||
|
/// │ in config order until visible network reached │
|
||||||
|
/// │ ↓ │
|
||||||
|
/// │ Example: Hidden1, Hidden2, Visible1, Hidden3, Visible2 │
|
||||||
|
/// │ Try: Hidden1, Hidden2 (stop at Visible1) │
|
||||||
|
/// │ ↓ │
|
||||||
/// │ [All Failed] → Fall back to scan-based connection │
|
/// │ [All Failed] → Fall back to scan-based connection │
|
||||||
/// └──────────────────────────────────────────────────────────────────────┘
|
/// └──────────────────────────────────────────────────────────────────────┘
|
||||||
/// ↓
|
/// ↓
|
||||||
@@ -73,12 +88,14 @@ static const char *const TAG = "wifi";
|
|||||||
/// │ └─────────────────────────────────────────────────┘ │
|
/// │ └─────────────────────────────────────────────────┘ │
|
||||||
/// │ ↓ │
|
/// │ ↓ │
|
||||||
/// │ 2. SCAN_CONNECTING → Try scan_result_[0] (2 attempts) │
|
/// │ 2. SCAN_CONNECTING → Try scan_result_[0] (2 attempts) │
|
||||||
|
/// │ (Visible1, Visible2 from example above) │
|
||||||
/// │ ↓ │
|
/// │ ↓ │
|
||||||
/// │ 3. FAILED → Decrease priority: 0.0 → -1.0 → -2.0 │
|
/// │ 3. FAILED → Decrease priority: 0.0 → -1.0 → -2.0 │
|
||||||
/// │ (stored in persistent sta_priorities_) │
|
/// │ (stored in persistent sta_priorities_) │
|
||||||
/// │ ↓ │
|
/// │ ↓ │
|
||||||
/// │ 4. SCAN_WITH_HIDDEN → Try SSIDs not in scan OR marked hidden │
|
/// │ 4. RETRY_HIDDEN → Try SSIDs not in scan (1 attempt per SSID) │
|
||||||
/// │ (skips visible SSIDs not marked hidden) │
|
/// │ Skip if already tried in EXPLICIT_HIDDEN │
|
||||||
|
/// │ (Hidden3 from example, NOT Hidden1/Hidden2) │
|
||||||
/// │ ↓ │
|
/// │ ↓ │
|
||||||
/// │ 5. FAILED → RESTARTING_ADAPTER (skipped if AP/improv active) │
|
/// │ 5. FAILED → RESTARTING_ADAPTER (skipped if AP/improv active) │
|
||||||
/// │ ↓ │
|
/// │ ↓ │
|
||||||
@@ -98,14 +115,16 @@ static const char *const TAG = "wifi";
|
|||||||
/// Retry Phases:
|
/// Retry Phases:
|
||||||
/// - INITIAL_CONNECT: First attempt (try saved credentials if fast_connect enabled)
|
/// - INITIAL_CONNECT: First attempt (try saved credentials if fast_connect enabled)
|
||||||
/// - FAST_CONNECT_CYCLING_APS: Cycle through configured APs (1 attempt per AP, fast_connect only)
|
/// - FAST_CONNECT_CYCLING_APS: Cycle through configured APs (1 attempt per AP, fast_connect only)
|
||||||
|
/// - EXPLICIT_HIDDEN: Try consecutive networks marked hidden:true before scanning (1 attempt per SSID)
|
||||||
/// - SCAN_CONNECTING: Connect using scan results (2 attempts per BSSID)
|
/// - SCAN_CONNECTING: Connect using scan results (2 attempts per BSSID)
|
||||||
/// - SCAN_WITH_HIDDEN: Try hidden mode for SSIDs not in scan or marked hidden (1 attempt per SSID)
|
/// - RETRY_HIDDEN: Try hidden mode for SSIDs not in scan (1 attempt per SSID, skips already tried)
|
||||||
/// - RESTARTING_ADAPTER: Restart WiFi adapter to clear stuck state
|
/// - RESTARTING_ADAPTER: Restart WiFi adapter to clear stuck state
|
||||||
///
|
///
|
||||||
/// Smart Hidden Mode Skip:
|
/// Hidden Network Handling:
|
||||||
/// - SSIDs marked 'hidden: true' → Always tried in hidden mode (respects user config)
|
/// - Networks marked 'hidden: true' at start of config → Tried in EXPLICIT_HIDDEN phase
|
||||||
/// - SSIDs visible in scan + not marked hidden → Skipped (we know they're not hidden)
|
/// - Networks marked 'hidden: true' after visible network → Tried in RETRY_HIDDEN phase
|
||||||
/// - SSIDs not in scan → Tried in hidden mode (might be hidden)
|
/// - Networks not in scan → Tried in RETRY_HIDDEN phase
|
||||||
|
/// - Networks visible in scan + not marked hidden → Skipped in RETRY_HIDDEN phase
|
||||||
|
|
||||||
static const LogString *retry_phase_to_log_string(WiFiRetryPhase phase) {
|
static const LogString *retry_phase_to_log_string(WiFiRetryPhase phase) {
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
@@ -115,10 +134,12 @@ static const LogString *retry_phase_to_log_string(WiFiRetryPhase phase) {
|
|||||||
case WiFiRetryPhase::FAST_CONNECT_CYCLING_APS:
|
case WiFiRetryPhase::FAST_CONNECT_CYCLING_APS:
|
||||||
return LOG_STR("FAST_CONNECT_CYCLING");
|
return LOG_STR("FAST_CONNECT_CYCLING");
|
||||||
#endif
|
#endif
|
||||||
|
case WiFiRetryPhase::EXPLICIT_HIDDEN:
|
||||||
|
return LOG_STR("EXPLICIT_HIDDEN");
|
||||||
case WiFiRetryPhase::SCAN_CONNECTING:
|
case WiFiRetryPhase::SCAN_CONNECTING:
|
||||||
return LOG_STR("SCAN_CONNECTING");
|
return LOG_STR("SCAN_CONNECTING");
|
||||||
case WiFiRetryPhase::SCAN_WITH_HIDDEN:
|
case WiFiRetryPhase::RETRY_HIDDEN:
|
||||||
return LOG_STR("SCAN_HIDDEN");
|
return LOG_STR("RETRY_HIDDEN");
|
||||||
case WiFiRetryPhase::RESTARTING_ADAPTER:
|
case WiFiRetryPhase::RESTARTING_ADAPTER:
|
||||||
return LOG_STR("RESTARTING");
|
return LOG_STR("RESTARTING");
|
||||||
default:
|
default:
|
||||||
@@ -133,7 +154,7 @@ static const LogString *retry_phase_to_log_string(WiFiRetryPhase phase) {
|
|||||||
// After 2 genuine failures, priority degradation ensures we skip this BSSID on subsequent scans.
|
// After 2 genuine failures, priority degradation ensures we skip this BSSID on subsequent scans.
|
||||||
static constexpr uint8_t WIFI_RETRY_COUNT_PER_BSSID = 2;
|
static constexpr uint8_t WIFI_RETRY_COUNT_PER_BSSID = 2;
|
||||||
|
|
||||||
// 1 attempt per SSID in SCAN_WITH_HIDDEN phase
|
// 1 attempt per SSID in RETRY_HIDDEN phase
|
||||||
// Rationale: Try hidden mode once, then rescan to get next best BSSID via priority system
|
// Rationale: Try hidden mode once, then rescan to get next best BSSID via priority system
|
||||||
static constexpr uint8_t WIFI_RETRY_COUNT_PER_SSID = 1;
|
static constexpr uint8_t WIFI_RETRY_COUNT_PER_SSID = 1;
|
||||||
|
|
||||||
@@ -149,11 +170,14 @@ static constexpr uint8_t get_max_retries_for_phase(WiFiRetryPhase phase) {
|
|||||||
#endif
|
#endif
|
||||||
// INITIAL_CONNECT and FAST_CONNECT_CYCLING_APS both use 1 attempt per AP (fast_connect mode)
|
// INITIAL_CONNECT and FAST_CONNECT_CYCLING_APS both use 1 attempt per AP (fast_connect mode)
|
||||||
return WIFI_RETRY_COUNT_PER_AP;
|
return WIFI_RETRY_COUNT_PER_AP;
|
||||||
|
case WiFiRetryPhase::EXPLICIT_HIDDEN:
|
||||||
|
// Explicitly hidden network: 1 attempt (user marked as hidden, try once then scan)
|
||||||
|
return WIFI_RETRY_COUNT_PER_SSID;
|
||||||
case WiFiRetryPhase::SCAN_CONNECTING:
|
case WiFiRetryPhase::SCAN_CONNECTING:
|
||||||
// Scan-based phase: 2 attempts per BSSID (handles transient auth failures after scan)
|
// Scan-based phase: 2 attempts per BSSID (handles transient auth failures after scan)
|
||||||
return WIFI_RETRY_COUNT_PER_BSSID;
|
return WIFI_RETRY_COUNT_PER_BSSID;
|
||||||
case WiFiRetryPhase::SCAN_WITH_HIDDEN:
|
case WiFiRetryPhase::RETRY_HIDDEN:
|
||||||
// Hidden network mode: 2 attempts per SSID
|
// Hidden network mode: 1 attempt per SSID
|
||||||
return WIFI_RETRY_COUNT_PER_SSID;
|
return WIFI_RETRY_COUNT_PER_SSID;
|
||||||
default:
|
default:
|
||||||
return WIFI_RETRY_COUNT_PER_BSSID;
|
return WIFI_RETRY_COUNT_PER_BSSID;
|
||||||
@@ -194,28 +218,36 @@ bool WiFiComponent::ssid_was_seen_in_scan_(const std::string &ssid) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t WiFiComponent::find_next_hidden_sta_(int8_t start_index) {
|
int8_t WiFiComponent::find_next_hidden_sta_(int8_t start_index, bool include_explicit_hidden) {
|
||||||
// Find next SSID that wasn't in scan results (might be hidden)
|
// Find next SSID that wasn't in scan results (might be hidden)
|
||||||
// Start searching from start_index + 1
|
// Start searching from start_index + 1
|
||||||
for (size_t i = start_index + 1; i < this->sta_.size(); i++) {
|
for (size_t i = start_index + 1; i < this->sta_.size(); i++) {
|
||||||
if (!this->ssid_was_seen_in_scan_(this->sta_[i].get_ssid())) {
|
const auto &sta = this->sta_[i];
|
||||||
ESP_LOGD(TAG, "Hidden candidate " LOG_SECRET("'%s'") " at index %d", this->sta_[i].get_ssid().c_str(),
|
|
||||||
static_cast<int>(i));
|
// If include_explicit_hidden is false, skip SSIDs marked as hidden (already tried in EXPLICIT_HIDDEN phase)
|
||||||
|
if (!include_explicit_hidden && sta.get_hidden()) {
|
||||||
|
ESP_LOGD(TAG, "Skipping " LOG_SECRET("'%s'") " (explicit hidden, already tried)", sta.get_ssid().c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->ssid_was_seen_in_scan_(sta.get_ssid())) {
|
||||||
|
ESP_LOGD(TAG, "Hidden candidate " LOG_SECRET("'%s'") " at index %d", sta.get_ssid().c_str(), static_cast<int>(i));
|
||||||
return static_cast<int8_t>(i);
|
return static_cast<int8_t>(i);
|
||||||
}
|
}
|
||||||
ESP_LOGD(TAG, "Skipping " LOG_SECRET("'%s'") " (visible in scan)", this->sta_[i].get_ssid().c_str());
|
ESP_LOGD(TAG, "Skipping " LOG_SECRET("'%s'") " (visible in scan)", sta.get_ssid().c_str());
|
||||||
}
|
}
|
||||||
// No hidden SSIDs found
|
// No hidden SSIDs found
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WiFiComponent::start_initial_connection_() {
|
void WiFiComponent::start_initial_connection_() {
|
||||||
// If all networks are configured as hidden, skip scanning and go straight to hidden mode
|
// If first network (highest priority) is explicitly marked hidden, try it first before scanning
|
||||||
if (this->all_networks_hidden_()) {
|
// This respects user's priority order when they explicitly configure hidden networks
|
||||||
ESP_LOGI(TAG, "Starting in hidden mode (all networks hidden)");
|
if (!this->sta_.empty() && this->sta_[0].get_hidden()) {
|
||||||
|
ESP_LOGI(TAG, "Starting with explicit hidden network (highest priority)");
|
||||||
this->selected_sta_index_ = 0;
|
this->selected_sta_index_ = 0;
|
||||||
this->retry_phase_ = WiFiRetryPhase::SCAN_WITH_HIDDEN;
|
this->retry_phase_ = WiFiRetryPhase::EXPLICIT_HIDDEN;
|
||||||
WiFiAP params = this->build_wifi_ap_from_selected_();
|
WiFiAP params = this->build_params_for_current_phase_();
|
||||||
this->start_connecting(params, false);
|
this->start_connecting(params, false);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(TAG, "Starting scan");
|
ESP_LOGI(TAG, "Starting scan");
|
||||||
@@ -302,7 +334,7 @@ void WiFiComponent::start() {
|
|||||||
if (!loaded_fast_connect) {
|
if (!loaded_fast_connect) {
|
||||||
// No saved settings available - use first config (will use SSID from config)
|
// No saved settings available - use first config (will use SSID from config)
|
||||||
this->selected_sta_index_ = 0;
|
this->selected_sta_index_ = 0;
|
||||||
params = this->build_wifi_ap_from_selected_();
|
params = this->build_params_for_current_phase_();
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "Starting fast_connect (%s) " LOG_SECRET("'%s'"),
|
ESP_LOGI(TAG, "Starting fast_connect (%s) " LOG_SECRET("'%s'"),
|
||||||
loaded_fast_connect ? LOG_STR_LITERAL("saved") : LOG_STR_LITERAL("config"), params.get_ssid().c_str());
|
loaded_fast_connect ? LOG_STR_LITERAL("saved") : LOG_STR_LITERAL("config"), params.get_ssid().c_str());
|
||||||
@@ -533,46 +565,9 @@ void WiFiComponent::set_sta(const WiFiAP &ap) {
|
|||||||
this->selected_sta_index_ = 0;
|
this->selected_sta_index_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
WiFiAP WiFiComponent::build_wifi_ap_from_selected_() const {
|
|
||||||
// PRECONDITION: selected_sta_index_ must be valid (ensured by all callers)
|
|
||||||
const WiFiAP *config = this->get_selected_sta_();
|
|
||||||
assert(config != nullptr);
|
|
||||||
WiFiAP params = *config;
|
|
||||||
|
|
||||||
// SYNCHRONIZATION: selected_sta_index_ and scan_result_[0] are kept in sync after wifi_scan_done():
|
|
||||||
// - wifi_scan_done() sorts all scan results by priority/RSSI (best first)
|
|
||||||
// - It then finds which sta_[i] config matches scan_result_[0]
|
|
||||||
// - Sets selected_sta_index_ = i to record that matching config
|
|
||||||
// This sync holds until scan_result_ is cleared (e.g., after connection or when advancing to next AP)
|
|
||||||
if (!this->scan_result_.empty()) {
|
|
||||||
// Override with scan data - network is visible
|
|
||||||
if (!this->scan_result_[0].get_matches()) {
|
|
||||||
// BUG: Sorting should ensure matching networks are always first
|
|
||||||
// This should never happen - indicates a bug in wifi_scan_result_is_better() or scan result matching
|
|
||||||
ESP_LOGE(TAG,
|
|
||||||
"BUG: Selected AP config " LOG_SECRET("(SSID='%s')") " does not match best scan result " LOG_SECRET(
|
|
||||||
"(SSID='%s')") "; using config values only",
|
|
||||||
config->get_ssid().c_str(), this->scan_result_[0].get_ssid().c_str());
|
|
||||||
} else {
|
|
||||||
// Apply best scan result to params
|
|
||||||
apply_scan_result_to_params(params, this->scan_result_[0]);
|
|
||||||
}
|
|
||||||
} else if (params.get_hidden()) {
|
|
||||||
// Hidden network - clear BSSID and channel even if set in config
|
|
||||||
// There might be multiple hidden networks with same SSID but we can't know which is correct
|
|
||||||
// Rely on probe-req with just SSID. Empty channel triggers ALL_CHANNEL_SCAN.
|
|
||||||
params.set_bssid(optional<bssid_t>{});
|
|
||||||
params.set_channel(optional<uint8_t>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
WiFiAP WiFiComponent::build_params_for_current_phase_() {
|
WiFiAP WiFiComponent::build_params_for_current_phase_() {
|
||||||
const WiFiAP *config = this->get_selected_sta_();
|
const WiFiAP *config = this->get_selected_sta_();
|
||||||
if (!config) {
|
assert(config != nullptr);
|
||||||
return WiFiAP{};
|
|
||||||
}
|
|
||||||
|
|
||||||
WiFiAP params = *config;
|
WiFiAP params = *config;
|
||||||
|
|
||||||
@@ -585,6 +580,14 @@ WiFiAP WiFiComponent::build_params_for_current_phase_() {
|
|||||||
// BSSID/channel from config if user specified them, otherwise empty
|
// BSSID/channel from config if user specified them, otherwise empty
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WiFiRetryPhase::EXPLICIT_HIDDEN:
|
||||||
|
case WiFiRetryPhase::RETRY_HIDDEN:
|
||||||
|
// Hidden network mode: clear BSSID/channel to trigger probe request
|
||||||
|
// (both explicit hidden and retry hidden use same behavior)
|
||||||
|
params.set_bssid(optional<bssid_t>{});
|
||||||
|
params.set_channel(optional<uint8_t>{});
|
||||||
|
break;
|
||||||
|
|
||||||
case WiFiRetryPhase::SCAN_CONNECTING:
|
case WiFiRetryPhase::SCAN_CONNECTING:
|
||||||
// Scan-based phase: always use best scan result (index 0 - highest priority after sorting)
|
// Scan-based phase: always use best scan result (index 0 - highest priority after sorting)
|
||||||
if (!this->scan_result_.empty()) {
|
if (!this->scan_result_.empty()) {
|
||||||
@@ -592,12 +595,6 @@ WiFiAP WiFiComponent::build_params_for_current_phase_() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WiFiRetryPhase::SCAN_WITH_HIDDEN:
|
|
||||||
// Hidden network mode: clear BSSID/channel to trigger probe request
|
|
||||||
params.set_bssid(optional<bssid_t>{});
|
|
||||||
params.set_channel(optional<uint8_t>{});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WiFiRetryPhase::RESTARTING_ADAPTER:
|
case WiFiRetryPhase::RESTARTING_ADAPTER:
|
||||||
// Should not be building params during restart
|
// Should not be building params during restart
|
||||||
break;
|
break;
|
||||||
@@ -943,7 +940,7 @@ void WiFiComponent::check_scanning_finished() {
|
|||||||
// SYNCHRONIZATION POINT: Establish link between scan_result_[0] and selected_sta_index_
|
// SYNCHRONIZATION POINT: Establish link between scan_result_[0] and selected_sta_index_
|
||||||
// After sorting, scan_result_[0] contains the best network. Now find which sta_[i] config
|
// After sorting, scan_result_[0] contains the best network. Now find which sta_[i] config
|
||||||
// matches that network and record it in selected_sta_index_. This keeps the two indices
|
// matches that network and record it in selected_sta_index_. This keeps the two indices
|
||||||
// synchronized so build_wifi_ap_from_selected_() can safely use both to build connection parameters.
|
// synchronized so build_params_for_current_phase_() can safely use both to build connection parameters.
|
||||||
const WiFiScanResult &scan_res = this->scan_result_[0];
|
const WiFiScanResult &scan_res = this->scan_result_[0];
|
||||||
bool found_match = false;
|
bool found_match = false;
|
||||||
if (scan_res.get_matches()) {
|
if (scan_res.get_matches()) {
|
||||||
@@ -962,7 +959,7 @@ void WiFiComponent::check_scanning_finished() {
|
|||||||
ESP_LOGW(TAG, "No matching network found");
|
ESP_LOGW(TAG, "No matching network found");
|
||||||
// No scan results matched our configured networks - transition directly to hidden mode
|
// No scan results matched our configured networks - transition directly to hidden mode
|
||||||
// Don't call retry_connect() since we never attempted a connection (no BSSID to penalize)
|
// Don't call retry_connect() since we never attempted a connection (no BSSID to penalize)
|
||||||
this->transition_to_phase_(WiFiRetryPhase::SCAN_WITH_HIDDEN);
|
this->transition_to_phase_(WiFiRetryPhase::RETRY_HIDDEN);
|
||||||
// Now start connection attempt in hidden mode
|
// Now start connection attempt in hidden mode
|
||||||
} else if (this->transition_to_phase_(WiFiRetryPhase::SCAN_CONNECTING)) {
|
} else if (this->transition_to_phase_(WiFiRetryPhase::SCAN_CONNECTING)) {
|
||||||
return; // scan started, wait for next loop iteration
|
return; // scan started, wait for next loop iteration
|
||||||
@@ -970,7 +967,7 @@ void WiFiComponent::check_scanning_finished() {
|
|||||||
|
|
||||||
yield();
|
yield();
|
||||||
|
|
||||||
WiFiAP params = this->build_wifi_ap_from_selected_();
|
WiFiAP params = this->build_params_for_current_phase_();
|
||||||
// Ensure we're in SCAN_CONNECTING phase when connecting with scan results
|
// Ensure we're in SCAN_CONNECTING phase when connecting with scan results
|
||||||
// (needed when scan was started directly without transition_to_phase_, e.g., initial scan)
|
// (needed when scan was started directly without transition_to_phase_, e.g., initial scan)
|
||||||
this->start_connecting(params, false);
|
this->start_connecting(params, false);
|
||||||
@@ -994,7 +991,7 @@ void WiFiComponent::check_connecting_finished() {
|
|||||||
ESP_LOGI(TAG, "Connected");
|
ESP_LOGI(TAG, "Connected");
|
||||||
// Warn if we had to retry with hidden network mode for a network that's not marked hidden
|
// Warn if we had to retry with hidden network mode for a network that's not marked hidden
|
||||||
// Only warn if we actually connected without scan data (SSID only), not if scan succeeded on retry
|
// Only warn if we actually connected without scan data (SSID only), not if scan succeeded on retry
|
||||||
if (const WiFiAP *config = this->get_selected_sta_(); this->retry_phase_ == WiFiRetryPhase::SCAN_WITH_HIDDEN &&
|
if (const WiFiAP *config = this->get_selected_sta_(); this->retry_phase_ == WiFiRetryPhase::RETRY_HIDDEN &&
|
||||||
config && !config->get_hidden() &&
|
config && !config->get_hidden() &&
|
||||||
this->scan_result_.empty()) {
|
this->scan_result_.empty()) {
|
||||||
ESP_LOGW(TAG, LOG_SECRET("'%s'") " should be marked hidden", config->get_ssid().c_str());
|
ESP_LOGW(TAG, LOG_SECRET("'%s'") " should be marked hidden", config->get_ssid().c_str());
|
||||||
@@ -1087,10 +1084,30 @@ WiFiRetryPhase WiFiComponent::determine_next_phase_() {
|
|||||||
// No more APs to try, fall back to scan
|
// No more APs to try, fall back to scan
|
||||||
return WiFiRetryPhase::SCAN_CONNECTING;
|
return WiFiRetryPhase::SCAN_CONNECTING;
|
||||||
|
|
||||||
|
case WiFiRetryPhase::EXPLICIT_HIDDEN:
|
||||||
|
// Try all explicitly hidden networks before scanning
|
||||||
|
if (this->num_retried_ + 1 < WIFI_RETRY_COUNT_PER_SSID) {
|
||||||
|
return WiFiRetryPhase::EXPLICIT_HIDDEN; // Keep retrying same SSID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exhausted retries on current SSID - check for more explicitly hidden networks
|
||||||
|
// Stop when we reach a visible network (proceed to scanning)
|
||||||
|
for (size_t i = this->selected_sta_index_ + 1; i < this->sta_.size(); i++) {
|
||||||
|
if (this->sta_[i].get_hidden()) {
|
||||||
|
// Found another explicitly hidden network
|
||||||
|
return WiFiRetryPhase::EXPLICIT_HIDDEN;
|
||||||
|
}
|
||||||
|
// Reached a visible network - stop trying explicit hidden and proceed to scanning
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No more consecutive explicitly hidden networks - proceed to scanning
|
||||||
|
return WiFiRetryPhase::SCAN_CONNECTING;
|
||||||
|
|
||||||
case WiFiRetryPhase::SCAN_CONNECTING:
|
case WiFiRetryPhase::SCAN_CONNECTING:
|
||||||
// If scan found no matching networks, skip to hidden network mode
|
// If scan found no matching networks, skip to hidden network mode
|
||||||
if (!this->scan_result_.empty() && !this->scan_result_[0].get_matches()) {
|
if (!this->scan_result_.empty() && !this->scan_result_[0].get_matches()) {
|
||||||
return WiFiRetryPhase::SCAN_WITH_HIDDEN;
|
return WiFiRetryPhase::RETRY_HIDDEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->num_retried_ + 1 < WIFI_RETRY_COUNT_PER_BSSID) {
|
if (this->num_retried_ + 1 < WIFI_RETRY_COUNT_PER_BSSID) {
|
||||||
@@ -1101,19 +1118,19 @@ WiFiRetryPhase WiFiComponent::determine_next_phase_() {
|
|||||||
// Its priority has been decreased, so on next scan it will be sorted lower
|
// Its priority has been decreased, so on next scan it will be sorted lower
|
||||||
// and we'll try the next best BSSID.
|
// and we'll try the next best BSSID.
|
||||||
// Always try hidden mode first - it will skip visible SSIDs and return to scanning
|
// Always try hidden mode first - it will skip visible SSIDs and return to scanning
|
||||||
return WiFiRetryPhase::SCAN_WITH_HIDDEN;
|
return WiFiRetryPhase::RETRY_HIDDEN;
|
||||||
|
|
||||||
case WiFiRetryPhase::SCAN_WITH_HIDDEN:
|
case WiFiRetryPhase::RETRY_HIDDEN:
|
||||||
// If no hidden SSIDs to try (selected_sta_index_ == -1), skip directly to rescan
|
// If no hidden SSIDs to try (selected_sta_index_ == -1), skip directly to rescan
|
||||||
if (this->selected_sta_index_ >= 0) {
|
if (this->selected_sta_index_ >= 0) {
|
||||||
if (this->num_retried_ + 1 < WIFI_RETRY_COUNT_PER_SSID) {
|
if (this->num_retried_ + 1 < WIFI_RETRY_COUNT_PER_SSID) {
|
||||||
return WiFiRetryPhase::SCAN_WITH_HIDDEN; // Keep retrying same SSID
|
return WiFiRetryPhase::RETRY_HIDDEN; // Keep retrying same SSID
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exhausted retries on current SSID - check if there are more potentially hidden SSIDs to try
|
// Exhausted retries on current SSID - check if there are more potentially hidden SSIDs to try
|
||||||
if (this->selected_sta_index_ < static_cast<int8_t>(this->sta_.size()) - 1) {
|
if (this->selected_sta_index_ < static_cast<int8_t>(this->sta_.size()) - 1) {
|
||||||
// More SSIDs available - stay in SCAN_WITH_HIDDEN, advance will happen in retry_connect()
|
// More SSIDs available - stay in RETRY_HIDDEN, advance will happen in retry_connect()
|
||||||
return WiFiRetryPhase::SCAN_WITH_HIDDEN;
|
return WiFiRetryPhase::RETRY_HIDDEN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Exhausted all potentially hidden SSIDs - rescan to try next BSSID
|
// Exhausted all potentially hidden SSIDs - rescan to try next BSSID
|
||||||
@@ -1181,25 +1198,28 @@ bool WiFiComponent::transition_to_phase_(WiFiRetryPhase new_phase) {
|
|||||||
this->selected_sta_index_ = 0;
|
this->selected_sta_index_ = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// Trigger scan if we don't have scan results OR if looping back from SCAN_WITH_HIDDEN
|
// Trigger scan if we don't have scan results OR if looping back from RETRY_HIDDEN
|
||||||
if (this->scan_result_.empty() || old_phase == WiFiRetryPhase::SCAN_WITH_HIDDEN ||
|
if (this->scan_result_.empty() || old_phase == WiFiRetryPhase::RETRY_HIDDEN ||
|
||||||
old_phase == WiFiRetryPhase::RESTARTING_ADAPTER) {
|
old_phase == WiFiRetryPhase::RESTARTING_ADAPTER) {
|
||||||
this->start_scanning();
|
this->start_scanning();
|
||||||
return true; // Started scan, wait for completion
|
return true; // Started scan, wait for completion
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WiFiRetryPhase::SCAN_WITH_HIDDEN:
|
case WiFiRetryPhase::RETRY_HIDDEN:
|
||||||
// Starting hidden mode - find first SSID that wasn't in scan results
|
// Starting hidden mode - find first SSID that wasn't in scan results
|
||||||
if (old_phase == WiFiRetryPhase::SCAN_CONNECTING) {
|
if (old_phase == WiFiRetryPhase::SCAN_CONNECTING) {
|
||||||
// Keep scan results so we can skip SSIDs that were visible in the scan
|
// Keep scan results so we can skip SSIDs that were visible in the scan
|
||||||
// Don't clear scan_result_ - we need it to know which SSIDs are NOT hidden
|
// Don't clear scan_result_ - we need it to know which SSIDs are NOT hidden
|
||||||
|
|
||||||
// Find first SSID that might be hidden (start from index -1 to search from beginning)
|
// If first network is marked hidden, we went through EXPLICIT_HIDDEN phase
|
||||||
this->selected_sta_index_ = this->find_next_hidden_sta_(-1);
|
// In that case, skip networks marked hidden:true (already tried)
|
||||||
|
// Otherwise, include them (they haven't been tried yet)
|
||||||
|
bool went_through_explicit_hidden = !this->sta_.empty() && this->sta_[0].get_hidden();
|
||||||
|
this->selected_sta_index_ = this->find_next_hidden_sta_(-1, !went_through_explicit_hidden);
|
||||||
|
|
||||||
if (this->selected_sta_index_ == -1) {
|
if (this->selected_sta_index_ == -1) {
|
||||||
ESP_LOGD(TAG, "All SSIDs visible, skipping hidden mode");
|
ESP_LOGD(TAG, "All SSIDs visible or already tried, skipping hidden mode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1270,7 +1290,7 @@ void WiFiComponent::log_and_adjust_priority_for_failed_connect_() {
|
|||||||
///
|
///
|
||||||
/// Phase-specific behavior:
|
/// Phase-specific behavior:
|
||||||
/// - FAST_CONNECT_CYCLING_APS: Always advance to next AP (no retries per AP)
|
/// - FAST_CONNECT_CYCLING_APS: Always advance to next AP (no retries per AP)
|
||||||
/// - SCAN_WITH_HIDDEN: Advance to next SSID after exhausting retries on current SSID
|
/// - RETRY_HIDDEN: Advance to next SSID after exhausting retries on current SSID
|
||||||
/// - Other phases: Increment retry counter (will retry same target)
|
/// - Other phases: Increment retry counter (will retry same target)
|
||||||
void WiFiComponent::advance_to_next_target_or_increment_retry_() {
|
void WiFiComponent::advance_to_next_target_or_increment_retry_() {
|
||||||
WiFiRetryPhase current_phase = this->retry_phase_;
|
WiFiRetryPhase current_phase = this->retry_phase_;
|
||||||
@@ -1286,9 +1306,29 @@ void WiFiComponent::advance_to_next_target_or_increment_retry_() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (current_phase == WiFiRetryPhase::SCAN_WITH_HIDDEN && this->num_retried_ + 1 >= WIFI_RETRY_COUNT_PER_SSID) {
|
if (current_phase == WiFiRetryPhase::EXPLICIT_HIDDEN && this->num_retried_ + 1 >= WIFI_RETRY_COUNT_PER_SSID) {
|
||||||
|
// Explicit hidden: exhausted retries on current SSID, find next explicitly hidden network
|
||||||
|
// Stop when we reach a visible network (proceed to scanning)
|
||||||
|
for (size_t i = this->selected_sta_index_ + 1; i < this->sta_.size(); i++) {
|
||||||
|
if (this->sta_[i].get_hidden()) {
|
||||||
|
this->selected_sta_index_ = static_cast<int8_t>(i);
|
||||||
|
this->num_retried_ = 0;
|
||||||
|
ESP_LOGD(TAG, "Next explicit hidden network at index %d", static_cast<int>(i));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Reached a visible network - stop and fall through to trigger phase change
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// No more consecutive explicit hidden networks found - fall through to trigger phase change
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_phase == WiFiRetryPhase::RETRY_HIDDEN && this->num_retried_ + 1 >= WIFI_RETRY_COUNT_PER_SSID) {
|
||||||
// Hidden mode: exhausted retries on current SSID, find next potentially hidden SSID
|
// Hidden mode: exhausted retries on current SSID, find next potentially hidden SSID
|
||||||
int8_t next_index = this->find_next_hidden_sta_(this->selected_sta_index_);
|
// If first network is marked hidden, we went through EXPLICIT_HIDDEN phase
|
||||||
|
// In that case, skip networks marked hidden:true (already tried)
|
||||||
|
// Otherwise, include them (they haven't been tried yet)
|
||||||
|
bool went_through_explicit_hidden = !this->sta_.empty() && this->sta_[0].get_hidden();
|
||||||
|
int8_t next_index = this->find_next_hidden_sta_(this->selected_sta_index_, !went_through_explicit_hidden);
|
||||||
if (next_index != -1) {
|
if (next_index != -1) {
|
||||||
// Found another potentially hidden SSID
|
// Found another potentially hidden SSID
|
||||||
this->selected_sta_index_ = next_index;
|
this->selected_sta_index_ = next_index;
|
||||||
|
|||||||
@@ -102,10 +102,12 @@ enum class WiFiRetryPhase : uint8_t {
|
|||||||
/// Fast connect mode: cycling through configured APs (config-only, no scan)
|
/// Fast connect mode: cycling through configured APs (config-only, no scan)
|
||||||
FAST_CONNECT_CYCLING_APS,
|
FAST_CONNECT_CYCLING_APS,
|
||||||
#endif
|
#endif
|
||||||
|
/// Explicitly hidden networks (user marked as hidden, try before scanning)
|
||||||
|
EXPLICIT_HIDDEN,
|
||||||
/// Scan-based: connecting to best AP from scan results
|
/// Scan-based: connecting to best AP from scan results
|
||||||
SCAN_CONNECTING,
|
SCAN_CONNECTING,
|
||||||
/// Retrying with hidden network flag
|
/// Retry networks not found in scan (might be hidden)
|
||||||
SCAN_WITH_HIDDEN,
|
RETRY_HIDDEN,
|
||||||
/// Restarting WiFi adapter to clear stuck state
|
/// Restarting WiFi adapter to clear stuck state
|
||||||
RESTARTING_ADAPTER,
|
RESTARTING_ADAPTER,
|
||||||
};
|
};
|
||||||
@@ -357,7 +359,6 @@ class WiFiComponent : public Component {
|
|||||||
#endif // USE_WIFI_AP
|
#endif // USE_WIFI_AP
|
||||||
|
|
||||||
void print_connect_params_();
|
void print_connect_params_();
|
||||||
WiFiAP build_wifi_ap_from_selected_() const;
|
|
||||||
WiFiAP build_params_for_current_phase_();
|
WiFiAP build_params_for_current_phase_();
|
||||||
|
|
||||||
/// Determine next retry phase based on current state and failure conditions
|
/// Determine next retry phase based on current state and failure conditions
|
||||||
@@ -373,7 +374,9 @@ class WiFiComponent : public Component {
|
|||||||
bool ssid_was_seen_in_scan_(const std::string &ssid) const;
|
bool ssid_was_seen_in_scan_(const std::string &ssid) const;
|
||||||
/// Find next SSID that wasn't in scan results (might be hidden)
|
/// Find next SSID that wasn't in scan results (might be hidden)
|
||||||
/// Returns index of next potentially hidden SSID, or -1 if none found
|
/// Returns index of next potentially hidden SSID, or -1 if none found
|
||||||
int8_t find_next_hidden_sta_(int8_t start_index);
|
/// @param start_index Start searching from index after this (-1 to start from beginning)
|
||||||
|
/// @param include_explicit_hidden If true, include SSIDs marked hidden:true. If false, only find truly hidden SSIDs.
|
||||||
|
int8_t find_next_hidden_sta_(int8_t start_index, bool include_explicit_hidden = true);
|
||||||
/// Log failed connection and decrease BSSID priority to avoid repeated attempts
|
/// Log failed connection and decrease BSSID priority to avoid repeated attempts
|
||||||
void log_and_adjust_priority_for_failed_connect_();
|
void log_and_adjust_priority_for_failed_connect_();
|
||||||
/// Advance to next target (AP/SSID) within current phase, or increment retry counter
|
/// Advance to next target (AP/SSID) within current phase, or increment retry counter
|
||||||
|
|||||||
Reference in New Issue
Block a user