Using ESPAsyncWebServer, once web server submit button pushed, to simultaneously send query parameters and move from the submenu to the main menu?

There are two GUI pages: index (the main menu) and selection (the submenu).


Main menu:
image


Submenu:


Once a shape (submit button) is pushed, it should return to the main menu and send the three query parameters. For example, if "Circle" is selected with shape size "1" and speed "Regular", it should return a URL with "?size=1&speed=2&circle=3".

The files are below and here: MinimalExamples/22-1-25_query_parameters_submitButton at main · adamelli/MinimalExamples · GitHub

File structure

sketch (folder)

  • sketch.ino
  • data (folder)
    • index.html
    • selection.html

sketch.ino

#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>
#include <painlessMesh.h>

const char* ssid = "Wireless Controller";
const char* password = "12345678";

// User stub
void sendMessage() ; // Prototype so PlatformIO doesn't complain

Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );

void sendMessage() {
  taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 5 ));
}

AsyncWebServer server(80);

void notFound(AsyncWebServerRequest *request) {
    request->send(404, "text/plain", "Not found");
}
IPAddress IP(192, 168, 1, 1);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

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



  // Initialize SPIFFS
  if (!SPIFFS.begin(true))
  {
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }



  WiFi.softAP(ssid, password);
  delay(500);
  WiFi.softAPConfig(IP, gateway, subnet);
  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);




  server.on("/selection.html", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(SPIFFS, "/selection.html", String(), false );
  });


    

// Main menu index page works (but not query parameters)
//  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
//    request->send(SPIFFS, "/index.html", String(), false );
//  });





// Query parameters works (but not main menu index page)
  server.on("/", 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", "what should be in here that does not clear the page?");
  });






  server.begin();
}



void loop() {}

index.html

<!DOCTYPE html>
<html>
<body>

  <h1>Main Menu</h1>
  

<p><a href="/selection.html"><button class="button">Selection</button></a></p>

<p><a href="/notMinimal.html"><button class="button">Oblivion</button></a></p>


</body>
</html>

selection.html

<!DOCTYPE html>
<html>
<body> 
<!-- -->
<form action="/" method="get"> 



	<label for="size" style="font-size: 22px">Shape Size:</label>

	<select name="size" id="size" style="font-size: 22px;">
	  <option value="1"> 1   </option>
	  <option value="2"> 1/2 </option> 
		</select>


	<p><label for="speed" style="font-size: 22px">Speed:</label>
	
	<select name="speed" id="speed" style="font-size: 24px">
	  <option value="1"> 		  Slowest </option>
	  <option value="2" selected> Regular </option>
	</select></p>




  <p><a href="/selection"><button class="submit" name="circle" value="3">Circle</button></a></p>
  
  <p><a href="/selection"><button class="submit" name="square" value="4">Square</button></a></p>



</form>

</body>
</html>

The data files must be uploaded via "Tools" → "ESP32 Sketch Data Upload".

How can the definitions, server.on("/" be combined so the data (size/speed/shape) is viewable in the serial monitor AND where the main and submenu remain the same (with their buttons)?

I have tried...

  • putting request->send(SPIFFS, "/selection.html", String(), false); and request->send(200, "text/plain", "message received"); together inside server.on("/", HTTP_GET, [](AsyncWebServerRequest * request)

  • sending different stuff for request->send(200, "text/plain", "message received"); even though I still do not understand how to get it to submit data, and return to the main menu, without clearing it out with a new message (various trial and error combinations either did not allow it to compile or just made one of the pages "Not found")

  • messing with HTML stuff (nothing changed)

I think the solution involves changing something with combining request->send(SPIFFS, "/index.html", String(), false ); (currently commented out) and the request->send(200...

Really not clear exactly what you're looking for, but it sounds like you might want to use server sent messaging, which allows the server to send any message it wants to the client at any time. The ESPAsyncWebServer supports this, and it is quite simple to implement. There are examples in the ESPAsyncWebServer examples, and several web articles explaining it.

I'm trying to send three pieces of information (size, speed and shape) from the GUI to the ESP32 (to manipulate). The last parameter, shape, is in the form of submit buttons.

At this point, if it could be made to just submit the three query parameters and stay in the submenu (instead of going back to the main menu), that would be good enough.

OK, so you want the client (browser) to send the size/speed/shape parameters to the server when either shape button is pressed? You simply have to append the parameters to the url that gets sent to the server when the button is clicked. There are many way to make that happen. The way I find the most useful is use a few lines of javascript and AJAX to send an aynchronous GET event that includes the URL with the parameters appended to it. The format of the URL is standard HTPP GET syntax, which you can find online. If you google "AJAX aynchronous events" you'll find lots of tutorials and examples for setting up the event handlers. It takes only perhaps 20-30 or so lines of javascript to do what you need. You'll also have to setup the server side to parse the arguments it receives with the GET request, which is probably another 20-30 lines of code.

This is a good place to start: AJAX Introduction

<form action="mainMenu.html" method="post">

I hope it doesn't need an internet connection because this application is an ESP32 access point.

No, it does not require an internet connection. It is simply sending HTTP messages between the client and server, which you are already doing. The rest is just software.

I totally agree with @RayLivingston.
With a small bunch of Javascript lines of code you can do this and much much more.

For example with a similar need, I would not have used two separate pages, but some Javascript (and CSS properties of the HTML elements) to "hide" the options menu and make it appear dynamically only when needed for having a more modern and easy-to-use feeling with a single page "web-app".

Just an example of what I mean: How To Create a Collapsible menu (w3schools.com)

With the same technique, you could also set HTML elements properties (like inputs, selections etc etc) according to which is current set on webserver side: on page load, send an AJAX request with Javascript and then parse the server response in order to set values.

I have written some ready to try examples for this library of mine, but you can easilty adapt to work even with ESPAsyncWebServer, just need the right handlers for the web requests in your sketch.

Check the sources in "data" subfolder content in each example for HTML, Javascript and CSS.

Actually your post gave me the idea to prepare a new example (handleFormData.ino) :grin:

Agh, it's going to take another week to figure out how to include a third language. Another forum mentioned changing to <form action="/submit" method="get"> and then something like

  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(SPIFFS, "/index.html", String(), false);
  });
  
  server.on("/selection", HTTP_POST, [](AsyncWebServerRequest * request) {
    request->send(SPIFFS, "/selection.html", String(), false);
  });
  

  
  server.on("/submit", 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", "");

  });

Although, I don't think I did something right with that either.

The changed selection.html file is this:

<!DOCTYPE html>
<html>
<body> 
<!-- -->
<form action="/submit" method="get"> 



	<label for="size" style="font-size: 22px">Shape Size:</label>

	<select name="size" id="size" style="font-size: 22px;">
	  <option value="1"> 1   </option>
	  <option value="2"> 1/2 </option> 
		</select>


	<p><label for="speed" style="font-size: 22px">Speed:</label>
	
	<select name="speed" id="speed" style="font-size: 24px">
	  <option value="1"> 		  Slowest </option>
	  <option value="2" selected> Regular </option>
	</select></p>




  <p><a href="/index.html"><button class="submit" name="circle" value="3">Circle</button></a></p>
  
  <p><a href="/index.html"><button class="submit" name="square" value="4">Square</button></a></p>



</form>

</body>
</html>

Is there some simple fix to make this minimal example work?

Try this

<form action="index.html" method="post">

@adamelli a third and even a fourth, because if you want build nice and responsive webpages you also have to handle a little CSS :wink: :upside_down_face:

Regarding your snippet of code, is still unclear what you want to achieve, at least for me.

Your page code send two HTML GET requests to /submit AsyncWebServer handler:

  • the first one is like this http://<you_esp_ip>/submit?size=1&speed=2&circle=3
  • the second is like this http://<you_esp_ip>/submit?size=1&speed=2&square=4

So you need simply parse the arguments (like library examples show to do) and use as you need.
The /submit handler return an empty reply, so in your browser you will see a blank page after submit data.

Did it work for you? Because I get a blank screen when the get/post method is changed:

sketch.ino

#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>
#include <painlessMesh.h>

const char* ssid = "Wireless Controller";
const char* password = "12345678";

// User stub
void sendMessage() ; // Prototype so PlatformIO doesn't complain

Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );

void sendMessage() {
  taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 5 ));
}

AsyncWebServer server(80);

void notFound(AsyncWebServerRequest *request) {
    request->send(404, "text/plain", "Not found");
}
IPAddress IP(192, 168, 1, 1);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

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



  // Initialize SPIFFS
  if (!SPIFFS.begin(true))
  {
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }



  WiFi.softAP(ssid, password);
  delay(500);
  WiFi.softAPConfig(IP, gateway, subnet);
  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);




  server.on("/selection.html", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(SPIFFS, "/selection.html", String(), false );
  });


    

// Main menu index page works (but not query parameters)
//  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
//    request->send(SPIFFS, "/index.html", String(), false );
//  });





// Query parameters works (but not main menu index page)
  server.on("/", 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", "what should be in here that does not clear the page?");
  });






  server.begin();
}



void loop() {}

index.html

<!DOCTYPE html>
<html>
<body>

  <h1>Main Menu</h1>
  

<p><a href="/selection.html"><button class="button">Selection</button></a></p>

<p><a href="/notMinimal.html"><button class="button">Oblivion</button></a></p>


</body>
</html>

selection.html

<!DOCTYPE html>
<html>
<body> 
<!-- -->
<form action="index.html" method="post">



	<label for="size" style="font-size: 22px">Shape Size:</label>

	<select name="size" id="size" style="font-size: 22px;">
	  <option value="1"> 1   </option>
	  <option value="2"> 1/2 </option> 
		</select>


	<p><label for="speed" style="font-size: 22px">Speed:</label>
	
	<select name="speed" id="speed" style="font-size: 24px">
	  <option value="1"> 		  Slowest </option>
	  <option value="2" selected> Regular </option>
	</select></p>




  <p><a href="/index.html"><button class="submit" name="circle" value="3">Circle</button></a></p>
  
  <p><a href="/index.html"><button class="submit" name="square" value="4">Square</button></a></p>



</form>

</body>
</html>

I thought the picture cleared that up. There are two web pages. The first is the "main menu."

The user selects an option, and they jump to a new page. In this case, I reduced the program to one choice: to go to selection.html. From there, they choose the speed and size. The third option or parameter is the shape the user wants. Once the user selects the shape, all three are sent as query parameters in the URL. That is how the ESP32 is getting all three parameters at one time. Additionally, the user is redirected back to the main menu.

What are two of the other ways besides AJAX?

You can communicate through a database, using PHP or similar. You can use server-sent events, which allows the server to control communications. Pick any common language used on web sites these days (and there are hundreds of them!). Each will have it's own way of dealing with asynchronous updates, and client/server communication. AJAX is but one.

Probably would take months for me to create 20-30 lines of JS and another 20-30 lines of original code with the AJAX method. But I guess I wasted 2-3 weeks already by trial and error (all error) trying to do without AJAX.