ESP32/ESP8266 API response in WIFI_AP_STA mode

I am currently using ESP32 which First Act as an AP and We can connect to it and connect to Available WIFI . I am using server end point as API for this. I am using two API one in get and other in post . First get api scan wifi and send details in json and other one receives data of the wifi network which it is needed to connect and it connect to it .and the response of this api is the ip and ssid name . but for some reason the response is not always sending back to the client who is connected at the time of AP .the response not getting is started after attempting to WIFI. Is there a way that i can make sure API response is received Everytime the API calls.

 _server.on("/WiFi", HTTP_POST, [](AsyncWebServerRequest* request) {
    //  To clear any WIFi Stack
    // WiFi.disconnect(true);
    // delay(50);

    if (request->hasArg("ssid") && request->hasArg("password")) {
      String ssid = request->arg("ssid");
      String password = request->arg("password");

      // Initialize optional static IP configuration variables
      String ip = "", gateway = "", subnet = "", primaryDNS = "", secondaryDNS = "";

      // Check for optional static IP and DNS parameters
      if (request->hasArg("ip") && request->hasArg("gateway") && request->hasArg("subnet")) {
        ip = request->arg("ip");
        gateway = request->arg("gateway");
        subnet = request->arg("subnet");
        if (request->hasArg("dns1")) primaryDNS = request->arg("dns1");
        if (request->hasArg("dns2")) secondaryDNS = request->arg("dns2");
      } else {
        ip = "";
        gateway = "";
        subnet = "";
        primaryDNS = "";
        secondaryDNS = "";
      }

      // Create a WiFiConfig structure with the received data
      currentConfig = { ssid, password, ip, gateway, subnet, primaryDNS, secondaryDNS };

      // Save WiFi configuration to LittleFS
      // saveWiFiConfig(currentConfig);


      if (currentConfig.ssid != "" && currentConfig.password != "") {



        // Optionally set static IP, gateway, and DNS if provided
        if (currentConfig.ip != "" && currentConfig.gateway != "" && currentConfig.subnet != "") {
          IPAddress ip, gateway, subnet, dns1, dns2;
          ip.fromString(currentConfig.ip);
          gateway.fromString(currentConfig.gateway);
          subnet.fromString(currentConfig.subnet);
          dns1.fromString(currentConfig.dns1);
          dns2.fromString(currentConfig.dns2);
          // Serial.println("NOt be this line");

          WiFi.config(ip, gateway, subnet, dns1, dns2);
        } else {
          // Serial.println("fien by this");
          // WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
        }

        WiFi.begin(currentConfig.ssid.c_str(), currentConfig.password.c_str());

        // Wait for connection
        int retries = 0;
        while (WiFi.status() != WL_CONNECTED && retries < 50) {
          delay(200);
          esp_task_wdt_reset();
          Serial.print(".");
          retries++;
        }


        if (WiFi.status() == WL_CONNECTED) {
          Serial.println("Connected to WiFi");
          Serial.println("IP Address: " + WiFi.localIP().toString());
          saveWiFiConfig(currentConfig);
          request->send(200, "text/plain", "Connected to : " + WiFi.SSID() + ", IP Address: " + WiFi.localIP().toString());
        } else {
          currentConfig = { "", "", "", "", "", "", "" };

          if (WiFi.status() != WL_CONNECTED && WiFi.status() != WL_NO_SSID_AVAIL) {
            Serial.println("Password is not correct in Server");
            request->send(200, "text/plain", "Password is not correct");

          } else if (WiFi.status() != WL_CONNECTED && WiFi.status() == WL_NO_SSID_AVAIL) {
            Serial.println("Wifi network is not avaliable");
            request->send(200, "text/plain", WiFi.SSID() + "  is not avaliable");
          }
        }
      }
      // Send response to client
      // // request->send(200, "text/plain", "WiFi setup data received and saved to Device");
      // // delay(100);
      // Serial.println("SSID: " + ssid);
      // Serial.println("Password: " + password);
      // if (ip != "") Serial.println("Static IP: " + ip);
      // if (gateway != "") Serial.println("Gateway: " + gateway);
      // if (subnet != "") Serial.println("Subnet: " + subnet);
      // if (primaryDNS != "") Serial.println("Primary DNS: " + primaryDNS);
      // if (secondaryDNS != "") Serial.println("Secondary DNS: " + secondaryDNS);

      // delay(100);
      // Serial.println("Device Restarting..");
      // ESP.restart();
    } else {
      request->send(400, "text/plain", "Missing parameters (ssid, password)");
    }
  });

this is the server code

The WiFi.begin() disconnects the device connected to the AP, you should use

WiFi.reconnect();

after connection has been established or not, to reconnect the AP client.

i am using WiFI.begin() at the intialisation then i never uses it may be in reconnect part but without begin we cannot initialize the connection .how to use reconnect without begin

You create the AP then from the credentials you use WiFi.begin(), after the connection has either been established or not, you need to use WiFi.reconnect(). to reconnect the device that is connected to the AP

Based on the code provided, I can see the issue with the WiFi connection response not always reaching the client. The problem likely occurs because the ESP32 is switching from AP mode to STA mode during the connection attempt, which can interrupt the response.

Here's how we can modify the code to ensure the response is always sent:

  1. First, we should send the response immediately after processing the request, before attempting to connect to WiFi.
  2. Then store the connection status and handle the WiFi connection in a separate task or loop.
    Here's the modified code:
_server.on("/WiFi", HTTP_POST, [](AsyncWebServerRequest* request) {
    if (request->hasArg("ssid") && request->hasArg("password")) {
        String ssid = request->arg("ssid");
        String password = request->arg("password");

        // Initialize optional static IP configuration variables
        String ip = "", gateway = "", subnet = "", primaryDNS = "", secondaryDNS = "";

        // Check for optional static IP and DNS parameters
        if (request->hasArg("ip") && request->hasArg("gateway") && request->hasArg("subnet")) {
            ip = request->arg("ip");
            gateway = request->arg("gateway");
            subnet = request->arg("subnet");
            if (request->hasArg("dns1")) primaryDNS = request->arg("dns1");
            if (request->hasArg("dns2")) secondaryDNS = request->arg("dns2");
        }

        // Create and save WiFi config
        currentConfig = { ssid, password, ip, gateway, subnet, primaryDNS, secondaryDNS };
        
        // Send immediate response to client
        request->send(200, "text/plain", "Attempting to connect to " + ssid);
        
        // Start WiFi connection in a separate task
        if (currentConfig.ssid != "" && currentConfig.password != "") {
            if (currentConfig.ip != "" && currentConfig.gateway != "" && currentConfig.subnet != "") {
                IPAddress ip, gateway, subnet, dns1, dns2;
                ip.fromString(currentConfig.ip);
                gateway.fromString(currentConfig.gateway);
                subnet.fromString(currentConfig.subnet);
                dns1.fromString(currentConfig.dns1);
                dns2.fromString(currentConfig.dns2);
                WiFi.config(ip, gateway, subnet, dns1, dns2);
            }

            WiFi.begin(currentConfig.ssid.c_str(), currentConfig.password.c_str());
            
            // Connection attempt continues in background
        }
    } else {
        request->send(400, "text/plain", "Missing parameters (ssid, password)");
    }
});

For better reliability, you should also:

  1. Implement a separate function to handle the WiFi connection status
  2. Consider using WebSockets or MQTT to send connection status updates after the initial response
  3. Add a separate endpoint to check connection status

I am using Websockets to send updates after the connection . I wish i could send the IP details back to Client when it connect to WiFI

Ah hold on my mistake. The way you do this, your request is going to timeout. Expect the connection to the network to take more than 5 seconds.

In the callback for making the connection request, send back a page telling the client that connection is attempted, and include a HTML refresh for another page which checks if the connection was successful.
send back something like this


void ConnectingPage(bool eth) {
  String s;
  s += FPSTR(pageheader);
  s += FPSTR(htmlhead);
  s += FPSTR(bodystyle);
  s += F("<h1>Connecting to Network : ");
  s += STAname;
  s += F("</h1>");

  s += F("<META http-equiv='refresh' content='10;URL=/?page=wifi'> Hold on a moment\n");

  s += FPSTR(htmlclose);
  serverSend(s, eth); //Send web page
  yield();
  delay(200);
}

(sorry i am using a slightly different system than you, but i think you'll get the gist)

And there after, try to make the connection to the network and the connection should have established after the 10 seconds when the refresh happens.
Then on the page you have sent you can provide all info you may want. Network IP address, mDNS if you have started it etc.

This example is part of a much bigger sketch, i don't have an isolated example for you unfortunately.

i updated the code like this

and for getting the ip address .After wifi connection it sends details to websocket server

OK so it works now ?

Yes it does

1 Like