Receive a string from Client

Hello! Greetings! hope everyone is doing well.

I'm working on a project which uses ESP32. I have configured ESP32 as softAP and have a web server running on it. What I need to do now is after connecting to the ESP32AP via WLAN, opening a web browser and entering the IP, I land on web page. What I'm trying to do now is, if I type in something like this in web browser:

http://192.168.4.1/changeSSID

My new SSID is set to changeSSID, then I reboot the softAP with this new SSID. I have a code written but I can't get it to work

 #ifdef ESP32
  #include <WiFi.h>
#else
  #include <ESP8266WiFi.h>
#endif
 
 #define Device  2  
    
 // Create the objects for server and client  
 WiFiServer server(80);  
 WiFiClient client;  
   
 const char* ssid   = "ESP32-Data-On-Tag";// This is the SSID that ESP32 will broadcast  
//const char* password = "12345678";     // password should be atleast 8 characters to make it work (later a self building password will be added)
   
 // Create the global variable  
 String http;  
 String DeviceState = "off";  

byte mac[6];
String one, Two, Pass;
const char* password;
const char* NewSSID;

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

    Serial.println();
    Serial.print("Program Start...");

    Create_Password_SetupAP();
    Set_New_SSID();
    pinMode(Device, OUTPUT);  
   digitalWrite(Device, LOW);  

 /* 
  WiFi.softAP(ssid, password);  
   
  Serial.println( "" );  
  Serial.println( "WiFi AP is now running" );  
  Serial.println( "IP address: " );  
  Serial.println( WiFi.softAPIP() );  
   */
  // Start our ESP32 server  
  server.begin();  
 }  
   
 void loop()
 {  
    
  if ( client = server.available() ) {  // Checks if a new client tries to connect to our server  
   Serial.println("New Client.");  
   String clientData = "";  
   while ( client.connected() ) {    // Wait until the client finish sending HTTP request  
    if ( client.available() ) {     // If there is a data,  
     char c = client.read();      //  read one character  
     http += c;            //  then parse it  
     Serial.write(c);    
     if (c == '\n') {         // If the character is carriage return,   
                      //  it means end of http request from client  
      if (clientData.length() == 0) { //  Now that the clientData is cleared,  
       sendResponse();        //    perform the necessary action  
       updateDevice();  
       updateWebpage();  
       break;  
      } else {  
       clientData = "";       //  First, clear the clientData  
      }  
     } else if (c != '\r') {      // Or if the character is NOT new line  
      clientData += c;        //  store the character to the clientData variable  
     }  
    }  
   }   
   http = "";  
   client.stop();            // Disconnect the client.  
   Serial.println("Client disconnected.");  
   Serial.println("");  
  }  
 }  
   
 void sendResponse() {  
  // Send the HTTP response headers  
  client.println("HTTP/1.1 200 OK");  
  client.println("Content-type:text/html");  
  client.println("Connection: close");  
  client.println();   
 }  
   
 void updateWebpage() {  
  // In here we will display / update the webpage by sending the HTML   
  //  to the connected client  
  // In order for us to use the HTTP GET functionality,  
  //  the HTML hyperlinks or href is use in the buttons.   
  //  So that, when you press the buttons, it will send a request to the   
  //  web server with the href links by which our ESP32 web server will  
  //  be check using HTTP GET and execute the equivalent action  
    
  // Send the whole HTML  
  client.println("<!DOCTYPE html><html>");  
  client.println("<head>");  
  client.println("<title>ESP32 WiFi Station</title>");  
  client.println("</head>");  
    
  // Web Page Heading  
  client.println("<body><h1>Data-On-Tag Plug</h1>");  
   
  // Display buttons for Blue LED  
  client.println("<p>1. Device is " + DeviceState + "</p>");    
  if (DeviceState == "off") 
  {  
   client.println("<p><a href=\"/Device/on\"><button>Turn ON</button></a></p>");  
  } else 
  {  
   client.println("<p><a href=\"/Device/off\"><button>Turn OFF</button></a></p>");  
  }   
   
  client.print("<hr>");  
    
  client.println("</body></html>");  
  client.println();  
 }  
   
 void updateDevice() {  
  // In here we will check the HTTP request of the connected client  
  //  using the HTTP GET function,  
  //  Then turns the LED on / off according to the HTTP request  
  if    (http.indexOf("GET /Device/on") >= 0) {  
   Serial.println("Device on");  
   DeviceState = "on";  
   digitalWrite(Device, HIGH);  
  } else if (http.indexOf("GET /Device/off") >= 0) {  
   Serial.println("Device off");  
   DeviceState = "off";  
   digitalWrite(Device, LOW);  
  } 
 }  

 void Create_Password_SetupAP()
 {
    WiFi.begin();
    Serial.println("WiFi began");
    WiFi.macAddress(mac);
    
    Serial.print("MAC: ");
    Serial.print(mac[0],HEX);
    Serial.print(":");
    Serial.print(mac[1],HEX);
    Serial.print(":");
    Serial.print(mac[2],HEX);
    Serial.print(":");
    Serial.print(mac[3],HEX);
    Serial.print(":");
    Serial.print(mac[4],HEX);
    Serial.print(":");
    Serial.println(mac[5],HEX);

    Serial.println("Creating Password from MAC ID");
    int mac0 = mac[0];
    int mac1 = mac[1];
     one = mac0;
     Two = one + mac1;
     Pass = Two + "DOT";
     Serial.println(Pass);

    password = Pass.c_str(); 
    
    Serial.print("Connecting to ");  
    Serial.println(ssid);  
  
    WiFi.softAP(ssid, password);  
   
  Serial.println( "" );  
  Serial.println( "WiFi AP is now running" );  
  Serial.println( "IP address: " );  
  Serial.println( WiFi.softAPIP() ); 
 }

 void Set_New_SSID()
 {
  Check_New_Client();
 }


void Check_New_Client()
{
  if ( client = server.available() ) {  // Checks if a new client tries to connect to our server  
   Serial.println("New Client.");  
   String clientData = "";  
   while ( client.connected() ) {    // Wait until the client finish sending HTTP request  
    if ( client.available() ) {     // If there is a data,  
     char c = client.read();      //  read one character  
     http += c;            //  then parse it  
     Serial.write(c);    
     if (c == '\n') {         // If the character is carriage return,   
                      //  it means end of http request from client  
      if (clientData.length() == 0) { //  Now that the clientData is cleared,  
       sendResponse();        //    perform the necessary action  
       updateSSID();  
       //updateSSIDWebpage();  
       break;  
      } else {  
       clientData = "";       //  First, clear the clientData  
      }  
     } else if (c != '\r') {      // Or if the character is NOT new line  
      clientData += c;        //  store the character to the clientData variable  
     }  
    }  
   }   
   http = "";  
   client.stop();            // Disconnect the client.  
   Serial.println("Client disconnected.");  
   Serial.println("");  
  }  
}

void updateSSID()
{

  /*Steps:
   * 1. Fetch new SSID
   * 2. Store it
   * 3. Disconnect AP
   * 4. Assign new SSID
   * 5. Restore AP
   * 6. Update to web page
  */
   if(http.indexOf("GET /changeSSID") >= 0)
   {  
    Serial.println(http);
     NewSSID = http.c_str();
     Serial.print("New SSID fetched:");
     Serial.println(NewSSID);
   }
   Serial.println("Disconnecting SoftAP");
   WiFi.softAPdisconnect (true);
   Serial.println("Soft AP Disconnected");
   Serial.print("Connecting to ");  
   Serial.println(NewSSID);  

    WiFi.softAP(NewSSID, password);  
   
   Serial.println( "" );  
   Serial.println( "WiFi AP is now running" );  
   Serial.println( "IP address: " );  
   Serial.println( WiFi.softAPIP() ); 
   
}

void updateSSIDWebpage()
{
  
}

I thought I might need to use POST method? if so how I do have to use it?
The ESP32 is not going to internet this all just works on WLAN
Any help please? Thanks in advance

could you use a HTML Form

can you guide me with an example please?

if you follow the link https://randomnerdtutorials.com/esp32-esp8266-input-data-html-form/ it gives an example of the use of a HTML form

It is actually what I'm looking for. But just one query. It uses the "ESPAsyncwebserver" and my existing code doesn't. is there any way to do it without using that library? can you help me out with that?

as far I know you need ESP Async WebServer to support multiple connections at the same time

1 Like

No there is no multiple connection. My apologies for the confusion.

Here's the sequence I need to achieve with only one client at a time:

  1. Make a password from MAC
  2. Set softAp using that password
  3. client connects to it and sends the new SSID
  4. ESP receives this and changes the SSID and reboots the softAp with new SSID and old password
  5. after that we manuakky connect the client to ESP32 and control the deivce connected to it

when you get the AsyncWebServerRequest check the remoteIP address and refuse any you don't want?, e.g.

  // Send web page with input fields to client
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    Serial.print("AsyncWebServerRequest from client with IP: ");
    Serial.println(request->client()->remoteIP());
    request->send_P(200, "text/html", index_html);
  });

example run

Access point enter data from form
.....
IP Address: 192.168.1.164
AsyncWebServerRequest from client with IP: 192.168.1.148
AsyncWebServerRequest from client with IP: 192.168.1.68

No No this scenario will never happen. There will always only one client connecting to the ESP32 AP no matter what

if HTML Forms will meet your requirements is "ESPAsyncwebserver" a problem?

No, not at all actually. Its just that I will have to change my entire existing code

you will find this often happens
when you are working on a project the end user changes the specification and one has to reimplement the code.
At least one is only dealing with code - hardware problems are more difficult often resulting in a circuit redesign and layout and making new PCBs.
This has been a major problem recently due to the world wide shortage of chips - chips one has used for years are no longer available and alternatives evaluated and PCBs modified at major costs and time delays.

1 Like

I completely agree with you. fortunately this time, for this project I do not have to work on hardware. I'll implement the async webserver and get back in here to let you knnow how it goes

So, I tried combining both the codes and here's what I have done till now.

#ifdef ESP32
  #include <WiFi.h>
  #include <AsyncTCP.h>
#else
  #include <ESP8266WiFi.h>
  #include <ESPAsyncTCP.h>
#endif
#include <ESPAsyncWebServer.h>

#define Device 2

AsyncWebServer server(80);
//WiFiServer server(80);  
//WiFiClient client;  
   
 const char* Old_ssid   = "ESP32-Data-On-Tag";// This is the SSID that ESP32 will broadcast  
  
// Create the global variable  
String http;  
String DeviceState = "off";  

byte mac[6];
String one, Two, Pass;

const char* PARAM_INPUT1 = "input1";
const char* password;

const char* PARAM_INPUT_1 = "output";
const char* PARAM_INPUT_2 = "state";

char ssid[64];

// HTML web page to handle 3 input fields (input1, input2, input3)
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html><head>
  <title>ESP Change ssid</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <style>
  html {font-family: Arial; display: inline-block; text-align: center;}
    h2 {font-size: 3.0rem;}
    p {font-size: 3.0rem;}
    body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}
    .switch {position: relative; display: inline-block; width: 120px; height: 68px} 
    .switch input {display: none}
    .slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 6px}
    .slider:before {position: absolute; content: ""; height: 52px; width: 52px; left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 3px}
    input:checked+.slider {background-color: #b30000}
    input:checked+.slider:before {-webkit-transform: translateX(52px); -ms-transform: translateX(52px); transform: translateX(52px)}
  </style>
  </head>
  <body>
  <form action="/get">
    input1: <input type="text" name="input1">
    <input type="submit" value="Submit">
  </form><br>
  %BUTTONPLACEHOLDER%
<script>function toggleCheckbox(element) {
  var xhr = new XMLHttpRequest();
  if(element.checked){ xhr.open("GET", "/update?output="+element.id+"&state=1", true); }
  else { xhr.open("GET", "/update?output="+element.id+"&state=0", true); }
  xhr.send();
}
</script>
</body></html>)rawliteral";

void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Not found");
}

// Replaces placeholder with button section in your web page
String processor(const String& var){
  //Serial.println(var);
  if(var == "BUTTONPLACEHOLDER"){
    String buttons = "";
    buttons += "<h4>Output - GPIO 2</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"2\" " + outputState(2) + "><span class=\"slider\"></span></label>";
    return buttons;
  }
  return String();
}

String outputState(int output){
  if(digitalRead(output)){
    return "checked";
  }
  else {
    return "";
  }
}

void Create_Password_SetupAP()
 {
    WiFi.begin();
    Serial.println("WiFi began");
    WiFi.macAddress(mac);
    
    Serial.print("MAC: ");
    Serial.print(mac[0],HEX);
    Serial.print(":");
    Serial.print(mac[1],HEX);
    Serial.print(":");
    Serial.print(mac[2],HEX);
    Serial.print(":");
    Serial.print(mac[3],HEX);
    Serial.print(":");
    Serial.print(mac[4],HEX);
    Serial.print(":");
    Serial.println(mac[5],HEX);

    Serial.println("Creating Password from MAC ID");
    int mac0 = mac[0];
    int mac1 = mac[1];
     one = mac0;
     Two = one + mac1;
     Pass = Two + "DOT";
     Serial.println(Pass);

    password = Pass.c_str(); 
    
    Serial.print("Connecting to ");  
    Serial.println(Old_ssid);  
  
    WiFi.softAP(Old_ssid, password);  
   
  Serial.println( "" );  
  Serial.println( "WiFi AP is now running" );  
  Serial.println( "IP address: " );  
  Serial.println( WiFi.softAPIP() ); 
 }

 void  Reset_SSID()
{
  WiFi.softAPdisconnect (true);
  delay(500);
  Serial.print("Connecting to New SSID: ");  
  Serial.println(ssid);

  WiFi.softAP(ssid, password);  
   
  Serial.println( "" );  
  Serial.println( "WiFi AP is now running with New SSID" );  
  Serial.println( "IP address: " );  
  Serial.println( WiFi.softAPIP() ); 
}

 void setup() 
 {  
    pinMode(2, OUTPUT);
    digitalWrite(2, LOW);
    
    Serial.begin(115200);
    delay(1000);

    Serial.println();
    Serial.print("Program Start...");

    Create_Password_SetupAP();

    // Send web page with input fields to client
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
  {
    request->send_P(200, "text/html", index_html);
  });

  // Send a GET request to <ESP_IP>/get?input1=<inputMessage>
  server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) 
  {
    String inputMessage;
    String inputParam;
    // GET input1 value on <ESP_IP>/get?input1=<inputMessage>
    if (request->hasParam(PARAM_INPUT1)) 
    {
      inputMessage = request->getParam(PARAM_INPUT1)->value();
      inputParam = PARAM_INPUT1;
    }
    Serial.println(inputMessage);
    //ssid = char(inputMessage); 
    inputMessage.toCharArray(ssid,64);
    Serial.print("New SSID is:");
    Serial.println(ssid);
    Reset_SSID();
  }
  );
 // Send a GET request to <ESP_IP>/update?output=<inputMessage1>&state=<inputMessage2>
  server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request)
   {
    String inputMessage1;
    String inputMessage2;
    // GET input1 value on <ESP_IP>/update?output=<inputMessage1>&state=<inputMessage2>
    if (request->hasParam(PARAM_INPUT_1) && request->hasParam(PARAM_INPUT_2)) 
    {
      inputMessage1 = request->getParam(PARAM_INPUT_1)->value();
      inputMessage2 = request->getParam(PARAM_INPUT_2)->value();
      digitalWrite(inputMessage1.toInt(), inputMessage2.toInt());
    }
    else 
    {
      inputMessage1 = "No message sent";
      inputMessage2 = "No message sent";
    }
    Serial.print("GPIO: ");
    Serial.print(inputMessage1);
    Serial.print(" - Set to: ");
    Serial.println(inputMessage2);
    request->send(200, "text/plain", "OK");
   }
  );
  server.onNotFound(notFound);
  // Start our ESP32 server  
  server.begin();  
 }
  
   
 void loop()
 {  
  
 }  
   

What is expected to happen:

  1. Fetch the MAC
  2. Generate Password from MAC
  3. Setup Soft AP with this password and default (old SSID)
  4. connect to the ESP hotspot, go to the browser type in the IP
  5. Change the SSID to desired name
  6. Reinitate the Soft AP with New SSID and same password
  7. Control the LED connected to GPIO 2

Now after I upload the code to my ESP32 and type in the IP in web browser I can't see anything with something appears as "Problem loading page"
Did I do anything wrong in the webpage section? I have no idea about HTML coding. Please help me with this

Another question (which might be dumb one to ask tho) I noticed all the examples of async web server are written in void setup and not in loop. While all the examples of wifi are in loop. Why is it so?
Setup is supposed to be run once and loop supposed to be run repeatedly, right?

@horace can you please tell me what mistake am I doing here?

if I run code on a Node32S it appears to work OK

I connect my PC to SSID ESP32-Data-On-Tag password 132204DOT and open URL 192.168.4.1
SSID_1

I enter the new SSID and click Submit

a new WiFi SSID appears SSID_TEST and I to connect to it and open URL 192.168.4.1
SSID_2

the ESP32 crashes with a CORRUPT HEAP message and reboots, .g. output of serial monitor is

Program Start...WiFi began
MAC: 84:CC:A8:7A:56:6C
Creating Password from MAC ID
132204DOT
Connecting to ESP32-Data-On-Tag

WiFi AP is now running
IP address: 
192.168.4.1
SSID_TEST
New SSID is:SSID_TEST
Connecting to New SSID: SSID_TEST

WiFi AP is now running with New SSID
IP address: 
192.168.4.1
SSID_TEST
New SSID is:SSID_TEST
Connecting to New SSID: SSID_TEST

WiFi AP is now running with New SSID
IP address: 
192.168.4.1
SSID_test2
New SSID is:SSID_test2
CORRUPT HEAP: Bad tail at 0x3ffd11d0. Expected 0xbaad5678 got 0x00000201
abort() was called at PC 0x400869b5 on core 0

ELF file SHA256: 0000000000000000

Backtrace: 0x4008856c:0x3ffb5260 0x400887e9:0x3ffb5280 0x400869b5:0x3ffb52a0 0x40086ae1:0x3ffb52d0 0x400f82db:0x3ffb52f0 0x400f41a9:0x3ffb55b0 0x400f4120:0x3ffb5600 0x4008cec5:0x3ffb5630 0x40081c22:0x3ffb5650 0x400868ad:0x3ffb5670 0x4000bec7:0x3ffb5690 0x400dd25e:0x3ffb56b0 0x400dd3dd:0x3ffb56d0 0x400e64e5:0x3ffb5720 0x400e35b6:0x3ffb5740 0x40109552:0x3ffb5760 0x400897fa:0x3ffb5790

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:10124
load:0x40080400,len:5856
entry 0x400806a8

Program Start...WiFi began
MAC: 84:CC:A8:7A:56:6C
Creating Password from MAC ID
132204DOT
Connecting to ESP32-Data-On-Tag

WiFi AP is now running
IP address: 
192.168.4.1

looks as though the code is basically doing what you want but is crashing on second setting of SSID - CORRUPT HEAP is typically array overflow, menory fragmentation, etc

may be worth printing the ESP32 Arduino: Getting the Free Heap size

Thanks for the update. I was not able to see that webpage at my end all I could see was "Problem loading page" can you tell me what might the reason for it? Also in your screen shots I couldn't see the slider for controlling the LED it was supposed to be there. were you able to see it?

I will go thru the link you have suggested and get back here

Thank you so much. I really appreciate your kind help!

no slider on webpage - the page is as screen dumps in post #16

what ESP32 board are you using?

I am using a ESP-WROOM-32_38 - I changed the IDE baord to DOIT ESP32 DEVKIT V1

ran it and I managed 5 changes of SSID before it crashed

Program Start...WiFi began
MAC: 84:CC:A8:7A:56:6C
Creating Password from MAC ID
132204DOT
Connecting to ESP32-Data-On-Tag

WiFi AP is now running
IP address: 
192.168.4.1
SSID_3
New SSID is:SSID_3
Connecting to New SSID: SSID_3

WiFi AP is now running with New SSID
IP address: 
192.168.4.1
SSID_3
New SSID is:SSID_3
Connecting to New SSID: SSID_3

WiFi AP is now running with New SSID
IP address: 
192.168.4.1
SSID_4
New SSID is:SSID_4
Connecting to New SSID: SSID_4

WiFi AP is now running with New SSID
IP address: 
192.168.4.1
SSID_5
New SSID is:SSID_5
Connecting to New SSID: SSID_5

WiFi AP is now running with New SSID
IP address: 
192.168.4.1
SSID_6
New SSID is:SSID_6
Connecting to New SSID: SSID_6

WiFi AP is now running with New SSID
IP address: 
192.168.4.1
assertion "new_rcv_ann_wnd <= 0xffff" failed: file "/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/lwip/lwip/src/core/tcp.c", line 779, function: tcp_update_rcv_ann_wnd
abort() was called at PC 0x400f4123 on core 0

ELF file SHA256: 0000000000000000

Backtrace: 0x4008856c:0x3ffb3dd0 0x400887e9:0x3ffb3df0 0x400f4123:0x3ffb3e10 0x40119a42:0x3ffb3e40 0x40119ac9:0x3ffb3e60 0x400d1e32:0x3ffb3e80 0x40116560:0x3ffb3ea0 0x400897fa:0x3ffb3ed0

Rebooting...
ets Jun  8 2016 00:22:57

I'm using ESP32 DOIT DevKit V1. There was supposed to be a slider to control the LED :frowning:

Should I use that code in the link in my code to check the free heap?