ESP8266 HTTP server: Serving HTML, Javascript and CSS

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.

esp8266-print-webserver-ip

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.

esp8266-serve-html

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.

esp8266-javascript

Figure 3 – Page with Javascript alert box.

In the other page, we have the button styled with some CSS, as can be seen bellow.

esp8266-css

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

[1] http://programmers.stackexchange.com/questions/171203/what-are-the-differences-between-server-side-and-client-side-programming

[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

85 thoughts on “ESP8266 HTTP server: Serving HTML, Javascript and CSS”

  1. Could you please help me i’m using ESP8266 wemos d1 > works with Arduino ide i have made an html page to show some sensor values but i want to show external link to my own blog it shows the highlighted link but when clicked it adds that request after the ip or ESP itself and if clicked multiple times it adds the request multiple times e.g. 10.0.0.36/LinkThat I Want it to refer to .com i’m a noob please help

    1. ok i figured it out . its not an issue with Esp itself or ide it happens with html if we don’t use https:// or http:// it thinks that the link is internal and thats why it adds it after the ip of esp

  2. Could you please help me i’m using ESP8266 wemos d1 > works with Arduino ide i have made an html page to show some sensor values but i want to show external link to my own blog it shows the highlighted link but when clicked it adds that request after the ip or ESP itself and if clicked multiple times it adds the request multiple times e.g. 10.0.0.36/LinkThat I Want it to refer to .com i’m a noob please help

    1. ok i figured it out . its not an issue with Esp itself or ide it happens with html if we don’t use https:// or http:// it thinks that the link is internal and thats why it adds it after the ip of esp

  3. Hi! You’re welcome 🙂

    I’m trying to refactor some of my older posts because at the time I wasn’t using the awesome source code tags of wordpress (for reference I will leave the link below) and thus the quotes were getting messed.

    So most likely you were running in a “stray error” or something similar when compiling the code right?

    I will try to change it as soon as I have some spare time, but this one will be a tough one because wordpress unformat all the code as soon as I re-edit the post 🙁 .

    https://en.support.wordpress.com/code/posting-source-code/

    Best regards,
    Nuno Santos

  4. Hi! You’re welcome 🙂
    I’m trying to refactor some of my older posts because at the time I wasn’t using the awesome source code tags of wordpress (for reference I will leave the link below) and thus the quotes were getting messed.
    So most likely you were running in a “stray error” or something similar when compiling the code right?
    I will try to change it as soon as I have some spare time, but this one will be a tough one because wordpress unformat all the code as soon as I re-edit the post 🙁 .
    https://en.support.wordpress.com/code/posting-source-code/
    Best regards,
    Nuno Santos

    1. Hi!

      Thanks for the feedback 🙂

      I haven’t yet tested that, but one simple way may be reading from the serial connection and putting the data in a global string variable and use it on the route that is serving the HTML.

      Naturally this is a very simplified way of doing it since it pretty much depends on what you want to achieve.

      For instance, if you are are going to receive the whole HTML from serial, then you can store it in a string and directly serve it.

      If you are going to receive for example numeric data only from serial and serve it in your route with some HTML to present it in a nice format, then you may store that numeric data in an array and then dynamically build the final HTML page on the route.

      Best regards,
      Nuno Santos

    1. Hi!
      Thanks for the feedback 🙂
      I haven’t yet tested that, but one simple way may be reading from the serial connection and putting the data in a global string variable and use it on the route that is serving the HTML.
      Naturally this is a very simplified way of doing it since it pretty much depends on what you want to achieve.
      For instance, if you are are going to receive the whole HTML from serial, then you can store it in a string and directly serve it.
      If you are going to receive for example numeric data only from serial and serve it in your route with some HTML to present it in a nice format, then you may store that numeric data in an array and then dynamically build the final HTML page on the route.
      Best regards,
      Nuno Santos

  5. Nuno,

    Great document, it has been my guide!

    My esp8266 sketch sets up as an ap server. It monitors temp from a max6675 probe. The iPhone client connects to the server and I send the temp via html to the web client phone.

    I want to update my sketch to allow the client to enter a temperature alarm threshold. When the temp exceeds the threshold I want the esp8266 to store a small mp3 file in spiff and play it as an alarm to the iPhone browser client. I don’t see any audio examples of how to store audio files or play them. Can you help me?

    Jim

    1. Hi Jim,

      Thank you very much for your feedback 🙂

      It seems a very interesting project that you are doing! Also challenging due to all the parts involved.

      Unfortunately I’ve never worked with audio on the ESP, I cannot be of much help.

      I’ve found this library though that may help getting you started:
      https://github.com/earlephilhower/ESP8266Audio

      Most likely you will have to adapt a lot of stuff for your application, but from the description it seems to be using SPIFFS to store the audio files.

      Note however that the ESP8266 has some resources limitation, I’m not sure if it will handle all the load of having the server plus the audio.

      If you run into resources limitation, maybe a good option is to move to the ESP32, which has plenty of power 🙂

      Let us know if you succeed, I’ve never played with audio but I’m interested in knowing if it is feasible on the ESPs.

      Best regards,
      Nuno Santos

  6. Nuno,
    Great document, it has been my guide!
    My esp8266 sketch sets up as an ap server. It monitors temp from a max6675 probe. The iPhone client connects to the server and I send the temp via html to the web client phone.
    I want to update my sketch to allow the client to enter a temperature alarm threshold. When the temp exceeds the threshold I want the esp8266 to store a small mp3 file in spiff and play it as an alarm to the iPhone browser client. I don’t see any audio examples of how to store audio files or play them. Can you help me?
    Jim

    1. Hi Jim,
      Thank you very much for your feedback 🙂
      It seems a very interesting project that you are doing! Also challenging due to all the parts involved.
      Unfortunately I’ve never worked with audio on the ESP, I cannot be of much help.
      I’ve found this library though that may help getting you started:
      https://github.com/earlephilhower/ESP8266Audio
      Most likely you will have to adapt a lot of stuff for your application, but from the description it seems to be using SPIFFS to store the audio files.
      Note however that the ESP8266 has some resources limitation, I’m not sure if it will handle all the load of having the server plus the audio.
      If you run into resources limitation, maybe a good option is to move to the ESP32, which has plenty of power 🙂
      Let us know if you succeed, I’ve never played with audio but I’m interested in knowing if it is feasible on the ESPs.
      Best regards,
      Nuno Santos

Leave a Reply

Discover more from techtutorialsx

Subscribe now to keep reading and get access to the full archive.

Continue reading