ESP32 webserver HTML help

Thread Starter

zazas321

Joined Nov 29, 2015
936
Hey. I am making a webserver application on my ESP32 device. I want to display the list of WIFI networks available on the internet then be able to select one and connect to it. I have already thought about how everything is going to work but I have got stuck on the html part of coding since I do not have any prior html knowledge.

Currently, my html index page looks like that:
Code:
<!DOCTYPE html>

<html>
<head>
  <title>ESP8266 Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>

 
 
  <h1>Networks detected(2.4Ghz):</h1>

<form action="/action_page">
<div class="wifi">
  <input type="radio" id="wifi1" name="wifi" value=%WIFI1%>
  <label for="wifi1"> %WIFI1%(%RSSI1%dB)</label><br>
 
  <input type="radio" id="wifi2" name="wifi" value=%WIFI2%>
  <label for="wifi2"> %WIFI2%(%RSSI2%dB)</label><br>
 
  <input type="radio" id="wifi3" name="wifi" value=%WIFI3%>
  <label for="wifi3"> %WIFI3%(%RSSI3%dB)</label><br>
</div>
 
<div class="input">
  <label for="Network_ID">Selected Network:</label>
  <input type="text" id="Network_ID" name="Network_ID"><br>
 
  <label for="Network_pass">Password:</label>
  <input type="text" id="Network_pass" name="Network_pass"><br>
</div> 
  <br>
  <input type="submit" value="Submit">
</form>
 
 
</body>

</html>
2020-11-16-104812_1920x1080_scrot.png

and my ESP32 code ( just showing the parts that handle server)
I have created 2 global varialbes.
String list_strings[10];//holds data about wifi names
String list_strings_RSSI[10];//holds data about signal strnegth

Code:
void handle_access_point() {
  Serial.println("WiFi Failed!");
  WiFi.mode(WIFI_AP);
  WiFi.softAPdisconnect (true);
  WiFi.softAP("ESPNOW123", nullptr, 3);
  Serial.print("MAC address of this node is ");
  Serial.println(WiFi.softAPmacAddress());
  Serial.println();
  Serial.print("IP address: ");
  Serial.println(WiFi.softAPIP());


  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(SPIFFS, "/index.html", String(), false, processor);
    Serial.println("executing index page");
  });
 
  server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(SPIFFS, "/style.css", "text/css");
  });
 
  server.on("/action_page", HTTP_GET, [](AsyncWebServerRequest * request) {
    Serial.println("executing action page");
    request->send(SPIFFS, "/action_page.html");

  });

  server.begin();
}


String processor(const String& var){
  Serial.println(var);

  if (var == "WIFI1"){
    Serial.println("PROCESSOR WIFI1 TRIGGERED");
    return list_strings[0];
  }
    if (var == "WIFI2"){
    Serial.println("PROCESSOR WIFI2 TRIGGERED");
   
    return list_strings[1];
  }
    if (var == "WIFI3"){
    Serial.println("PROCESSOR WIFI3 TRIGGERED");
    return list_strings[2];
  }

    if (var == "RSSI1"){
    Serial.println("PROCESSOR RSSI1 TRIGGERED");
    return list_strings_RSSI[0];
  }
    if (var == "RSSI2"){
    Serial.println("PROCESSOR RSSI2 TRIGGERED");
    return list_strings_RSSI[1];
  }
    if (var == "RSSI3"){
    Serial.println("PROCESSOR RSSI3 TRIGGERED");
    return list_strings_RSSI[2];
  }
 

}

1.
When I request the index page on my browser, I immediately trigger the processor function and fill the data that index has requested. That part works fine because as you can see from the image above, I can display the 3 nearby wifi networks and their signal strenghts.

However, What I want to do, instead of hardcoding the number of wifi networks to display which in my case I have hardcoded 3. Display all nearby wifi networks detected. But I could not find how to change my index.html code to take in a parameter as input which would tell how many wifi networks have been detected and then dynamically create an input form .


2.When I select one of the networks from the list on the browser, I want the Selected Network text input form to automatically populate with whatever I have selected.
 

MrSalts

Joined Apr 2, 2020
2,767
So please clarify how far along you are in this concept...

1) are you able to get the ESP32 server (access point) to find all available networks and load them into your webpage (above) and then access said page from another device?

If so, and could you send a screen shot of that page?

then the nest step becomes fairly easy, I just need to clarify where you are with this.
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
So please clarify how far along you are in this concept...

1) are you able to get the ESP32 server (access point) to find all available networks and load them into your webpage (above) and then access said page from another device?

If so, and could you send a screen shot of that page?

then the nest step becomes fairly easy, I just need to clarify where you are with this.
Hey. Thanks for the response. I am able to connect to the server on my linux machine and I have posted the picture on my initial post:
1605590891957.png



Also, I have managed to do part 2 of the task:
1605590846113.png
As you can see from the image above, I have the WIFI2 checked, and it shows my selection "Network_ID = %WIFI2%" - that is exactly what I wanted.


My index.html now looks like:
Code:
<!DOCTYPE html>

<html>
<head>
  <title>ESP8266 Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>

 
 
  <h1 id="Networks_detected">Networks detected(2.4Ghz):%NUMBER_OF_NETWORKS% </h1>

<form action="/action_page">
<div class="wifi">
  <input type="checkbox" id="wifi1" name="wifi" value=%WIFI1% onclick="myFunction(id,value)">
  <label for="wifi1"> %WIFI1%(%RSSI1%dB)</label><br>
 
  <input type="checkbox" id="wifi2" name="wifi" value=%WIFI2% onclick="myFunction(id,value)">
  <label for="wifi2"> %WIFI2%(%RSSI2%dB)</label><br>
 
  <input type="checkbox" id="wifi3" name="wifi" value=%WIFI3% onclick="myFunction(id,value)">
  <label for="wifi3"> %WIFI3%(%RSSI3%dB)</label><br>
</div>
 
<div class="input">




  <p id="Network_ID">Select one of the networks</p>

 
  <label for="Network_pass">Network_Password:</label>
  <input type="text" id="Network_pass" name="Network_pass"><br>
</div> 

<script>
function myFunction(id,value) {
  var checkBox = document.getElementById(id);
  var text = document.getElementById("Network_ID");
  if (checkBox.checked == true){
    text.style.display = "block";
    document.getElementById("Network_ID").innerHTML = "Network_ID:"+value;
  } else {
     document.getElementById("Network_ID").innerHTML = "Select one of the networks"
  }
}
</script>


  <br>
  <input type="submit" value="Submit">
</form>
 
 
</body>

</html>
My initial idea is to use simmilar method as I was using to retrieve the WIFI names from my ESP32 program ( using % signs ).
something like:
Code:
<h1 id="Networks_detected">Networks detected(2.4Ghz):%NUMBER_OF_NETWORKS% </h1>
Then the program would return a variable how many networks have been detected ( for example 9) , Then I would have to dynamically create form as I did here:
Code:
<div class="wifi">
  <input type="checkbox" id="wifi1" name="wifi" value=%WIFI1% onclick="myFunction(id,value)">
  <label for="wifi1"> %WIFI1%(%RSSI1%dB)</label><br>
 
  <input type="checkbox" id="wifi2" name="wifi" value=%WIFI2% onclick="myFunction(id,value)">
  <label for="wifi2"> %WIFI2%(%RSSI2%dB)</label><br>
 
  <input type="checkbox" id="wifi3" name="wifi" value=%WIFI3% onclick="myFunction(id,value)">
  <label for="wifi3"> %WIFI3%(%RSSI3%dB)</label><br>
</div>
Just this time, I would need to do it 9 times instead hardcoded 3.



I know how to request a variable from my program by using input form as following:
Code:
<input type="checkbox" id="wifi1" name="wifi" value=%WIFI1% onclick="myFunction(id,value)">
The line above would find %WIFI1% and call a process in my program running on ESP32. Then the ESP32 will assign %WIFI1% to an actual variable.

I would like to know how can I do the same thing for header since its a little bit different syntax:
Code:
<h1 id="Networks_detected">Networks detected(2.4Ghz):%NUMBER_OF_NETWORKS% </h1>
Obviously the line above wont work, since %NUMBER_OF_NETWORKS% is decoded as part of the text, but I am really not sure how can I use that properly
 
Last edited:

Thread Starter

zazas321

Joined Nov 29, 2015
936
Yes, that's the idea but you need to add a JavaScript to the top of the html page you've created (or do it inline with html). Both options are on this JavaScript Form submission tutorial.
Look at the example and execute the linked example as well.
.
https://www.w3schools.com/js/js_validation.asp
.
.

Hey. I do not fully understand how this example is relevant for me since I will not input any data into the webserver regarding the WIFI. The webserver have to request the data from my program
 

geekoftheweek

Joined Oct 6, 2013
1,201
How about instead of sending a html file you build the page in a buffer and send it as plain text.

Code:
server.on("/", HTTP_GET, (AsyncWebServerRequest *request) {

   char *your_page = "<!DOCTYPE html>\n\
          <html> \n\
          <head> \n\
          <title>ESP8266 Web Server</title>\n\
          <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\
          <link rel=\"icon\" href=\"data:,\">\n\
          <link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">\n\
          </head>\n\
          <body>\n\
          ...........      ";



     request->send(200, "text/plain", your_page);
}
The fun part will be resizing your_page to make everything work, but you could then make a simple loop to add in all the networks available.

Edit:
use request->send(200, "text/html", your_page); instead;

I found this link https://techtutorialsx.com/2017/12/...server-serving-a-html-page-from-flash-memory/ which describes the idea a bit, but not exactly using it the same way.
 
Last edited:

geekoftheweek

Joined Oct 6, 2013
1,201
After a little more digging around... I never liked javascript which lead to learning ways of figuring out how to make the server do as much as possible.

https://techtutorialsx.com/2017/12/17/esp32-arduino-http-server-getting-query-parameters/ helped my thinking along a bit more

Instead of
Code:
<div class="wifi">
       <input type="checkbox" id="wifi1" name="wifi" value=%WIFI1% onclick="myFunction(id,value)">
       <label for="wifi1"> %WIFI1%(%RSSI1%dB)</label><br>

       <input type="checkbox" id="wifi2" name="wifi" value=%WIFI2% onclick="myFunction(id,value)">
       <label for="wifi2"> %WIFI2%(%RSSI2%dB)</label><br>

       <input type="checkbox" id="wifi3" name="wifi" value=%WIFI3% onclick="myFunction(id,value)">
       <label for="wifi3"> %WIFI3%(%RSSI3%dB)</label><br>
</div>
You could then create a list of links pointing to something like "/connect?network=ssid1", "/connect?network=ssid2","/connect?network=ssid3",...
and append them to your_page started above, then append your closing html tags and send it.

then something like

Code:
    server.on("/connect", HTTP_GET, [](AsyncWebServerRequest *request){

    int paramsNr = request->params();
    Serial.println(paramsNr);

    for(int i=0;i<paramsNr;i++){

        AsyncWebParameter* p = request->getParam(i);
        Serial.print("Param name: ");
        Serial.println(p->name());
        Serial.print("Param value: ");
        Serial.println(p->value());
        Serial.println("------");
    }

    request->send(200, "text/plain", "message received");
You could then sort which network to connect with from the p->value();
 
Last edited:

Thread Starter

zazas321

Joined Nov 29, 2015
936
After a little more digging around... I never liked javascript which lead to learning ways of figuring out how to make the server do as much as possible.

https://techtutorialsx.com/2017/12/17/esp32-arduino-http-server-getting-query-parameters/ helped my thinking along a bit more

Instead of
Code:
<div class="wifi">
       <input type="checkbox" id="wifi1" name="wifi" value=%WIFI1% onclick="myFunction(id,value)">
       <label for="wifi1"> %WIFI1%(%RSSI1%dB)</label><br>

       <input type="checkbox" id="wifi2" name="wifi" value=%WIFI2% onclick="myFunction(id,value)">
       <label for="wifi2"> %WIFI2%(%RSSI2%dB)</label><br>

       <input type="checkbox" id="wifi3" name="wifi" value=%WIFI3% onclick="myFunction(id,value)">
       <label for="wifi3"> %WIFI3%(%RSSI3%dB)</label><br>
</div>
You could then create a list of links pointing to something like "/connect?network=ssid1", "/connect?network=ssid2","/connect?network=ssid3",...
and append them to your_page started above, then append your closing html tags and send it.

then something like

Code:
    server.on("/connect", HTTP_GET, [](AsyncWebServerRequest *request){

    int paramsNr = request->params();
    Serial.println(paramsNr);

    for(int i=0;i<paramsNr;i++){

        AsyncWebParameter* p = request->getParam(i);
        Serial.print("Param name: ");
        Serial.println(p->name());
        Serial.print("Param value: ");
        Serial.println(p->value());
        Serial.println("------");
    }

    request->send(200, "text/plain", "message received");
You could then sort which network to connect with from the p->value();



I had given up on this for a while but I want to accomplish what I initially started.

Been thinking about what you suggested but cant really understand how to do it. Surely there should be an easy way to request data from the ESP32 from my index page? Because when the ESP32 starts up, it calculates the number of wifi networks and it saves all Wifi names to memory. When I request index page, all this information is already available in the ES32 memory I just need to request it as I have done manually with 3 wifis.
 

geekoftheweek

Joined Oct 6, 2013
1,201
Been thinking about what you suggested but cant really understand how to do it. Surely there should be an easy way to request data from the ESP32 from my index page? Because when the ESP32 starts up, it calculates the number of wifi networks and it saves all Wifi names to memory. When I request index page, all this information is already available in the ES32 memory I just need to request it as I have done manually with 3 wifis.
Luckily 70% of the dirty work is done already. I have neared the end of my first real ESP8266 project myself and learned a lot. My initial thought was something like this for the "server.on("/", HTTP_GET, (AsyncWebServerRequest *request)".

Code:
   char *html = malloc(512); // just a random number for an example.  It sould be how ever many characters of your page are static plus one for a null character.
   sprintf(html,"<html>\n<head>\n.....</head>\n<body>\n");  // a header section
   for (i=0; i < wifi_name_count; i++) {
          html = realloc(html, 512 + strlen(html) + strlen(wifi_name[i] + additional_characters); // see next line for the additional characters
          sprintf(html+strlen(html),"<a href=\"page?connect=\"%s>%s</a><br>\n",wifi_name[i], ,wifi_name[i]);
     }
     sprintf(html+strlen(html),"</body>\n\</html>\n");
     request->send(200, "text/html", html);
     free(html);
It's quick and ugly, but it will work... sort of. Ideally you would want to have your total character count for the page figured out from the beginning. You could also then do a simple html[char_count+1] = {0}; and not mess with malloc() and realloc(); Along with that you could calculate where in the buffer to sprintf(&html[current_pos], .....) instead of using strlen() to find the end of the current string. Using malloc() would have the benefit of being able to find out if there is enough memory to allocate instead of the ESP dumping debug info on the serial terminal and rebooting if you run into a problem.

In the time since posting last I have learned with ESP modules you generally want to avoid malloc and it's friends except for temporary data (which this would qualify). The problem is realloc() may fail due to not enough free memory inline with the first malloc() or a large enough open block to work with from my understanding.

Also if I read everything correctly onServer() and the like are called each time the page is requested so instead of storing the WiFi information in memory you could rescan every time you request the page and rebuild the page to detect new networks or networks that have disappeared for whatever reason.

Then when clicking on the link the ESP would go to
Code:
server.on("/page", HTTP_GET, [](AsyncWebServerRequest *request){

int paramsNr = request->params();
Serial.println(paramsNr);

for(int i=0;i<paramsNr;i++){

AsyncWebParameter* p = request->getParam(i);
Serial.print("Param name: ");
Serial.println(p->name());
Serial.print("Param value: ");
Serial.println(p->value());
Serial.println("------");
}
// sort out which network in p->value() and is matched with p->name() == "connect" and connect to that network

request->send(200, "text/plain", "you connected");
Hopefully that makes enough sense to help you decide if you want to continue on.
 
Last edited:

geekoftheweek

Joined Oct 6, 2013
1,201
As far as the index page requesting data from the server itself it just doesn't work that way if I'm thinking what I think you are thinking. Once the html is sent out that is the end of the transaction for the page. Javascript adds some dynamic properties to the page, but it can't connect to the ESP and get more information if that is what you are wondering. Java can, but that is a whole different concept that I want to explore myself, and it's on the list. There is a way to build a Java app that your browser would run and connect with the ESP for communication through the web server or even a different server. I tried to find it again quickly, but will have to look around more later on.
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
Luckily 70% of the dirty work is done already. I have neared the end of my first real ESP8266 project myself and learned a lot. My initial thought was something like this for the "server.on("/", HTTP_GET, (AsyncWebServerRequest *request)".

Code:
   char *html = malloc(512); // just a random number for an example.  It sould be how ever many characters of your page are static plus one for a null character.
   sprintf(html,"<html>\n<head>\n.....</head>\n<body>\n");  // a header section
   for (i=0; i < wifi_name_count; i++) {
          html = realloc(html, 512 + strlen(html) + strlen(wifi_name[i] + additional_characters); // see next line for the additional characters
          sprintf(html+strlen(html),"<a href=\"page?connect=\"%s>%s</a><br>\n",wifi_name[i], ,wifi_name[i]);
     }
     sprintf(html+strlen(html),"</body>\n\</html>\n");
     request->send(200, "text/html", html);
     free(html);
It's quick and ugly, but it will work... sort of. Ideally you would want to have your total character count for the page figured out from the beginning. You could also then do a simple html[char_count+1] = {0}; and not mess with malloc() and realloc(); Along with that you could calculate where in the buffer to sprintf(&html[current_pos], .....) instead of using strlen() to find the end of the current string. Using malloc() would have the benefit of being able to find out if there is enough memory to allocate instead of the ESP dumping debug info on the serial terminal and rebooting if you run into a problem.

In the time since posting last I have learned with ESP modules you generally want to avoid malloc and it's friends except for temporary data (which this would qualify). The problem is realloc() may fail due to not enough free memory inline with the first malloc() or a large enough open block to work with from my understanding.

Also if I read everything correctly onServer() and the like are called each time the page is requested so instead of storing the WiFi information in memory you could rescan every time you request the page and rebuild the page to detect new networks or networks that have disappeared for whatever reason.

Then when clicking on the link the ESP would go to
Code:
server.on("/page", HTTP_GET, [](AsyncWebServerRequest *request){

int paramsNr = request->params();
Serial.println(paramsNr);

for(int i=0;i<paramsNr;i++){

AsyncWebParameter* p = request->getParam(i);
Serial.print("Param name: ");
Serial.println(p->name());
Serial.print("Param value: ");
Serial.println(p->value());
Serial.println("------");
}
// sort out which network in p->value() and is matched with p->name() == "connect" and connect to that network

request->send(200, "text/plain", "you connected");
Hopefully that makes enough sense to help you decide if you want to continue on.

Thanks for the response. I have managed to implement something very simmilar to what you have suggested. Instead of having index.html file and running it from SPIFFS, I generate the index page inside the program and send it directly to the server when request is made.

The function that generates HTML data:
Code:
String SendHTML(){
  String ptr = "<!DOCTYPE html>";
  ptr +="<html>";
  ptr +="<head>";
  ptr +="<title>ESP32 Temperature Monitor</title>";
  ptr +="<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
  ptr +="<link rel='icon' href='data:,'><link rel='stylesheet' type='text/css' href='style.css'>";
  ptr +="</head>";
  ptr +="<body>";
  ptr +="<div class='wifi'>";
              //list_strings[i] = WiFi.SSID(i);
            //list_strings_RSSI[i] = WiFi.RSSI(i);
    
  for(int i=0 ; i<number_of_wifi_networks ; i++){
  String str="";
  str = "wifi"+i;
  Serial.print("wifi id=");
  Serial.println(str);
  ptr += "<input type='radio' id="+str+" name='wifi' value="+list_strings[i]+" onclick='myFunction(id,value)'>";
  ptr += "<label for="+str+">"+list_strings[i]+"</label><br>";
  } 
  ptr +="</div>";

  ptr +="<form action='/action_page'><div class='input'><label for='Network_ID'>Network_ID:</label><br><input type='text' id='Network_ID' name='Network_ID' value='Select one of the networks'><br><label for='Network_pass'>Network_Password:</label><br><input type='text' id='Network_pass' name='Network_pass'><br></div>";  
  ptr +="<script>function myFunction(id,value) {var checkBox = document.getElementById(id);var text = document.getElementById('Network_ID');if (checkBox.checked == true){document.getElementById('Network_ID').value = value;} else {document.getElementById('Network_ID').value = 'Select one of the networks'}}</script>";

  ptr +="<br><input type='submit' value='Submit'></form><br><br><br><br>";

  ptr +="</body>";
  ptr +="</html>";
  return ptr;
}

Code:
  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(200, "text/html", SendHTML());
    Serial.println("executing index page");
  });
That seems to work. However, I am still uncertain regarding String vs char array. The webserver library that I use for ESP32 expects all input variables to be type String so I am tempted to use String type variables everywhere.
I am used to using char array types but I am not able to pass char array to any of the functions without the extra annoying conversions such as:

Code:
server.on("/action_page", HTTP_GET, [](AsyncWebServerRequest * request) {
    Serial.println("executing action page");
    int paramsNr = request->params();
    String Pass_string;
    String ID_string;
    Serial.println(paramsNr);

    for(int i=0;i<paramsNr;i++){
        AsyncWebParameter* p = request->getParam(i);
        Serial.print("Param name: ");
        Serial.println(p->name());
        Serial.print("Param value: ");
        Serial.println(p->value());
        Serial.println("------");

        char temp_buffer[100];
        p->name().toCharArray(temp_buffer, sizeof(temp_buffer));
        if (strcmp(temp_buffer,"Network_ID")==0){

          Serial.println("network id received");
          Serial.print("ID: ");
          Serial.println(p->value());
          ID_string=p->value();
          writeFile(SPIFFS, "/ID.txt", p->value().c_str());
          //writeFile(SPIFFS, "/ID.txt", temp_buffer);
        }

        if (strcmp(temp_buffer,"Network_pass")==0){
          Serial.println("network pass received");
          Serial.print("Pass: ");
          Serial.println(p->value());
          Pass_string=p->value();
          writeFile(SPIFFS, "/Pass.txt", p->value().c_str());
          //writeFile(SPIFFS, "/Pass.txt", temp_buffer);
        }
    }
In the code above, I have a 2 variables that I want to keep track of:
p->name() and p->value()
I want to check and compare them, but I am not able to use strcmp or any char array functions with them since they are string type, therefore I need to do a conversion:
Code:
        char temp_buffer[100];
        p->name().toCharArray(temp_buffer, sizeof(temp_buffer));
And I am not sure whether thats efficient
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
Also, second biggest problem I am trying to figure out right now is how to switch from Access point mode WIFI to station mode without restarting the ESP32 device. Initially, I start the ESP32 in access point mode, then from the webserver, I allow user to select which WIFI network he wants to connect to and input password and ID. I write this data to SPIFFS to save for the next power ON.

When the user submits the data on the webserver, I run the following function:

Code:
  server.on("/action_page", HTTP_GET, [](AsyncWebServerRequest * request) {
    Serial.println("executing action page");
    int paramsNr = request->params();
    String inputMessage_ID;
    String inputMessage_Pass;
    Serial.println(paramsNr);

        if (request->hasParam("Network_ID")) {
          inputMessage_ID = request->getParam("Network_ID")->value();
          Serial.print("Input message ID: ");
          Serial.println(inputMessage_ID);
          writeFile(SPIFFS, "/ID.txt", inputMessage_ID.c_str());
        }

        if (request->hasParam("Network_pass")) {
          inputMessage_Pass = request->getParam("Network_pass")->value();
          Serial.print("Input message pass: ");
          Serial.println(inputMessage_Pass);
          writeFile(SPIFFS, "/Pass.txt", inputMessage_Pass.c_str());
        }

    
    request->send(200, "text/html", "<h1>The following values has been changed:</h1> <br>  Network_ID: " + inputMessage_ID +"<br> Network_Pass:"+inputMessage_Pass+"<br><a href=\"/\">Return to Home Page</a>");
    attempt_wifi_connection(inputMessage_ID,inputMessage_Pass);
  });
As you can see, after data submission on the webserver, I call the function:
attempt_wifi_connection(inputMessage_ID,inputMessage_Pass);



Code:
void attempt_wifi_connection(String ID_string, String Pass_string){
//void attempt_wifi_connection(char* ID_string, char* Pass_string){
  WiFi.mode(WIFI_OFF); // First turn OFF the WIFI interface
  delay(2000); //Needed, at least in my tests WiFi doesn't power off without this for some reason
  /*
  char temp_buffer_ID[100]; // temporary storage for char array ID
  char temp_buffer_Pass[100]; // temporary storage for char array Password
   //Convert String type ID and password to char array
   ID_string.toCharArray(temp_buffer_ID, sizeof(temp_buffer_ID));
   Pass_string.toCharArray(temp_buffer_Pass, sizeof(temp_buffer_Pass));
   Serial.print("Attempting to connect to the wifi with ID and password=");
   Serial.println(temp_buffer_ID);
   Serial.println(temp_buffer_Pass);
*/

   
   WiFi.mode(WIFI_STA);//start program by attempting to connect to wifi
   //WiFi.begin(temp_buffer_ID,temp_buffer_Pass);
   WiFi.begin(ID_string.c_str(),Pass_string.c_str());
   if(WiFi.waitForConnectResult() != WL_CONNECTED)
    {
    Serial.println("WiFi Failed!");
    handle_access_point();
    return;
    }
    
   Serial.println("Connection sucessful");
   Serial.print("IP Address: ");
   Serial.println(WiFi.localIP());
}
The function above will turn OFF the wifi for 2 seconds, then attempt to start the WIFI in Station mode and connect to wifi with the data that user has submitted on the server. However, after submitting data, the device reboots :
1607325532876.png
 

geekoftheweek

Joined Oct 6, 2013
1,201
Looks good. I haven't tried async servers myself yet. I've learned a lot from your project either from looking things up to try to find an answer or just from the posts themself.

Anyways... The debugging output is a bit cryptic (as always), but something has me thinking...

Instead of
Code:
WiFi.mode(WIFI_OFF); // First turn OFF the WIFI interface
Maybe
Code:
Wifi.disconnect()
and then wait for
Code:
WIFI_EVENT_STA_DISCONNECTED --> https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#esp32-wi-fi-programming-model
then when the disconnect event happens continue with
Code:
WiFi.mode(WIFI_OFF); // First turn OFF the WIFI interface
  delay(2000); //Needed, at least in my tests WiFi doesn't power off without this for some reason
...
Something with the "task watchdog" followed by "async_top" in your debug messages has me wondering if it is trying to perform some sort of async task on the old wifi that doesn't exist anymore (if that makes sense).

One of my favorite tricks is to put in a
Code:
Serial.println("here")
and just keep moving it down one line at a time until it stops showing up in the terminal.
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
Looks good. I haven't tried async servers myself yet. I've learned a lot from your project either from looking things up to try to find an answer or just from the posts themself.

Anyways... The debugging output is a bit cryptic (as always), but something has me thinking...

Instead of
Code:
WiFi.mode(WIFI_OFF); // First turn OFF the WIFI interface
Maybe
Code:
Wifi.disconnect()
and then wait for
Code:
WIFI_EVENT_STA_DISCONNECTED --> https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#esp32-wi-fi-programming-model
then when the disconnect event happens continue with
Code:
WiFi.mode(WIFI_OFF); // First turn OFF the WIFI interface
  delay(2000); //Needed, at least in my tests WiFi doesn't power off without this for some reason
...
Something with the "task watchdog" followed by "async_top" in your debug messages has me wondering if it is trying to perform some sort of async task on the old wifi that doesn't exist anymore (if that makes sense).

One of my favorite tricks is to put in a
Code:
Serial.println("here")
and just keep moving it down one line at a time until it stops showing up in the terminal.
Thanks for the tips as always
 

geekoftheweek

Joined Oct 6, 2013
1,201
Thanks for the tips as always
No problem. I took another look to see if anything different jumps out at me today. I'm betting your program is hanging on WiFi.waitForConnectResult().

I tried to find the default watchdog times, but couldn't seem to find any. Maybe when switching to station mode it's taking too long to connect.
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
No problem. I took another look to see if anything different jumps out at me today. I'm betting your program is hanging on WiFi.waitForConnectResult().

I tried to find the default watchdog times, but couldn't seem to find any. Maybe when switching to station mode it's taking too long to connect.
Cannot get code to compile with
Code:
  while(WiFi.disconnect() != WIFI_EVENT_STA_DISCONNECTED)
    {
      Serial.println("wifint not yet disconnected");
    }
Could that be an esp-idf thing only?
 

geekoftheweek

Joined Oct 6, 2013
1,201
Could that be an esp-idf thing only?
It is possible, but WIFI_EVENT_STA_DISCONNECTED would actually get passed to an event handler when the disconnect happens.
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/event-handling.html, https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/esp_event.html

The problem with events is going to be keeping everything synchronized, and storing needed data until the event happens to allow the next step to happen.

I know with my next project I'll dump the Arduino IDE and use the esp-idf. I wanted to for the current project, but it's too close to being complete to start over and will take a bit of trial and error to get a working skeleton program to build on.

You'd have to do wifi.disconnect() and then start a loop to monitor wifi.status() until it is disconnected.
Would do the trick probably. In your loop call yield() also which should reset the watchdog timer if I have read everything correctly. Actually yield() shouldn't be needed from my experiences so far as it should disconnect fast enough not to trip the watchdog.

You could use the same concept for WiFi.waitForConnectResult(). Loop and call WiFi.status() until it shows an active connection. yield() would be a good idea here as it seems to me this is where the issue is. You could also say keep track of how many times it goes through the loop and break out after a couple hundred tries if the connection doesn't actually get established.
 
Top