Skip to content

ESP32 AP+STA and scanNetworks fails if STA not connected #8916

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
astrogene1000 opened this issue Nov 24, 2023 · 11 comments
Closed
1 task done

ESP32 AP+STA and scanNetworks fails if STA not connected #8916

astrogene1000 opened this issue Nov 24, 2023 · 11 comments
Assignees
Labels
Area: BT&Wifi BT & Wifi related issues Status: Solved Type: Question Only question

Comments

@astrogene1000
Copy link

Board

PICO-D4 and Devkit 3

Device Description

None

Hardware Configuration

None

Version

v2.0.14

IDE Name

Arduino IDE

Operating System

W11

Flash frequency

80

PSRAM enabled

yes

Upload speed

115200

Description

I have a build that always presents an Access point.
There is a need for also for connecting to a STA whose info the user enters via a web interface.
The issue is if the STA is not connected (which is possible as device may move to another physical area and need to connect to a different network) then while in main application if a scanNetworks is done it -always- returns a -2 (WIFI_SCAN_FAILED) basically immediately.

If a scanNetworks is done and the device is connected to a STA then works as expected.
If a scanNetworks is done prior to attempting to connect to the (non-existent) AP then it works as expected.

This is what I see as far as response time to scan
start_time = esp_timer_get_time();
numnets = WiFi.scanNetworks();
total_time = esp_timer_get_time() - start_time;
Serial.println(total_time);

total_time for scan prints out as 307/255/287 for three subsequent tries when not able to connected to
configured access point.

Here is what I see if successfully connected to an AP

total_time prints out as 7238971/8131168/8779417

For seeing 61, 66 and 59 unique external access points.

I believe the err is kick from this call in WiFiScan.cpp
if(esp_wifi_scan_start(&config, false) == ESP_OK) {

Based on this thread
espressif/esp-idf#11437

ESP_OK: succeed
ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
ESP_ERR_WIFI_NOT_STARTED: WiFi was not started by esp_wifi_start
ESP_ERR_WIFI_TIMEOUT: blocking scan is timeout
ESP_ERR_WIFI_STATE: wifi still connecting when invoke esp_wifi_scan_start
others: refer to error code in esp_err.h

esp_err_t esp_wifi_scan_start(const wifi_scan_config_t *config, bool block);

Which is getting back a "ESP_ERR_WIFI_STATE: wifi still connecting" and scanNetworks returns it as a generic failure.

Question, how to get around this issue?
Can I shutdown the attempts to connect to the non-existent AP

I cannot stop then restart the whole wifi subsystem as that would drop the connection to the internal AP of the esp32.

Thoughts?

Thanks!

Gene

Sketch

int64_t start_time, total_time;
WiFi.begin("IDONOTEXIST", "123456789");
delay(1000);
int numnets = 0;

  start_time = esp_timer_get_time();
  numnets = WiFi.scanNetworks();
  total_time = esp_timer_get_time() - start_time;
  Serial.print("Total time: "); Serial.println(total_time);
  Serial.print("Numnets = "); Serial.println(numnets);

Debug Message

WiFi.scanNetworks() returns a -2 (WIFI_SCAN_FAILED)

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@astrogene1000 astrogene1000 added the Status: Awaiting triage Issue is waiting for triage label Nov 24, 2023
@SuGlider
Copy link
Collaborator

@astrogene1000 - I have tested this sketch using Arduino 2.0.14. It works fine.
I can see all necessary messages in the Verbose Mode.

#include "WiFi.h"

const char* ssid     = "YOUR_SSID"; // Change this to your WiFi SSID
const char* password = "YOUR_PASSWORD"; // Change this to your WiFi password

const char* host = "google.com"; // This should not be changed
const int httpPort = 80; // This should not be changed


const char *soft_ap_ssid = "MyESP32AP";
const char *soft_ap_password = "12345678";

void readResponse(WiFiClient *client) {
  unsigned long timeout = millis();
  while (client->available() == 0) {
    if (millis() - timeout > 5000) {
      Serial.println(">>> Client Timeout !");
      client->stop();
      return;
    }
  }

  // Read all the lines of the reply from server and print them to Serial
  while (client->available()) {
    String line = client->readStringUntil('\r');
    Serial.print(line);
  }

  Serial.printf("\nClosing connection\n\n");
}

void connectWiFi()
{
  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println("******************************************************");
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.println();
  Serial.println("******************************************************");
}


void setup()
{
  Serial.begin(115200);
  delay(100);

  // Start mode AP+STA with default IP

  // Start mode AP 
  Serial.println("\n++++++++++++++\nStarting AP Mode\n++++++++++++++\n");
  WiFi.mode(WIFI_MODE_APSTA);
  WiFi.softAP(soft_ap_ssid, soft_ap_password);
  Serial.print("ESP32 IP as soft AP: ");
  Serial.println(WiFi.softAPIP());
  Serial.println();

  // Start Connection using STA mode
  Serial.println("\n++++++++++++++\nStarting STA Mode\n++++++++++++++\n");
  connectWiFi();

  Serial.println("Setup [issue 8916] done");
}

void loop()
{
  Serial.println("Scan start");

  // WiFi.scanNetworks will return the number of networks found.
  int n = WiFi.scanNetworks();
  Serial.println("Scan done");
  if (n == 0) {
    Serial.println("no networks found");
  } else {
    Serial.print(n);
    Serial.println(" networks found");
    Serial.println("Nr | SSID                             | RSSI | CH | Encryption");
    for (int i = 0; i < n; ++i) {
      // Print SSID and RSSI for each network found
      Serial.printf("%2d", i + 1);
      Serial.print(" | ");
      Serial.printf("%-32.32s", WiFi.SSID(i).c_str());
      Serial.print(" | ");
      Serial.printf("%4ld", WiFi.RSSI(i));
      Serial.print(" | ");
      Serial.printf("%2ld", WiFi.channel(i));
      Serial.print(" | ");
      switch (WiFi.encryptionType(i))
      {
        case WIFI_AUTH_OPEN:
          Serial.print("open");
          break;
        case WIFI_AUTH_WEP:
          Serial.print("WEP");
          break;
        case WIFI_AUTH_WPA_PSK:
          Serial.print("WPA");
          break;
        case WIFI_AUTH_WPA2_PSK:
          Serial.print("WPA2");
          break;
        case WIFI_AUTH_WPA_WPA2_PSK:
          Serial.print("WPA+WPA2");
          break;
        case WIFI_AUTH_WPA2_ENTERPRISE:
          Serial.print("WPA2-EAP");
          break;
        case WIFI_AUTH_WPA3_PSK:
          Serial.print("WPA3");
          break;
        case WIFI_AUTH_WPA2_WPA3_PSK:
          Serial.print("WPA2+WPA3");
          break;
        case WIFI_AUTH_WAPI_PSK:
          Serial.print("WAPI");
          break;
        default:
          Serial.print("unknown");
      }
      Serial.println();
      delay(10);
    }
  }
  Serial.println("");

  // Delete the scan result to free memory for code below.
  WiFi.scanDelete();

  // Connecting to HOST ...
  Serial.println();
  Serial.println("******************************************************");
  if (WiFi.status() == WL_CONNECTED) {
    Serial.printf("WiFi still connected to [%s]. Reading Host [%s]\n\n=============\n", ssid, host);
    WiFiClient client;
    String footer = String(" HTTP/1.1\r\n Connection: close\r\n\r\n");

    // WRITE --------------------------------------------------------------------------------------------
    if (!client.connect(host, httpPort)) {
      return;
    }
    // READ ---------------------------------------------------------------------------------------------
    client.print("GET /" + footer);
    readResponse(&client);
    Serial.println("=============");
  } else {
    Serial.printf("WiFi is **disconnected** from [%s]!\n", ssid);
  }
  Serial.println();
  Serial.println("******************************************************");
  // Wait a bit before scanning // reading Host again.
  delay(5000);
}

@SuGlider SuGlider self-assigned this Nov 26, 2023
@SuGlider
Copy link
Collaborator

If I comment out the setup() line connectWiFi();, it also works correctly.
Therefore it can scan WiFi networks when connected ot not to the AP.
I can also connetc to the ESP32 AP Mode as well in both cases.

@mrengineer7777
Copy link
Collaborator

@astrogene1000 I'm not surprised that you can't scan while the ESP32 is trying to connect to STA. The connection attempt ties up the radio, so any scan will fail.

If a scanNetworks is done and the device is connected to a STA then works as expected.
If a scanNetworks is done prior to attempting to connect to the (non-existent) AP then it works as expected.

That is also expected.

As far as I know, the only way to stop the STA connection attempt is to turn off the WiFi radio. As you have noted, that will also stop the AP mode used for setup.

In 2.0.9 running an SSID scan while in AP mode also temporarily disrupts the AP connection. I believe this is a limitation of the hardware.

Here's the approach I use for my firmware:

  1. First thing in life scan WiFi networks and save results to memory.
  2. Bring up AP or STA connection. I had poor results when using AP+STA, so I avoid that mode.
  3. If STA connection fails then fallback to AP.
  4. I do have a command to trigger a new SSID scan, but I generally don't use it as I can't communicate with the ESP32 during the scan.

These limitations aren't unique to the ESP32. I had the same challenges when using a Zentri AMW106 radio.

@astrogene1000
Copy link
Author

Thanks for the responses!
@SuGlider Not sure this is apples to oranges comparison because how does your code ever exit the while loop if it cannot connect to the AP?
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

@mrengineer7777 I do have a fallback in my use case because the user can still connect to devices AP and user could configure a known local external AP and reset or could configure as no external AP and reset then execute scan after the reset's. I have had good luck running both AP+STA except for this scan issue and have multiple web interfaces into both device control and business logic, reason I need to keep the devices local AP functional at all times.

Thanks again,

Gene

@SuGlider
Copy link
Collaborator

Thanks for the responses! @SuGlider Not sure this is apples to oranges comparison because how does your code ever exit the while loop if it cannot connect to the AP? while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }

In my testing, or I can connect and that loop exits or it is never called by commenting it out.
//connectWiFi(); in setup()

In other words, when it connects to the AP in STA mode, I can scan the WiFi.
If that line is commented out, it will never try to connect (or it could just fail and exit the loop after a timeout) and then it would still be able to scan the network.

@SuGlider
Copy link
Collaborator

Let me also test it when failing after a timeout...

@SuGlider
Copy link
Collaborator

@astrogene1000 - Yes, I could reproduce the issue now. I changed the connectWiFi() code and now I get the error -2

void connectWiFi()
{
  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println("******************************************************");
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  int tries = 10;
  while (WiFi.status() != WL_CONNECTED && tries) {
    delay(500);
    Serial.print(".");
    tries--;
  }

  if (!tries) {
    Serial.printf("\n===>It couldn't connect to the AP using SSID %s\n", ssid);
  } else {
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    Serial.println();
    Serial.println("******************************************************");
  }
}
`

@SuGlider
Copy link
Collaborator

@astrogene1000 - I got it to work by adding a WiFi.disconnect(false); if it fails to connect in STA mode.

void connectWiFi()
{
  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println("******************************************************");
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  int tries = 10;
  while (WiFi.status() != WL_CONNECTED && tries) {
    delay(500);
    Serial.print(".");
    tries--;
  }

  if (!tries) {
    Serial.printf("\n===>It couldn't connect to the AP using SSID %s\n", ssid);
    WiFi.disconnect(false);   // <<<<<<<<<<<<<<================ This allow it to scan WiFi
  } else {
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    Serial.println();
    Serial.println("******************************************************");
  }
}

@SuGlider SuGlider added Area: BT&Wifi BT & Wifi related issues Type: Question Only question Status: Solved and removed Status: Awaiting triage Issue is waiting for triage labels Nov 28, 2023
@astrogene1000
Copy link
Author

Thanks @SuGlider for confirming the disconnect kicks it out and lets things scan!
I was thinking about trying the disconnect but got tied up,
Super find!
this issue seems to go back a ways in time!

Gene

@SuGlider
Copy link
Collaborator

Good to know that the issue is finally solved.
I'll close it. Fell free to open it again if necessary.

@dagnall53
Copy link

dagnall53 commented Mar 8, 2025

@astrogene1000 @SuGlider
Thanks for recording ths. I just had the same -2 result problem.
Slightly different scenario, but the WIFI.disconnect(false) cured it!>
My code (simplified) looks like this after the wifi begin:

if (WiFi.status() == WL_CONNECTED) {
Serial.print("** Connected.: ");
Serial.print(" *Running with: ssid<");
Serial.print(WiFi.SSID());
Serial.print("> Ip:");
Serial.println(WiFi.localIP());
} else {
WiFi.disconnect(false); // allows the later scan to work ? //#8916
Serial.print(" NO WIFI Connected");
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: BT&Wifi BT & Wifi related issues Status: Solved Type: Question Only question
Projects
None yet
Development

No branches or pull requests

4 participants