ESP32 Arduino HTTP Server: Serving HTML and JavaScript

The objective of this post is to explain how to serve a HTML webpage with some JavaScript from a HTTP webserver running on the ESP32, using the Arduino core. The tests of this ESP32 tutorial were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 FireBeetle board.


Introduction

The objective of this post is to explain how to serve a HTML webpage with some JavaScript from a HTTP webserver running on the ESP32, using the Arduino core.

You can check here in detail how to install and get started with the HTTP web server library we are going to use, which allows to run the HTTP web server asynchronously.

In terms of Arduino code, it will be the same we have covered in this previous post, which explains how to serve a HTML page from PROGMEM. In this case, the changes in the code will be performed in the HTML code, which will now have additional JavaScript.

We will use the HTML example from that post, which contains a very simple form with two fields for the user to input the access credentials to a WiFi network, namely the network name and the password.

Previously, when we clicked the submit button, nothing happened. Now, we will add some JavaScript that will get the form data, convert it to JSON and print it in a popup window.

The tests of this ESP32 tutorial were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 FireBeetle board.


The JavaScript code

In this section, we will only analyze the JavaScript code, which will be inside a Script tag on the HTML code. Thus, we will develop a function to be executed when the form is submitted.

In JavaScript, the syntax for declaring a function corresponds to the function keyword, followed by the name of the function. After the name of the function, we specify the parameters inside parenthesis, separated by commas if we have multiple.

Note that since JavaScript is a dynamically typed language, we don’t specify the type of the arguments (like we do in Arduino or C++, for example) and thus we just need to specify their names.

In our case, we will call our function formToJson and it will receive an argument called form. This argument will be an object representing our form, from which we will gather the information inputted by the user.

The body of the JavaScript function is then specified inside brackets, as can be seen below.

function formToJson(form){
// function code goes here
}

Inside our function we will retrieve the values that the user has inserted for both the password and ssid fields into two distinct JavaScript variables.

In JavaScript, we can declare a variable using the var keyword followed by the name of the variable. Then, we assign it with the equal operator (=).

We will need to retrieve the values from the form object that we defined as input of our JavaScript function.

We can access an object representing each input field of the form using their tag name attribute, which we need to define in the HTML  input tags nested inside the form tag. We will see HTML part in the following section.

So, we will assume that the HTML input field of the form for the password will be named “pass” and the HTML input field for the network name will be “ssid” (from service set identifier, which is the technical term used to denominate the name of a WiFi network).

So, in JavaScript, we can retrieve these objects by accessing our form object like this:

form.pass // Assumes an input HTML tag with name = "pass" nested in the HTML form tag
form.ssid // Assumes an input HTML tag with name = "ssid" nested in the HTML form tag

In both cases, we end up accessing objects representing each input and to get their actual value, we need to access their value attribute, as shown below.

var pass = form.pass.value;
var ssid = form.ssid.value;

Now that we have retrieved the value for both input fields, we want to convert them into a JSON string. Although in this tutorial we will simply print the JSON string to a JavaScript alert window, this could be useful to submit the data in JSON format to the server, for example.

In JavaScript, we can easily serialize and deserialize JSON using the JSON object, which we can call from our code.

In our case, we want to use its stringify method to convert a JavaScript object composed by the previously retrieved SSID (network name) and pass into a string.

We first need to build a JavaScript object from these variables. In JavaScript, we can use the object initializer notation to create an object very simply. Thus, we just need to enclose key value pairs inside brackets, as can be seen below.

{
pass:pass,
ssid:ssid
}

Note that in each pair, the name of the left is the key and the name of the right is the value. So our object will have a key named “pass” and another named “ssid”. The values are the ones from our variables, which have the same name.

So, in order to convert our object to a JSON string, we just need to call the stringify method of the JSON object, passing as input our JavaScript object, and assign the result to a new variable.

var jsonFormInfo = JSON.stringify({
	pass:pass,
	ssid: ssid
});

To finalize, we will call the alert method of the window object to create a popup window in the browser with an alert dialog, which will be our JSON string. The final code can be seen below, and already includes the call to this function, passing as input the JSON string.

function formToJson(form){

	var pass = form.pass.value;
	var ssid = form.ssid.value;

	var jsonFormInfo = JSON.stringify({
		pass:pass,
		ssid: ssid
	});

	window.alert(jsonFormInfo);

}

Note that our code is very simple and we assume that the user always fills both fields before clicking the submit button. Naturally, you can add some extra logic to check if both fields have values and act accordingly.

To finalize this section, it is important to mention that JavaScript executes in the client side. Thus, the code we are developing here will run on the web browser of the client that contacts our server and not on the ESP32.

Just as curiosity, there is a way to program the ESP32 using JavaScript (check a tutorial here), but it’s a completely different thing from what we are doing here and should not be confused.


The HTML code

As mentioned, the HTML code for this tutorial will be similar to the one from the previous post, with the difference that now we will have the JavaScript function, which will be executed upon clicking the submit button of the form.

The first thing we need to do is grabbing the previous JavaScript function and enclosing it inside a script HTML tag, so we can call it in the form submit event.

<script language = "JavaScript">
	function formToJson(form){
		
		var pass = form.pass.value;
		var ssid = form.ssid.value;
		
		var jsonFormInfo = JSON.stringify({
			pass:pass, 
			ssid: ssid
		});

		window.alert(jsonFormInfo);
		
	}
</script>

Next, in the form tag, we need to add the call for this function on the onSubmit attribute. First, we will keep the event.preventDefault call, which will prevent the default submitting behavior of the form.

Followed by that, we will call the formToJson function, passing as input the word this, which basically means that we are going to pass as input the object representing the form.

<form onSubmit = "event.preventDefault(); formToJson(this);">
...
</form>

Remember that both the input tags which we will use to render the input fields for the network name and password will need to have their name attributes matching the ones we have used in the JavaScript code. If the names don’t match, then we will not be able to retrieve the values.

<input type = "text" name = "ssid"/>
...
<input type = "text" name = "pass"/>

The final complete HTML code can be seen below.

<script language = "JavaScript">
	function formToJson(form){
		
		var pass = form.pass.value;
		var ssid = form.ssid.value;
		
		var jsonFormInfo = JSON.stringify({
			pass:pass, 
			ssid: ssid
		});

		window.alert(jsonFormInfo);
		
	}
</script>

<form onSubmit = "event.preventDefault(); formToJson(this);">
    <label class="label">Network Name</label>
    <input type = "text" name = "ssid"/>
    <br/>
    <label>Password</label>
    <input type = "text" name = "pass"/>
    <br/>
    <input type="submit" value="Submit">
</form>


Preparing the HTML / JavaScript code for Arduino

We will need to serve our HTML and JavaScript code from the ESP32, which we will program in C++ / Arduino. Thus, we will need to convert it to a representation that our microcontroller understands and is able to work with.

The previous post has a detailed guide how to do it, but to sum up we will first compress the code to a single line, getting rid of all the unnecessary empty spaces and lines (so it occupies less space in the ESP32), followed by escaping it to a C string.

So, we first use this online tool to minify the whole code, followed by this tool to convert it to an escaped C string. You should end with the following string:

"<script language=\"JavaScript\">function formToJson(form){var pass=form.pass.value;var ssid=form.ssid.value;var jsonFormInfo=JSON.stringify({pass:pass, ssid: ssid});window.alert(jsonFormInfo);}</script> <form onSubmit=\"event.preventDefault(); formToJson(this);\"> <label class=\"label\">Network Name</label> <input type=\"text\" name=\"ssid\"/> <label>Password</label> <input type=\"text\" name=\"pass\"/> <input type=\"submit\" value=\"Submit\"></form>"


The Arduino code

Please note that the Arduino code below is exactly the same of the previous tutorial, with the exception that the HTML string is different. Thus, we will only do a quick description of the code on this section. Please refer to the previous post if you need more detail.

We start the Arduino code by doing all the library includes. Followed by that, we declare two global variables to hold the credentials from the WiFi network to which we will connect to.

Next, we will need an object of class AsyncWebServer, which will be later used to configure and run the server.

After that, we will declare a string in PROGMEM with our HTML page. Thus, we will use the previously obtained compressed and escaped HTML.

#include <WiFi.h>
#include <FS.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>

const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPass;

AsyncWebServer server(80);
const char HTML[] PROGMEM = "<script language=\"JavaScript\">function formToJson(form){var pass=form.pass.value;var ssid=form.ssid.value;var jsonFormInfo=JSON.stringify({pass:pass, ssid: ssid});window.alert(jsonFormInfo);}</script> <form onSubmit=\"event.preventDefault(); formToJson(this);\"> <label class=\"label\">Network Name</label> <input type=\"text\" name=\"ssid\"/> <label>Password</label> <input type=\"text\" name=\"pass\"/> <input type=\"submit\" value=\"Submit\"></form>";

The remaining code will be done in the setup function. We will first open a serial connection and then connect the ESP32 to the WiFi network. After the connection, we will print the ESP32 IP on the network, so we can later reach the server using a web browser.

Next we will configure a route in the “/html” path, which will listen to incoming HTTP GET requests. Its handling function will correspond to return the previously declared HTML string.

To finalize, we call the begin method on our server object, so it starts listening to the incoming requests. The Arduino loop function will be left empty since the server works asynchronously and thus no periodic client handling calls need to be done.

The full source code can be seen below.

#include <WiFi.h>
#include <FS.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPass;

AsyncWebServer server(80);

const char HTML[] PROGMEM = "<script language=\"JavaScript\">function formToJson(form){var pass=form.pass.value;var ssid=form.ssid.value;var jsonFormInfo=JSON.stringify({pass:pass, ssid: ssid});window.alert(jsonFormInfo);}</script> <form onSubmit=\"event.preventDefault(); formToJson(this);\"> <label class=\"label\">Network Name</label> <input type=\"text\" name=\"ssid\"/> <label>Password</label> <input type=\"text\" name=\"pass\"/> <input type=\"submit\" value=\"Submit\"></form>";

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

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  Serial.println(WiFi.localIP());

  server.on("/html", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/html", HTML);
  });

  server.begin();
}

void loop(){
}


Testing the code

To test everything, first compile and upload the Arduino code to the ESP32. Then, open the serial monitor to retrieve the IP of the device on the WiFi network.

Once you have the IP, open a web browser of your choice and paste the following in the address bar, changing {yourDeviceIP} for the IP you have just copied from the serial monitor.

http://{yourDeviceIP}/html

You should get the HTML page we have just implemented, with the form inputs and the submit button. To test it, insert some values in both fields and click the submit button. As indicated in figure 1, you should get an alert window with a JSON string containing the submitted values.

ESP32 Arduino HTTP server HTML and JavaScript.png

Figure 1 – Output of the alert window, after submitting the form.


Related Posts

Advertisements
This entry was posted in ESP32 and tagged , , , , , , , , . Bookmark the permalink.

5 Responses to ESP32 Arduino HTTP Server: Serving HTML and JavaScript

  1. Carter says:

    Thanks for your series of tutorials. They are very helpful and clearly explained.

    Liked by 1 person

  2. Pingback: ESP32 Arduino: HTTP server over soft AP | techtutorialsx

  3. Pingback: ESP32 Arduino HTTP server: external and internal redirects | techtutorialsx

  4. Pingback: ESP32 Arduino HTTP server: route not found handling | techtutorialsx

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s