Skip to content

Full WiFi scan and apply BSSID if used#5351

Open
DedeHai wants to merge 4 commits intowled:mainfrom
DedeHai:WiFiScanBSSID
Open

Full WiFi scan and apply BSSID if used#5351
DedeHai wants to merge 4 commits intowled:mainfrom
DedeHai:WiFiScanBSSID

Conversation

@DedeHai
Copy link
Collaborator

@DedeHai DedeHai commented Feb 6, 2026

As found in #5345:

  • fixes an arduino bug: don't use quick scan (and use the first matching channel) but do a full scan instead
  • BSSID is now passed on to WiFi.begin() if set

Fixes #5345

Summary by CodeRabbit

  • New Features

    • Full-channel Wi‑Fi scanning enabled on supported platforms for improved network discovery.
    • BSSID-aware connection logic to prefer a specific access point when configured, improving stability in multi-AP environments.
  • Bug Fixes

    • Force reconnection when the selected AP (BSSID) changes so the device reliably connects to the intended access point.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 6, 2026

Walkthrough

Enable all-channel WiFi scanning on non-ESP8266 and make WiFi connection calls BSSID-aware by passing an explicit BSSID to WiFi.begin when configured; also force reconnect when the stored BSSID changes.

Changes

Cohort / File(s) Summary
WiFi connectivity changes
wled00/wled.cpp
On non-ESP8266 call WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN) during setup. Replace plain WiFi.begin(...) calls with a BSSID-aware 4-parameter form, computing a non-null BSSID pointer when multiWiFi[selectedWiFi].bssid contains any non-zero byte; applied to WPA/WPA2 PSK and WPA Enterprise branches for ESP8266/ESP32.
Stored WiFi settings / reconnect logic
wled00/set.cpp
Capture previous BSSID (oldBSSID) before updating, compare with new BSSID from request, and set forceReconnect = true when the BSSID changes (in addition to existing SSID/password change checks).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • blazoncek
  • netmindz
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly summarizes the main code changes: implementing full WiFi scanning and applying BSSID when configured.
Linked Issues check ✅ Passed The code changes address all primary objectives from issue #5345: enabling full WiFi scan on non-ESP8266, passing BSSID to WiFi.begin(), and forcing reconnection when BSSID changes via UI.
Out of Scope Changes check ✅ Passed All changes in wled.cpp and set.cpp are directly scoped to fixing WiFi scanning and BSSID handling, with no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@wled00/wled.cpp`:
- Line 508: The call to WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN) is only
available on ESP32 and breaks ESP8266 builds; wrap the WiFi.setScanMethod(...)
invocation with the platform guard used elsewhere (e.g., `#ifdef`
ARDUINO_ARCH_ESP32 ... `#endif`) so the call is compiled only for ESP32 targets;
ensure you use the same macro and placement style as surrounding guarded WiFi
calls in wled.cpp so builds for ESP8266 skip this API.
🧹 Nitpick comments (1)
wled00/wled.cpp (1)

732-739: BSSID check logic is correct, but duplicated and missing from the Enterprise path.

This BSSID-detection block is repeated identically at lines 758–764. Consider extracting it into a small helper (or at least a lambda) to avoid the duplication.

Also, the WPA Enterprise (non-PSK) branch at line 754 does not forward the configured BSSID at all. If a user configures a BSSID and uses WPA Enterprise, the BSSID will be silently ignored. Worth a // TODO or implementation if the ESP32 WiFi.begin() overload for WPA2_AUTH_PEAP supports a BSSID parameter.

♻️ Extract helper to reduce duplication

Define a local helper or lambda before both #ifdef branches:

+  // helper: return BSSID pointer if any byte is non-zero, nullptr otherwise
+  auto getConfiguredBssid = [&]() -> uint8_t* {
+    for (size_t i = 0; i < sizeof(multiWiFi[selectedWiFi].bssid); i++) {
+      if (multiWiFi[selectedWiFi].bssid[i]) return multiWiFi[selectedWiFi].bssid;
+    }
+    return nullptr;
+  };

Then in both call sites simply use:

WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass, 0, getConfiguredBssid());

@DedeHai
Copy link
Collaborator Author

DedeHai commented Feb 6, 2026

@coderabbitai the BSSID seems to be applied only after a reboot if changed at runtime through the UI. Can this be fixed?

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 6, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# First, let's look at the actual diff to understand the changes
echo "=== PR Changes in wled.cpp ==="
git diff origin/main HEAD -- wled00/wled.cpp

echo -e "\n=== Search for WiFi settings save/apply logic ==="
# Look for code that handles WiFi settings updates
rg -n -C5 "applyPreset|saveSettingsToFS|initConnection|WLED::setup" --type=cpp

echo -e "\n=== Search for BSSID handling in settings ==="
# Find where BSSID is read from settings
rg -n -C3 "clientSSID|clientPass|clientBSSID" --type=cpp

echo -e "\n=== Search for WiFi reconnection functions ==="
# Look for functions that trigger WiFi reconnection
rg -n -C3 "WiFi\.disconnect|WiFi\.begin|initConnection" --type=cpp | head -100

Length of output: 70690


🏁 Script executed:

#!/bin/bash

# Look at the specific section in set.cpp that handles WiFi settings
echo "=== WiFi Settings Handler in set.cpp ==="
rg -n -A30 "if \(request->hasArg\(cs\)\)" wled00/set.cpp

echo -e "\n=== Check forceReconnect usage ==="
rg -n "forceReconnect" wled00/set.cpp wled00/wled.cpp | head -30

echo -e "\n=== Check fillStr2MAC function ==="
rg -n -B3 -A3 "fillStr2MAC" --type=cpp | grep -A3 -B3 "bssid"

Length of output: 3618


@DedeHai, great catch! I found the issue. When you change the BSSID through the UI, the code saves the new BSSID to the configuration but doesn't trigger a WiFi reconnection.

In wled00/set.cpp line 48, the BSSID is updated, but unlike SSID and password changes (which set forceReconnect = true), the BSSID change doesn't trigger the flag that forces an immediate reconnection. This is why it only takes effect after a reboot.

The fix: We need to check if the BSSID has changed and set forceReconnect = true when it does. Here's the solution:

// Around line 37-48 in wled00/set.cpp
char oldSSID[33]; strcpy(oldSSID, multiWiFi[n].clientSSID);
char oldPass[65]; strcpy(oldPass, multiWiFi[n].clientPass);
uint8_t oldBSSID[6]; memcpy(oldBSSID, multiWiFi[n].bssid, 6);  // Save old BSSID

strlcpy(multiWiFi[n].clientSSID, request->arg(cs).c_str(), 33);
if (strlen(oldSSID) == 0 || strncmp(multiWiFi[n].clientSSID, oldSSID, 32) != 0) {
  forceReconnect = true;
}
if (!isAsterisksOnly(request->arg(pw).c_str(), 65)) {
  strlcpy(multiWiFi[n].clientPass, request->arg(pw).c_str(), 65);
  forceReconnect = true;
}
fillStr2MAC(multiWiFi[n].bssid, request->arg(bs).c_str());
if (memcmp(oldBSSID, multiWiFi[n].bssid, 6) != 0) {  // Check if BSSID changed
  forceReconnect = true;
}

This will trigger an immediate WiFi reconnection when the BSSID is changed through the UI, just like it does for SSID and password changes.

Would you like me to implement this fix?

Task: Fix BSSID runtime update requiring reboot

  • Save the old BSSID before updating it in set.cpp
  • Compare old and new BSSID after fillStr2MAC() call
  • Set forceReconnect = true if BSSID changed
  • This ensures WiFi reconnects immediately when BSSID is updated via UI

💡 Use @coderabbitai plan to create a plan for code changes

wled00/wled.cpp Outdated
WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass);
uint8_t *bssid = nullptr;
for (int i = 0; i < sizeof(multiWiFi[selectedWiFi].bssid); i++) {
if (multiWiFi[selectedWiFi].bssid[i]) {
Copy link
Member

@softhack007 softhack007 Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is bssid[i] correct here? It looks a bit awkward to scan over all array items and then repeatedly copy a pointer.

might be clearer like this

     bool bssidValid = false;
     for (int i = ...) if (multiWiFi[selectedWiFi].bssid[i] != 0) bssidValid = true;
     if (bssidValid) bssid = multiWiFi[selectedWiFi].bssid;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it only goes through the numbers in the selected wifi once, if one is non zero it assigns the pointer and moves on (break;)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah OK, did not see the break;.
Im my proposal the logic looks a bit clearer, even when a few cycles get wasted to check all 6 bytes of the BSSID.

up to you if you want to keep the current code

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add the != 0 and extend the comment.

#else // WLED_ENABLE_WPA_ENTERPRISE
WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); // no harm if called multiple times
uint8_t *bssid = nullptr;
for (int i = 0; i < sizeof(multiWiFi[selectedWiFi].bssid); i++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see previous comment

softhack007 added a commit to MoonModules/WLED-MM that referenced this pull request Feb 6, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@wled00/wled.cpp`:
- Around line 734-742: The bssid assignment inside the for-loop is misindented;
in the block that checks multiWiFi[selectedWiFi].bssid you should indent the
statement that sets bssid = multiWiFi[selectedWiFi].bssid by two spaces so it is
clearly inside the if block (matching the indentation of the subsequent break;)
— update the indentation in the block that touches variables bssid and
multiWiFi[selectedWiFi].bssid and ensure the file uses the project’s 2-space C++
indentation style for that if/for block and the WiFi.begin(...) call that
follows.
🧹 Nitpick comments (1)
wled00/wled.cpp (1)

734-742: Consider extracting the BSSID null-check into a small helper.

The same "check if BSSID is non-zero, return pointer or nullptr" logic is duplicated in both the enterprise-PSK path (Lines 734-741) and the non-enterprise path (Lines 761-768). A tiny inline helper would reduce duplication:

// e.g. at file scope or as a static helper
static uint8_t* getConfiguredBSSID(uint8_t* bssid, size_t len) {
  for (size_t i = 0; i < len; i++) {
    if (bssid[i] != 0) return bssid;
  }
  return nullptr;
}

Also applies to: 761-769

@DedeHai
Copy link
Collaborator Author

DedeHai commented Feb 6, 2026

@softhack007 btw this change of scanning all WiFi "breaks" the bootup glitch fix - well not really but it needs to be extended. I have a solution: just always update NVM on bootup - it is quite safe and will not cause flash wear in any realistic use case. Will update that PR once this is merged.

@DedeHai
Copy link
Collaborator Author

DedeHai commented Feb 6, 2026

note to @netmindz this fix needs 0.15 backport

@netmindz netmindz added this to the 0.15.4 milestone Feb 6, 2026
@netmindz netmindz added bug connectivity Issue regarding protocols, WiFi connection or availability of interfaces labels Feb 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug connectivity Issue regarding protocols, WiFi connection or availability of interfaces

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WLED 0.16.0 alpha on ESP32 can only connect to WiFi access points on channel 1

3 participants