ESP32 Switch STA with AP

Hi everybody. It's me again, a fool. I have compiled a code below that talks about the conversion model between 2 STA and AP modes. By default I leave the STA, after the STA is lost, the AP can run. And after the STA is available, reconnect the STA and turn off the AP. I wrote it but it still doesn't run properly. It hasn't switched to the correct mode yet. After the STA becomes available, it switches to the STA but loses connection continuously. Unable to maintain connection with STA mode. The time to switch and connect between the two modes is very long. I would like everyone's input and comments. Thank you very much.

#include <WiFi.h>
#include <WiFiClient.h>

const char* ssid1     = "Mxxx";
const char* password1 = "xxxx";

const char* ssid = "Nxxx";
const char* password = "xxxxx";

short time_out = 0;
bool currentMode = false; // true == AccessPoint ... false == StationMode
bool availableSTA = false; 

void accessPoint() // AP mode
{
  Serial.print("Configuring access point...");
  WiFi.softAP(ssid, password);
  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
  currentMode = true;
}

void stationMode() // STA mode
{
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid1);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid1, password1);
  currentMode = false;
  // if cannot connect to home Wifi then switch to AP mode
  Switch_STA_to_AP();
}

void connectWF() // connect to home Wifi first, if fail then switch to AP mode
{
  stationMode();

  if (currentMode == false)
  {
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
  }
}

void Switch_STA_to_AP() // check if cannot connect to home Wifi then switch to AP mode
{
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    time_out++;
    Serial.print(".");
    if (time_out == 15)
    {
      accessPoint();
      availableSTA = false;
      time_out = 0;
      break;
    }
  }
}

void scan_Networks() // scan if home Wifi available
{
  int count = 0;
  int n = WiFi.scanNetworks();
  if (n == 0) {
    Serial.println("no networks found");
  } 
  else 
  {
    for (int i = 0; i < n; ++i) {
      if (WiFi.SSID(i) == ssid1)
      {
        availableSTA = true;
        count++;
      }
      delay(10);
    }
  }
  if(count == 0)
    availableSTA = false;
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.println();
  connectWF();
}

void loop() {
  // put your main code here, to run repeatedly:
  scan_Networks();
  if (availableSTA == false && currentMode == false) // if HOME WIFI NOT AVAILABLE and CURRENT MODE == STA
    accessPoint();
  if (availableSTA == true && currentMode == true) // if HOME WIFI AVAILABLE and CURRENT MODE == AP
    stationMode();
  if(currentMode == true)
  {
    Serial.println("AccessPoint");
    Serial.println(WiFi.softAPgetStationNum());
  }
  else
    Serial.println("STA");
  delay(300);
}

I'm confused. You start off in STA mode by calling "connectWF()" in your setup. In that function you then call stationMode()l, However, in stationMode, you begin STA mode, but then immediately call "Switch_STA_toAP()". Your comment says "if can't connect to home wifi then switch to AP mode" but you aren't actually waiting to see if you are connect to home wifi before beginning AP mode. Your start it immediately.

You also have to realize, when you call "Wifi.begin", it will take some time before the board actually connects to your WiFi, especially if you are using a DHCP assigned IP address. It will take a few seconds before the router will reply with your IP address. What you could do is add an event timer to wait while it is connecting with a timeout to start AP mode. Something like this:

 Serial.print("Connecting to ");
  Serial.print(ssid1);
  unsigned long start = millis();
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid1, password1);
  while(WiFi.status() != WL_CONNECTED && millis() - start < 10000){
     Serial.print)".");
}
  if(WiFi.status != WL_CONNECTED){
  currentMode = false;
  // if cannot connect to home Wifi then switch to AP mode
  Switch_STA_to_AP();
  } else{
    return;
  }
}

Also, you really want to scan for available wifi networks every 300 ms? The board isn't going to have time to complete an entire scan in that amount of time let alone actually do anything with the results. That's less time than you can perceive with your naked eye.

Think of it this way. When you turn Wifi on on your laptop or cell phone, how long does it take to connect? A good few seconds right? Do you think the ESP32 is going to be more powerful than your phone or PC? Heck no.

Also, you don't have to continue to check if you are connected to wifi. Plus, you are calling "scan_Networks" immediately in your loop, even if you just finished successfully connecting to your home wifi. This will immediately terminate your existing WiFi connection. The board cannot simultaneously scan for available networks and maintain a connection to the network your are connected to.

You might also want to look at ESP32 event driven wifi management. Core 0 on the esp32 is what will handle the wifi connection. If for some reason the connection is dropped, it can post that status back to your main program to allow a callback function to run. This can allow you to begin AP mode when that connection is dropped and is unable to be reconnected. And you can do that without periodically checking on the status. Random Nerd Tutorials has a good write-up on it.

1 Like

oh, I'm really touched to receive your specific comment like this. I will take it as a memorable lesson for mistakes. i am really a newbie when it comes to arduino in logic problem. i see what you mean but i really don't know how to modify my code. I know this forum is for sharing learning, not getting help and ready to eat. but I'd be grateful if you could take a moment to edit my code? so that it can run perfectly. I know it's okay to bother you like that, but I'm really bad at logic. I sincerely thank you.

1 Like

I am trying to build a code of esp32 that connects to an existing network (STA_Mode), if after a certain time the ESP fails to connect to that current network, it will come back to create an access point. access(AP_Mode). When the current network returns, the ESP will reconnect to that network (STA_Mode) and stop the access point (AP_Mode). My problem now is that I don't know how to build it so that it works stably and flexibly between the 2 modes.

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();

#if defined(ESP32)
  WiFi.setHostname(AP_hostname); // xxy
#else
  WiFi.hostname(AP_hostname);
#endif

  // try to connect to existing network
  WiFi.begin(home_ssid, home_password);
  Serial.print("\n\nTry to connect to existing network");
  Serial.print(" named #");
  Serial.print(home_ssid);
  Serial.println("#");

  {
    uint8_t timeout = 10;

    // Wait for connection, 5s timeout
    do {
      BlinkHeartBeatLED(OnBoard_LED,100);
      delay(500);
      Serial.print(".");
      timeout--;
    } while (timeout && WiFi.status() != WL_CONNECTED);

    // not connected -> create hotspot
    if (WiFi.status() != WL_CONNECTED) {
      Serial.print("\n\n no connection to SSID #");
      Serial.print(home_ssid);
      Serial.println("#\n Creating hotspot");

      WiFi.mode(WIFI_AP);
      delay(100);
      WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));

#if defined(ESP32)
      uint32_t chipid = 0;
      for (int i = 0; i < 17; i = i + 8) {
        chipid |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
      }
#else
      uint32_t chipid = ESP.getChipId();
#endif
      char ap_ssid[25];
      snprintf(ap_ssid, 26, "ESPUI-%08X", chipid);
      WiFi.softAP(ap_ssid);
      Serial.print("SSID #");
      Serial.print(ap_ssid);
      Serial.println("#");

      timeout = 5;

      do {
        delay(500);
        Serial.print(".");
        timeout--;
      } while (timeout);
    }
  }

How can I combine this with this code that tries to connect to a first SSID and if this fails will create an access point (AP Mode). (Here I am using "trying to connect to 2nd SSID network"). Can it be modified to create AP Mode access point?

const char *ssid2     = "your SSID 1";
const char *ssid1     = "your SSID 2"; //FRITZ!Box 7490 WLANBuero_EXT
const char *password = "password";


void ConnectToWiFi() {
  WiFi.mode(WIFI_STA);
  Serial.println("WiFi.mode(WIFI_STA)");

  int myCount = 0;

  Serial.print("trying to connect to #");
  Serial.print(ssid1);
  Serial.println("#");
  WiFi.begin(ssid1, password);

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED && myCount < 31) {
    BlinkHeartBeatLED(OnBoard_LED, 50);

    if ( TimePeriodIsOver(MyTestTimer, 1000) ) {
      Serial.print(".");
      if (myCount++ > 30) {
        Serial.println();
        //myCount = 0;
        Serial.print("not yet connected trying other SSID");
      }
    }
  }

  if (WiFi.status() == WL_CONNECTED ) {
    Serial.println("");
    Serial.print("Connected to #");
    Serial.print(ssid1);
    Serial.print("# IP address: ");
    Serial.println(WiFi.localIP());
  }
  
  if (WiFi.status() != WL_CONNECTED ) {
    Serial.print("trying to connect to #");
    Serial.print(ssid2);
    Serial.println("#");
    WiFi.begin(ssid2, password);
    myCount = 0;
  
    // Wait for connection
    while (WiFi.status() != WL_CONNECTED ) {
      BlinkHeartBeatLED(OnBoard_LED, 250);
  
      if ( TimePeriodIsOver(MyTestTimer, 1000) ) {
        Serial.print(".");
        if (myCount++ > 30) {
          Serial.println();
          myCount = 0;
          Serial.print("not yet connected setting AP");
          // code to setup as accesspoint with its own wifi
        }
      }
    }
  }

  if (WiFi.status() == WL_CONNECTED ) {
    Serial.println("");
    Serial.print("Connected to #");
    Serial.print(ssid1);
    Serial.print("# IP address: ");
    Serial.println(WiFi.localIP());
  }

Thanks forum so much.

Please help me.

I have merged your topics due to them having too much overlap on the same subject matter @dmitaw.

In the future, please only create one topic for each distinct subject matter and be careful not to cause them to converge into parallel discussions.

The reason is that generating multiple threads on the same subject matter can waste the time of the people trying to help. Someone might spend a lot of time investigating and writing a detailed answer on one topic, without knowing that someone else already did the same in the other topic.

Thanks in advance for your cooperation.

I have posted a new topic, I don't know how to delete/disable my old topics, so people don't get confused. Can you help me?

Hi everybody. I am testing a code. Runs in parallel between both STA Mode and AP Mode. Due to a special request from the contractor, I am not allowed to use available libraries such as wifi multi, wifi manager... I know using those libraries will help and save me a lot of time. . I have asked 2 3 forum posts but have not found a solution.
My program will be, using 2 esp32, one server, one client. The server will run in 2 wifi modes: STA Mode and AP Mode. I always prioritize using STA Mode, AP Mode is only used when the network is out. The problem here is that the ESP server will have to flexibly switch between those two modes. When there is internet, STA Mode is available, esp will catch the internet to run STA Mode, if during runtime it loses connection to the internet, the ESP server will automatically generate an access point for itself AP Mode. And after the internet is back, the esp server will have to reconnect itself to the Internet to run STA Mode. In a nutshell, ESP will have to scan the network continuously, so that it can find the Internet to run STA Mode (because I prefer to use STA Mode)
Here is the code I did:

/*
  Example from WiFi > WiFiScan
  Complete details at https://RandomNerdTutorials.com/esp32-useful-wi-fi-functions-arduino/
*/

#include <WiFi.h>

// Replace with your network credentials
const char* ssid = "MINHTAM.HUS";
const char* password = "daominhtam";

const char* ssid_ap = "esp32_access_point";
const char* password_ap = "a$1234567890."; // use something more secure :)

void setup() {
  Serial.begin(115200);
  Serial.println("Setup done");
  bool our_network = scanWIFI();
  Serial.println(our_network);
  if (our_network == true) {
    // We found our network, go to sta mode
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(100);
    WiFi.begin(ssid, password);
    Serial.print("Connecting to WiFi ..");
    while (WiFi.status() != WL_CONNECTED) {
      Serial.print('.');
      delay(1000);
    }
    Serial.println(WiFi.localIP());
  } else {
    // We did not found our network, going into AP mode
    Serial.println("we did not find our network. :(");
    WiFi.mode(WIFI_AP);
    WiFi.softAP(ssid_ap, password_ap);
    IPAddress IP = WiFi.softAPIP();
    Serial.print("AP IP address: ");
    Serial.println(IP);

  }
}

void loop() {
  Serial.println("sleeping for 5s");

  // WiFi.scanNetworks will return the number of networks found


  // Wait a bit before scanning again
  delay(5000);
}

bool scanWIFI() {
  // Set WiFi to station mode and disconnect from an AP if it was previously connected
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);
  Serial.println("Wifi mode setup done.");
  int n = WiFi.scanNetworks();
  Serial.println("scan done");
  if (n == 0) {
    Serial.println("no networks found");
  } else {
    Serial.print(n);
    Serial.println(" networks found");
    for (int i = 0; i < n; ++i) {
      // Print SSID and RSSI for each network found
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      if (WiFi.SSID(i) == "MINHTAM.HUS") { //the one that you'll be searching for
        Serial.println(" : Found our desired network");
        return true;
      } else {
        return false;
      }
      Serial.print(" (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");
      Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
      delay(10);
    }
  }
  Serial.println("");
}

It is set up right in the setup, if it finds the SSID I declared above, it will catch the internet and run STA, if after a period of time cannot find the above SSID, it will run AP Mode.
The problem here is that I don't know how to make my ESP server do what in the loop so that it can scan the network continuously, know when it can't connect to the internet so that STA Mode stops running and switches to AP. Mode. And after the network is back, my ESP will have to rescan the internet or the SSID I declared to reconnect to it, running STA Mode. I am a newbie in Arduino programming, or ESP so things are quite difficult for me. I don't have much time because I'm about to submit my work report. It's almost been my big workout this month. Thank you all for watching and sharing. have a nice day.

Please don't do that. Just reply to your existing topic to provide more information or updates.

I have merged your cross-post to this topic.

maybe something like this..

/*
  Example from WiFi > WiFiScan
  Complete details at https://RandomNerdTutorials.com/esp32-useful-wi-fi-functions-arduino/
*/

#include <WiFi.h>

// Replace with your network credentials
const char* ssid = "MINHTAM.HUS";
const char* password = "daominhtam";

const char* ssid_ap = "esp32_access_point";
const char* password_ap = "a$1234567890."; // use something more secure :)
int WiFi_MODE = 0;

void setup() {
  Serial.begin(115200);
  Serial.println("Setup done");
  bool our_network = scanWIFI();
  Serial.println(our_network);
  if (our_network == true) {
    // We found our network, go to sta mode
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(100);
    WiFi.begin(ssid, password);
    Serial.print("Connecting to WiFi ..");
    while (WiFi.status() != WL_CONNECTED) {
      Serial.print('.');
      delay(1000);
    }
    Serial.println(WiFi.localIP());
    WiFi_MODE = 0;
  } else {
    // We did not found our network, going into AP mode
    Serial.println("we did not find our network. :(");
    WiFi.mode(WIFI_AP);
    WiFi.softAP(ssid_ap, password_ap);
    IPAddress IP = WiFi.softAPIP();
    Serial.print("AP IP address: ");
    Serial.println(IP);
    WiFi_MODE = 1;

  }
    xTaskCreateUniversal(loopTask_WTD, "loopTask_WTD", 8192, NULL, 0, NULL, 0);
}

void loop() {
  Serial.println("sleeping for 5s");

  // WiFi.scanNetworks will return the number of networks found


  // Wait a bit before scanning again
  delay(5000);
}

bool scanWIFI() {
  // Set WiFi to station mode and disconnect from an AP if it was previously connected
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);
  Serial.println("Wifi mode setup done.");
  int n = WiFi.scanNetworks();
  Serial.println("scan done");
  if (n == 0) {
    Serial.println("no networks found");
  } else {
    Serial.print(n);
    Serial.println(" networks found");
    for (int i = 0; i < n; ++i) {
      // Print SSID and RSSI for each network found
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      if (WiFi.SSID(i) == "MINHTAM.HUS") { //the one that you'll be searching for
        Serial.println(" : Found our desired network");
        return true;
      } else {
        return false;
      }
      Serial.print(" (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");
      Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
      delay(10);
    }
  }
  Serial.println("");
}


int wtdFlag = 0;
void loopTask_WTD(void *pvParameters) {
  while (1)
  {
    if (WiFi_MODE == 0)
    {
      if ((WiFi.isConnected() == 0) && wtdFlag == 0)
      {
        delay(100);
      }
      else if ((WiFi.isConnected() != 0) && wtdFlag == 0)
      {
        wtdFlag = 1;
        delay(100);
      }
      else if ((WiFi.isConnected() == 0) && wtdFlag == 1)
      {
        wtdFlag = 0;
        ESP.restart();
      }
    }
    else
    {
      if ((WiFi.softAPgetStationNum() == 0) && wtdFlag == 0)
      {
        delay(100);
      }
      else if ((WiFi.softAPgetStationNum() != 0) && wtdFlag == 0)
      {
        wtdFlag = 1;
        delay(100);
      }
      else if ((WiFi.softAPgetStationNum() == 0) && wtdFlag == 1)
      {
        wtdFlag = 0;
        ESP.restart();
      }
    }
  }
}

this will restart the esp when it gets disconnected..
then it should switch to AP mode..
still to do, see when internet is back and reboot again..
good luck.. ~q

But what else will the board be doing? That will change how you are going to implement what you want. If you are periodically going to be sending data to a server, then obviously that can't happen if you are in AP mode. If you are going to be running a webserver for someone to connect to, then that will have to be stopped and then restarted once you are in AP mode. Just because you're in AP mode doesn't mean that there will be a webserver running for you to connect to.

Also, your board cannot run in AP mode and also check to see if your home network is back in order to join it at the same time. Once you scan for networks and begin to connect to your home network, you are going to lose your connection to AP mode. If you are in the middle of doing something, that could be problematic. So, you have to decide how frequently you want to check to see whether or not your home network is available again.

However, I do have one more question. Is the board going to be moving around? Why would your home network be there and then suddenly disappear and then re-appear? If your board is going to be mobile (and running on a battery) that is something else to take into consideration as searching for WiFi is VERY power hungry.

I'm simply sending some parameters like the number of people present in the classroom to an esp32 client. In the esp32 server I am setting it up to send to the webserver in both STA and AP modes. So even though the STA mode is disconnected, the esp32 client will still receive data from the webserver based on it being able to connect to the esp32 server using AP mode. But I am setting it to STA mode so that users can access the IP address generated from STA mode anywhere anytime without having to connect to the AP mode that esp generates. Because to access the IP address of AP Mode, users must connect to the wifi network of AP mode. It's quite inconvenient if I'm not near esp32 that broadcasts AP Mode. Maybe the time for scanning the internet to be available or not does not need to be too fast, maybe 5 10 seconds or something. Or maybe longer but not too long because my parameter of number of people changes constantly and needs to be saved continuously to ensure accuracy. In my locality, loss of connection to the internet is a regular occurrence. It can take any time so what I want my esp will need to detect when the connection is lost and when it can be reconnected to resume STA mode.

In my loop will be a problem that needs to store information and send it to the webserver. if I reset esp will cause all data to be lost the last time it was run. and it will have to run again from the beginning. That is not acceptable.

I'm sorry, I still don't understand. Why are there two boards? You keep talking about how you want the boards to communicate but you don't talk about WHY they are communicating with each other.

You do understand that once connected to wifi, a board does not have to be in AP or STA to receive or send data, correct? You can receive or send data if you are in STA mode or in AP mode. The only requirement would be that if you want to be able to connect to the board it has to be in AP mode. But it seems that a lot of your problems would be solved if both boards just connected to WiFi already present in the building.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.