NodeMCU Ajax: Dynamic Sensor Data on Web Page

nodemcu ajax dynamic sensor data

Last time we managed to display sensor data to a NodeMCU web server. The problem with that code is that we need to refresh the page manually in order to update the sensor value. A better method is to use Ajax (asynchronous javascript and XML) so that we can request data from the ESP8266 server in the background with no page reloads.

Ajax is a combination of an XMLHttpRequest object and JavaScript. The XMLHttpRequest object performs the request on the server while the javascript DOM object updates the element on the web page. Besides updating page elements without reload, ajax also makes it possible to a) request data from a server - after the page has loaded; b) receive data from a server - after the page has loaded and c) send data to a server - in the background. W3Schools has a great tutorial on Ajax.

We shall now edit the sketch from last time to include the Ajax script. We will be using the same schematic:

nodemcu ajax sensor

Here is the Ajax script that we’ll be using:

function loadData(url, callback){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function(){
 if(this.readyState == 4 && this.status == 200){
 callback.apply(xhttp);
 }
};
xhttp.open("GET", url, true);
xhttp.send();
}
function updateData(){
 document.getElementById("data").innerHTML = this.responseText;
}

The main Ajax script is the loadData() function. Inside this function, an XMLHttpRequest() object is created. The server waits for a readystate of 4 (done) and a http status of 200 (OK) before the web page element is updated via callback to updateData(). The request is then initiated via the open() and send() functions. Callback was necessary here to make the requests asynchronous, i.e., make the page still responsive even if there is a pending request.

In order for this function to be repeatedly called, we will be using the javascript setInterval() function. Here the loadData() function is called every second.

There are a couple of ways to get data from the sensor. What I did was save the data to a text file. This text file will then be read by the XMLHttpRequest object and then display its contents to the page element.

Full Code

#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 = "";
String text = "";
double data;

void setup(void){
 pinMode(A0, INPUT);
 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("/data.txt", [](){
   text = (String)data;
   server.send(200, "text/html", text);
 });
 server.on("/", [](){
   page = "<h1>Sensor to Node MCU Web Server</h1><h1>Data:</h1> <h1 id=\"data\">""</h1>\r\n";
   page += "<script>\r\n";
   page += "var x = setInterval(function() {loadData(\"data.txt\",updateData)}, 1000);\r\n";
   page += "function loadData(url, callback){\r\n";
   page += "var xhttp = new XMLHttpRequest();\r\n";
   page += "xhttp.onreadystatechange = function(){\r\n";
   page += " if(this.readyState == 4 && this.status == 200){\r\n";
   page += " callback.apply(xhttp);\r\n";
   page += " }\r\n";
   page += "};\r\n";
   page += "xhttp.open(\"GET\", url, true);\r\n";
   page += "xhttp.send();\r\n";
   page += "}\r\n";
   page += "function updateData(){\r\n";
   page += " document.getElementById(\"data\").innerHTML = this.responseText;\r\n";
   page += "}\r\n";
   page += "</script>\r\n";
   server.send(200, "text/html", page);
});

 server.begin();
 Serial.println("Web server started!");
}

void loop(void){
 data = analogRead(A0);
 delay(1000);
 server.handleClient();
}

Video:


 

You can also add CSS to make the web page look nicer. If you want to record the sensor readings, you can send NodeMCU data to Google sheets or save it to a database.

 

Leave a Reply

Your email address will not be published. Required fields are marked *