Creating a Simple NodeMCU Web Server

nodemcu-webserver

We're done with basics of the NodeMCU in my last post. Now it's time to use the NodeMCU like how it's meant to be: an IoT device. Here I will show you how to create a simple NodeMCU web server which will control a LED attached to one of the NodeMCU's pins. Sounds interesting? Read on!

Video Tutorial

NodeMCU Web Server Sketch

For this to work, you must have already installed the ESP8266 board development toolkit as shown in my last tutorial. Also, you must wire a LED to D7 on your NodeMCU as shown:

NodeMCU Web Server LED control

Obviously, the NodeMCU must have power for it to work. You can use a microUSB cable to your computer for this.

Here's the code for our simple nodemcu web server:

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

// Replace with your network credentials
const char* ssid = "<YOUR WIFI SSID>";
const char* password = "<YOUR WIFI PASSWORD>";

ESP8266WebServer server(80);   //instantiate server at port 80 (http port)

String page = "";
int LEDPin = 13;
void setup(void){
  //the HTML of the web page
  page = "<h1>Simple NodeMCU Web Server</h1><p><a href=\"LEDOn\"><button>ON</button></a>&nbsp;<a href=\"LEDOff\"><button>OFF</button></a></p>";
  //make the LED pin output and initially turned off
  pinMode(LEDPin, OUTPUT);
  digitalWrite(LEDPin, LOW);
   
  delay(1000);
  Serial.begin(115200);
  WiFi.begin(ssid, password); //begin WiFi connection
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
   
  server.on("/", [](){
    server.send(200, "text/html", page);
  });
  server.on("/LEDOn", [](){
    server.send(200, "text/html", page);
    digitalWrite(LEDPin, HIGH);
    delay(1000);
  });
  server.on("/LEDOff", [](){
    server.send(200, "text/html", page);
    digitalWrite(LEDPin, LOW);
    delay(1000); 
  });
  server.begin();
  Serial.println("Web server started!");
}
 
void loop(void){
  server.handleClient();
}

Explaining the Sketch

Preliminaries

Because we are now using the Arduino platform to write a code for the NodeMCU, we can now use the basic Arduino functions.

Notice that I used three headers on the top.

#include <ESP8266WiFi.h> 
#include <WiFiClient.h> 
#include <ESP8266WebServer.h>

These libraries are already installed after adding the ESP8266 toolkit via the board manager.

Then, we specify the WiFi ssid and password:

// Replace with your network credentials 
const char* ssid = "<YOUR WIFI SSID>";
const char* password = "<YOUR WIFI PASSWORD>";

Obviously, you need to give your network's own ssid and password.

Then we create a ESP8266WebServer object:

ESP8266WebServer server(80); //instantiate server at port 80 (http port)

80 is the common port number used in HTTP communication. Since the Internet mostly uses this port, we don't need to change this to other number except if we choose to use HTTPS (which uses port 443).

[the_ad id="3059"]

Next we declare an empty string called page and the pin where the LED is attached:

String page = ""; 
int LEDPin = 13;

Here we use 13 to mean GPIO13. This is D7 on the NodeMCU board. For more details on the pinouts of the NodeMCU, see our pinout reference.

Setting Up the Web Page

Inside setup(), we create a simple HTML code and place this as a string to page.

//the HTML of the web page 
page = "<h1>Simple NodeMCU Web Server</h1><p><a href=\"LEDOn\"><button>ON</button></a>&nbsp;<a href=\"LEDOff\"><button>OFF</button></a></p>"; //make the LED pin output and initially turned off

This will give us a simple web page with two buttons. Now this is not that good looking but I think it's enough for our purpose here. If you are looking to create a much more good looking website, I suggest you use a microSD card module or SPIFFS to house your images, or CSS and Javascript files.

We then initialize the LED pin as an output pin and make it low:

//make the LED pin output and initially turned off 
pinMode(LEDPin, OUTPUT);
digitalWrite(LEDPin, LOW);

Next, we wait for a second and then initialize the serial output.

delay(1000);
Serial.begin(115200);

We need this so that we can have some feedback on the serial monitor as to what is now going on. You can change the baud rate to any other rate that you like.

Then we start the WiFi connection, wait, and then display the SSID and the IP address of the NodeMCU on the serial monitor. You should see something like this:

nodemcu web server 1

This means you are successfully connected to the WiFi network! You can also see the IP address assigned to the NodeMCU (192.168.1.7 in this example).

Turning On the Web Server

Now we want the NodeMCU to react everytime someone visits that IP address. When you open  your preferred web browser and type that IP address on the address bar, you will see something like this:

nodemcu web server 2

This is thanks to this line of code:

server.on("/", [](){
  server.send(200, "text/html", page); 
});

The "/" means this is the home page of the server. When a user visits this IP address, the server uses the send() function to reply with "200" which is the HTTP status code for "OK". Then, it specifies the object that the browser is about to see (a text or html file) and then the HTML code (which is inside the string page).

Click the "On" button and watch as your LED turns on.This is made possible through this line:

server.on("/LEDOn", [](){ 
  server.send(200, "text/html", page); 
  digitalWrite(LEDPin, HIGH); 
  delay(1000); 
});

If you look back at the HTML code inside page, the "On" button has a hyperlink to "<ip address>/LEDOn". So what the code above does is serve the browser the web page /LEDOn which is in fact the same as the home page since page is still the one specified inside send(). The only difference is that within the server.on() function, we have this:

digitalWrite(LEDPin, HIGH);

This code turns on the LED.

Click the "Off" button to turn it off. The same process happens as with the turning on the LED. We only now use

digitalWrite(LEDPin, LOW);

We also need to remember that the server doesn't start unless we specify this line:

server.begin();

Finally, we need the server to keep listening to incoming clients (web browsers). Thus, we place this inside loop():

server.handleClient();

Troubleshooting

This code has been tested many times without a problem encountered. If you've experienced errors that are displayed on the serial monitor, especially when the exception code is shown, I suggest you use the Exception Decoder.

Easy! Next, you can display data coming from a sensor to a webpage or use WebSockets instead of HTTP!