The objective of this post is to explain how to serve some HTML, Javascript and CSS in a ESP8266 HTTP webserver.
Introduction
The objective of this post is to explain how to serve some HTML, Javascript and CSS in a ESP8266 HTTP webserver.
It’s important to take in consideration that HTML, Javascript and CSS are languages that are executed / rendered in the client side [1]. In this example, since we are going to do HTTP requests from a web browser, it will be its responsibility to render the HTML and CSS and to execute the Javascript we will be serving.
This means that the ESP8266 doesn’t need to know how to interpret HTML, CSS or Javascript. So, as we will see bellow, that code will be stored in strings that will be returned in the HTTP responses, pretty much the same way as we would do to return any other kind of content.
In this simple example, we will create an intro page in HTML, a page with Javascript code that will trigger an alert window when a button is clicked, and a page with a button styled with CSS.
The Arduino HTTP server code
In order to create our webserver, we will use the exact same approach explained in the previous post, which explains all the details of setting the server.
So, the most important part that we need to remember is that that we need to specify the handling function for each URL of our server. Recovering the code from the last post, we need to declare a global variable of the class ESP8266WebServer and pass as argument of the constructor the port where the server will be listening for incoming HTTP requests.
ESP8266WebServer server(80);
Then, for each URL, we specify the handling function that will be executed when a request is sent to that path. To do so, we call the On method on the server object.
For this tutorial, let’s assume that we declare the handling function inline, in order to make the code more compact.
For the sake of simplicity, we will assume that the HTML, Javascript and CSS code we are serving will be static. This means that we can declare it in a string and just return it when a HTTP request is performed on the desired URL.
Remembering again the code from the last post, we call the send method on the server object. As arguments, we pass it the return code for the request, the type of return content and the content, from left to right.
So first, we want to return the 200 HTTP code (OK code). Then, we need to make sure that we specify the return content as text/html, so the browser will know that it should be interpreted and rendered as such. The content type will always be this because for the case we are sending CSS or Javascript code, it will be embedded in HTML code.
Finally, we pass the string with the HTML/Javascript/CSS code. Check the generic function for this bellow.
server.on(“/anyPathWeWant”, [](){ //Define the handling function for the path
server.send(200, “text/html”, stringContainingCode); //Send the code in the response
});
The HTML code
In our use case, we will assume that the root URL (“/”) will show a HTML message that will have a description message and 2 links. Each of those links will redirect the user to the URL that is serving the Javascript or the CSS code. You can check the code to be used bellow.
const char * htmlMessage = ” <!DOCTYPE html> “
“<html> “
“<body> “
“<p>This is a HTML only intro page. Please select a button bellow.</p>”
“<a href=\”/javascript\”>Javascript code</a>”
“</br>”
“<a href=\”/cssButton\”>CSS code</a>”
“</body> “
“</html> “;
Explaining the details of the structure of HTML is beyond the scope of this post and only a brief analysis of what each element of the code does will be conducted.
The <!DOCTYPE html> tag tells the browser what version of HTML the document is written so that the browser knows what to expect [2]. The <html> element represents the root of an HTML document. All other elements must be descendants of this element [3]. The <body> tag specifies where the body of the document starts [4].
The <p> tag specifies a paragraph and thus we use it to indicate our description message.
The <a> tag allows us to create a hyperlink by specifying the URL of a page and the message of the hyperlink. So, in the href attribute we specify the URL we want the user to be redirected to, and between the two tags we specify the message of the hyperlink.
In this case, we are specifying a path in the current address, so we don’t need to put the IP and the port. So, when a user clicks the hyperlink, the browser knows it will need to redirect the user to http://IP:port/{href value}.
As we will see later, the paths we are specifying in the href will correspond to the paths where the ESP8266 will be programmed to return the corresponding code.
the <br> tag is just a simple line break between the hyperlinks.
One thing that is very important is that we are specifying the HTML code inside a string, and thus some details need to be taken in consideration.
First, in order to leave the code structured, we should split the declaration of the string in multiple lines. To do so, as explained here, we need to put the double quotes in each line so the compiler will know that it should be considered as a single string. So, the outermost quotes of the previous code are not from the HTML but from the declaration of a string in multiple lines.
Finally, every quote that is part of the HTML code (for example, the quotes around the URLs in the <a> tag) needs to be escaped with the \ character. So, the \ characters we see before the quotes are also not part of the HTML code but rather the escaping mechanism.
Those considerations will be the same for the rest of the code described bellow.
The Javascript Code
For the Javascript code we follow just the same approach of declaring it in a string, as seen bellow.
Important: WordPress doesn’t let me add a script block, probably due to security reasons. Please remove the REMOVE THIS bellow and just leave the <> and the script keyword inside.
const char * javascriptCode = ” <!DOCTYPE html> “
“<html> “
“<body> “
“<p>Click the button to get a message from the ESP8266:</p> “
“<button onclick=\”buttonFunction()\”>Message</button> “
“<REMOVE THIS script>”
“function buttonFunction() { “
” alert(\”Hello from the ESP8266!\”); “
“} “
“</script>”
“</body> “
“</html> “;
Since most of the tags were explained in the previous section, we will just focus on the new ones.
The <button> tag allows for the definition of a clickable button. One of its functionalities allows us to specify a function that is executed when the button is clicked (onclick event). In this case, we are assigning to that event the execution of a Javascript function called “buttonFunction”.
We then use the <script> tag that allows us to define Javascript code. In this case, it’s there that we specify the code of the mentioned buttonFunction. The code specified corresponds to an alert window that will output the “Hello from ESP8266” message.
The CSS code
Following the previously mentioned approach, we also declare the CSS as a string, as seen bellow.
const char * cssButton =”<!DOCTYPE html>”
“<html>”
“<head>”
“<style>”
“.button {“
“background-color: #990033;”
“border: none;”
“color: white;”
“padding: 7px 15px;”
“text-align: center;”
“cursor: pointer;”
“}”
“</style>”
“</head>”
“<body>”
“<input type=\”button\” class=\”button\” value=\”Input Button\”>”
“</body>”
“</html>”;
In this case, we have the <head> which specifies where the definitions of the header elements starts, pretty much as the <body> tag does for the body elements.
Then, we have the <style> element, which is where we specify how HTML elements should render in a browser [5]. In this case, we are specifying the style of a button by changing some of its default attributes, such as the background color or the type of cursor that appears when the mouse is over it. CSS allows for a lot of different customization that falls outside the scope of this post. You can check here for some example attributes to manipulate the appearance of a button.
Finally, we have the <input> tag, which specifies an input field where the user can enter data [6]. In this specific case, we defined that our input will be a button. This button will have the properties specified on the CSS of the header.
Just as a note, we didn’t associate any functionality to the button for the code to stay compact, so clicking on it will do nothing. The objective was just to demonstrate the difference of styling, in comparison to the button specified for the javascript section, which has the default styling.
The final code
The full Arduino code needed to start the server is shown bellow. Only the declaration of the strings that contain the HTML, Javascript and CSS code is omitted to maintain this post small. Don’t forget to declare them as global variables so they are accessible in the handling functions.
Note that the paths we defined for the CSS and Javascript code are the ones we specified in the URLs of the <a> tags we defined in the HTML code for the intro page. So, when the user clicks the hyperlinks, he will be redirected to existing paths and thus the ESP8266 will return the correct content.
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
ESP8266WebServer server(80); //Webserver Object
void setup() {
Serial.begin(115200); //Open Serial connection
WiFi.begin(“ssid”, “password”); //Connect to the WiFi network
while (WiFi.status() != WL_CONNECTED) { //Wait for connection
delay(500);
Serial.println(“Waiting to connect…”);
}
Serial.print(“IP address: “);
Serial.println(WiFi.localIP()); //Print the local IP
server.on(“/”, []() { //Define the handling function for root path (HTML message)
server.send(200, “text/html”, htmlMessage);
});
server.on(“/javascript”, []() { //Define the handling function for the javascript path
server.send(200, “text/html”, javascriptCode);
});
server.on(“/cssButton”, []() { //Define the handling function for the CSS path
server.send(200, “text/html”, cssButton);
});
server.begin(); //Start the server
Serial.println(“Server listening”);
}
void loop() {
server.handleClient(); //Handling of incoming requests
}
Important: When directly copying the code from the blog, a stray error may occur when trying to compile it on Arduino. In my case, this occurs because the editor assumes the wrong type of quotes. The easiest way to fix this, given the number of existing quotes, is to do a find and replace and put the correct quotes.
Running the code
To try the code, just upload it to the ESP8266 and after the “Server listening” message is sent to the serial port, just copy the IP printed before and access the server in a browser, on the following url, changing the {IP} for your IP:
http://{IP}/
You can see bellow the expected output in the serial console, with the IP to use. Note that the IP you get will most probably be different, depending on what your router as assigned to the ESP8266 when registering in the wireless network.
Figure 1 – Output of the serial console with the IP of the webserver.
So, when we access the URL in a browser (in my case, http://192.168.1.103/) we get to the HTML intro page, as seen bellow. Then, we can click in one of the hyperlinks to go to the page with Javascript or CSS.
Figure 2 – HTML intro page.
In figure 3, we can see the page that has the Javascript code. If we click the button, we get an alert box with the string we defined before.
Figure 3 – Page with Javascript alert box.
In the other page, we have the button styled with some CSS, as can be seen bellow.
Figure 4 – Page with button styled with CSS.
Final notes
As seen through this post, the ESP8266 offers all the tools to set a simple HTTP webserver and start serving some HTML, Javascript and CSS in a very easy way. Nevertheless, we need to take in consideration that we are working with a microcontroller with considerably limited resources.
Thus, we should not expect to implement a full website with lots of complex functionality and styling. On top of that, even for simpler examples as we have shown here, we should also not expect to be able to serve hundreds of requests per second.
Personally, I see this kind of functionality to implement simple configuration or debugging interface for devices. For example, if we implement a temperature server, we can create a simple webpage to configure how many measurements per second we will do, amongst other configurations, and serve that webpage on the ESP8266, removing any external dependencies. Naturally, this would be more suitable for technical users, since developing a good looking webpage for a end user of a commercial product wold need a lot of styling and functionality which, as we said, is not practical for this device.
Related posts
References
[2] https://www.techonthenet.com/html/elements/doctype_tag.php
[3] https://developer.mozilla.org/en-US/docs/Web/HTML/Element
[4] http://www.w3schools.com/tags/tag_body.asp
[5] http://www.w3schools.com/tags/tag_style.asp
[6] http://www.w3schools.com/tags/tag_input.asp
Technical details
ESP8266 libraries: v2.2.0
Hola buenas tardes,
estuve mirando este tutorial y me pareció buenísimo porque de hecho acabo de hacer una página web donde tengo por separado cada uno de los archivos pero me gustaria saber si puedo insertarlos como variables char* string, tal como el tutorial o hay otra manera que se pueda hacer con ‘client.println(“”)’.
Agradezco tu ayuda,
Sebastian Baquero
Hi!
I’ve not been using this library in a while, but if it is still working as before you should be able to. I’m using const * char just because the content is indeed constant and will not be changed.
Note however that this tutorial is for an older library of the ESP8266. Currently there is a better library which allow you to set up an asynchronous HTTP web server, which means you don’t need to be polling the server on the main loop function, like we do here.
https://techtutorialsx.com/2018/01/01/esp8266-arduino-asynchronous-http-web-server/
Best regards,
Nuno Santos
Hola buenas tardes,
estuve mirando este tutorial y me pareció buenísimo porque de hecho acabo de hacer una página web donde tengo por separado cada uno de los archivos pero me gustaria saber si puedo insertarlos como variables char* string, tal como el tutorial o hay otra manera que se pueda hacer con ‘client.println(“”)’.
Agradezco tu ayuda,
Sebastian Baquero
Hi!
I’ve not been using this library in a while, but if it is still working as before you should be able to. I’m using const * char just because the content is indeed constant and will not be changed.
Note however that this tutorial is for an older library of the ESP8266. Currently there is a better library which allow you to set up an asynchronous HTTP web server, which means you don’t need to be polling the server on the main loop function, like we do here.
https://techtutorialsx.com/2018/01/01/esp8266-arduino-asynchronous-http-web-server/
Best regards,
Nuno Santos
Hi Nuno .. thank you so much for your awesome tutorials. Well done ..you rock!
I wonder if you could please explain something I am battling with.
I have a web page containing a table with buttons to add or delete rows etc.
I would like to be able to read the table data (into an VAR/array or directly from a file in SPIFFS)
Do you know how to share the VAR/array so that I can access it from both the webpage (HTML/javascript/jquery) and the serial console (esp arduino side) ?
Are variable shared and accessible between the two ? For example if I have String WORDS=ABC; in my arduino code then will that data be accessible from the webpage (HTML side) ?
I would really appreciate if you cuold clarify this and maybye post an example of if you know of a URL somewhere as a reference ..I have been looking for a few weeks now to understand this.
Den
Hi!
Thank you very much for the feedback, I’m very happy to know you are finding the tutorials useful 🙂
For the ESP, the HTML code is nothing more than a simple string, so you cannot “share” a variable between the Arduino code and the HTML code.
What you can do, since for the ESP your html is just a string, is to build the html dynamically based on the values that you have for the table data in your ESP.
For instance, a very rough example. Imagine that you have a string in your arduino code that you want to return as a paragraph in your HTML code. You code do something like (pseudo code):
String myStr =” Awesome string to return to the client”;
String HTML = “<p>” + myStr + “</p>”
And then return the HTML string in your route handling function.
Note that this is feasible for simple stuff, but if you want to replace a lot of things in your HTML, the code can quickly become a mess.
So what many web frameworks have is what is called a template engine, which allow you to define your HTML dynamically without having to be building the strings piece by piece.
In the case of the ESP, the new HTTP async libraries have a template engine:
https://github.com/me-no-dev/ESPAsyncWebServer#template-processing
I’ve never tested it so I cannot confirm if it works well, but it is my recommendation to take a look if you want to implement a more scalable solution.
Hope this helps 🙂
Best regards,
Nuno Santos
Hi Nuno .. thank you so much for your awesome tutorials. Well done ..you rock!
I wonder if you could please explain something I am battling with.
I have a web page containing a table with buttons to add or delete rows etc.
I would like to be able to read the table data (into an VAR/array or directly from a file in SPIFFS)
Do you know how to share the VAR/array so that I can access it from both the webpage (HTML/javascript/jquery) and the serial console (esp arduino side) ?
Are variable shared and accessible between the two ? For example if I have String WORDS=ABC; in my arduino code then will that data be accessible from the webpage (HTML side) ?
I would really appreciate if you cuold clarify this and maybye post an example of if you know of a URL somewhere as a reference ..I have been looking for a few weeks now to understand this.
Den
Hi!
Thank you very much for the feedback, I’m very happy to know you are finding the tutorials useful 🙂
For the ESP, the HTML code is nothing more than a simple string, so you cannot “share” a variable between the Arduino code and the HTML code.
What you can do, since for the ESP your html is just a string, is to build the html dynamically based on the values that you have for the table data in your ESP.
For instance, a very rough example. Imagine that you have a string in your arduino code that you want to return as a paragraph in your HTML code. You code do something like (pseudo code):
String myStr =” Awesome string to return to the client”;
String HTML = “<p>” + myStr + “</p>”
And then return the HTML string in your route handling function.
Note that this is feasible for simple stuff, but if you want to replace a lot of things in your HTML, the code can quickly become a mess.
So what many web frameworks have is what is called a template engine, which allow you to define your HTML dynamically without having to be building the strings piece by piece.
In the case of the ESP, the new HTTP async libraries have a template engine:
https://github.com/me-no-dev/ESPAsyncWebServer#template-processing
I’ve never tested it so I cannot confirm if it works well, but it is my recommendation to take a look if you want to implement a more scalable solution.
Hope this helps 🙂
Best regards,
Nuno Santos
thank you for these tutorials you are a heaven send for anything esp8266webserver! Great explanations and examples. I really appreciate what you have done to help out the esp community,
Hi!
Thank you very much for the feedback, I’m very happy to know you are finding these tutorials useful 🙂
I will try to keep posting more content and hopefully bring more people to work with the ESP, these are really great microcontrollers 🙂
Best regards,
Nuno Santos
thank you for these tutorials you are a heaven send for anything esp8266webserver! Great explanations and examples. I really appreciate what you have done to help out the esp community,
Hi!
Thank you very much for the feedback, I’m very happy to know you are finding these tutorials useful 🙂
I will try to keep posting more content and hopefully bring more people to work with the ESP, these are really great microcontrollers 🙂
Best regards,
Nuno Santos
how can i include externel js files in esp32 without using cdn like jQuery.
CDN requires internet connection to fetch the contents.
Hi!
If you need to use external JS files without having an internet connection, you will need to serve them by the ESP32.
Depending on the size of the file, it may not be feasible due to resource constrains on the ESP32.
I’m guessing that jQuery may be a little bit to big to fit in the ESP32, but I’ve never looked into its size.
If it is a file small enough to fit in the ESP32, then you can create a route just to serve those JS file.
Hope this helps.
Best regards,
Nuno Santos
how can i include externel js files in esp32 without using cdn like jQuery.
CDN requires internet connection to fetch the contents.
Hi!
If you need to use external JS files without having an internet connection, you will need to serve them by the ESP32.
Depending on the size of the file, it may not be feasible due to resource constrains on the ESP32.
I’m guessing that jQuery may be a little bit to big to fit in the ESP32, but I’ve never looked into its size.
If it is a file small enough to fit in the ESP32, then you can create a route just to serve those JS file.
Hope this helps.
Best regards,
Nuno Santos
Hi, can someone post the full code or a downloadlink because i am to dumb to create the full code.
Hi,
Having the same issue. Got the code to compile but I get a “Not found: /” error message… I’ll post the whole code if I can figure out what I’m missing here 🙂
please delete all my posts, to make eat easier… thanks.
Hi!
Thanks for trying to share the code 🙂
I’m not sure if comments allow to add code blocks, due to security reasons.
At the time I’ve written this post (it was a long time ago 🙂 ) I wasn’t aware of the existence of the code tags, which is why the code was just pasted as normal text.
In new posts I’m now making use of code tags.
As for the older posts, I’m trying to update the more problematic ones (such as this) to use code tags.
But unfortunately I have very few time for blogging and thus I’m taking more time to get back to the older stuff :/
Sorry for the troubles, I’ll put this one on the top of my list.
Best regards,
Nuno Santos
Hi, can someone post the full code or a downloadlink because i am to dumb to create the full code.
Hi,
Having the same issue. Got the code to compile but I get a “Not found: /” error message… I’ll post the whole code if I can figure out what I’m missing here 🙂
please delete all my posts, to make eat easier… thanks.
Hi!
Thanks for trying to share the code 🙂
I’m not sure if comments allow to add code blocks, due to security reasons.
At the time I’ve written this post (it was a long time ago 🙂 ) I wasn’t aware of the existence of the code tags, which is why the code was just pasted as normal text.
In new posts I’m now making use of code tags.
As for the older posts, I’m trying to update the more problematic ones (such as this) to use code tags.
But unfortunately I have very few time for blogging and thus I’m taking more time to get back to the older stuff :/
Sorry for the troubles, I’ll put this one on the top of my list.
Best regards,
Nuno Santos