Home / Tutorials / ESP8266 Tutorial / NodeMCU Ajax: Dynamic Sensor Data on Web Page
pcbway
nodemcu ajax dynamic sensor data

NodeMCU Ajax: Dynamic Sensor Data on Web Page

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.

 

Check Also

mini-submersible-water-pump-controlled-by-wemos-d1-mini

Controlling a Water Pump with WeMos D1 Mini

I recently bought a mini Arduino water pump that runs on 3 to 6 V. …

30 comments

  1. Great tutorial!

    My NodeMCU crashes though after 30 seconds with this error:

    Exception (29):
    epc1=0x4020dc0c epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

    ctx: sys
    sp: 3ffffcd0 end: 3fffffb0 offset: 01a0

    ets Jan 8 2013,rst cause:2, boot mode:(1,6)

    ets Jan 8 2013,rst cause:4, boot mode:(1,6)

    wdt reset

    Any ideas how to fix this?

  2. Hi,

    In this tuttorial you put sensor data into text file, where u put the text file? SD card (perhaps)?

    • Hi Sanz,

      There was no SD card. The text file is dynamically created on the NodeMCU server. Like, the file was created when the NodeMCU server was running. When you stop the server, that text file will vanish also.

  3. C Satish kumar

    hlo,
    i have run the code which u have mentioned in the tutorial above,but i m getting the error “stray ‘\302’ in program” so can u tell how to resolve it.do i need to do changes in it???

    • Hi,

      The code compiles on mine with no error. I think there is a stray character on the code you pasted. Try pressing the “toggle plain code” on the upper right of the code above and copy-paste that to your IDE.

  4. Hi,

    Fantastic tuttorial but i found some problem when i try to read 3 sensor using ajax method for my final project.Can you help me with my problem read 3 sensor using ajax method?

    Thank You

    • Hi,

      You can change my example so that the variable “data” is a string that contains three sensor readings. For example,

      data = “Temperature: ” + (String)temp_c + ” ℃Humidity: ” + (String)humidity + ” %Pressure: ” + (String)pressure + ” Pa”;

      Here, temperature, humidity and pressure is displayed. Again, change the data variable in my original code from double to string and also remove the (String) modifier in line 33.

      Feel free to ask me questions if there’s something you don’t understand. Good luck!

      • Hi,

        I try change your example according to your explanation, but I got this error:

        invalid operands of types ‘const char [14]’ and ‘const char [14]’ to binary ‘operator+’

        For this:

        data = “Air Quality: ” + (String)T+ “Temperature: ” + (String)T + “Ax: ” + (String)Ax + “Ay: ” + (String)Ay + “Az: ” + (String)Az + “Gx: ” + (String)Gx +”Gy: ” + (String)Gy +”Gz: ” + (String)Gz +;

        I use MQ2 gas sensor and MPU6050 which can detect temperature, acceleration and rotational movement (gyro meter).
        Can you help me to solve this problem?

        Thank you.

      • Hi,

        i changed the code for 3 sensors and its working. The issue i have is: The Sensor values are displayed in one row. I have no idea how to get a carriage return in HTML to have each sensor value in a single row. Can you help?

  5. hey nice tutorial it worked. But can you tell me how can i decrease the time of update of data on server.

    • Hi,

      You can change the time interval in the setInterval() JS function. In line 39 of my sketch, change 1000 (in milliseconds) to whichever value that suits you.

  6. Hi,
    very great serie of tutorials ; every sketchs are running without porblem ! many thanks for all of theses, they are very helpfull for my project
    My next problem will be to integer a picture on the web page ..

  7. Hi! Thanks for the tutorial.
    I’m trying to do similar, but for show “Voltage” and “Current”.
    The problem is that Voltage and Current values I get from SPI communication with Arduino inside of
    void loop(void){} function.

    How can I get this values and show?

  8. How it can do for 2 analog sensors

  9. How can we do for two analog sensors , provided it has only one analog pin ..? Please help .

  10. how to do if 2 or more analog sensor? thanks..

  11. Hii I have been trying this code but I got this error.

    Arduino: 1.8.8 (Windows 10), Board: “NodeMCU 1.0 (ESP-12E Module), 80 MHz, Flash, Disabled, 4M (no SPIFFS), v2 Lower Memory, Disabled, None, Only Sketch, 115200”

    nodemcu_server:8:1: error: stray ‘\302’ in program

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

    ^

    nodemcu_server:8:1: error: stray ‘\240’ in program

    nodemcu_server:8:1: error: stray ‘\302’ in program

    nodemcu_server:8:1: error: stray ‘\240’ in program

    nodemcu_server:15:1: error: stray ‘\302’ in program

     pinMode(A0, INPUT);

    ^

    nodemcu_server:15:1: error: stray ‘\240’ in program

    nodemcu_server:16:1: error: stray ‘\302’ in program

     delay(1000);

    ^

    nodemcu_server:16:1: error: stray ‘\240’ in program

    nodemcu_server:17:1: error: stray ‘\302’ in program

     Serial.begin(115200);

    ^

    nodemcu_server:17:1: error: stray ‘\240’ in program

    nodemcu_server:18:1: error: stray ‘\302’ in program

     WiFi.begin(ssid, password); //begin WiFi connection

    ^

    nodemcu_server:18:1: error: stray ‘\240’ in program

    nodemcu_server:19:1: error: stray ‘\302’ in program

     Serial.println(“”);

    ^

    nodemcu_server:19:1: error: stray ‘\240’ in program

    nodemcu_server:21:1: error: stray ‘\302’ in program

     // Wait for connection

    ^

    nodemcu_server:21:1: error: stray ‘\240’ in program

    nodemcu_server:22:1: error: stray ‘\302’ in program

     while (WiFi.status() != WL_CONNECTED) {

    ^

    nodemcu_server:22:1: error: stray ‘\240’ in program

    nodemcu_server:23:1: error: stray ‘\302’ in program

     delay(500);

    ^

    nodemcu_server:23:1: error: stray ‘\240’ in program

    nodemcu_server:24:1: error: stray ‘\302’ in program

     Serial.print(“.”);

    ^

    nodemcu_server:24:1: error: stray ‘\240’ in program

    nodemcu_server:27:1: error: stray ‘\302’ in program

     Serial.println(“”);

    ^

    nodemcu_server:27:1: error: stray ‘\240’ in program

    nodemcu_server:28:1: error: stray ‘\302’ in program

     Serial.print(“Connected to “);

    ^

    nodemcu_server:28:1: error: stray ‘\240’ in program

    nodemcu_server:29:1: error: stray ‘\302’ in program

     Serial.println(ssid);

    ^

    nodemcu_server:29:1: error: stray ‘\240’ in program

    nodemcu_server:30:1: error: stray ‘\302’ in program

     Serial.print(“IP address: “);

    ^

    nodemcu_server:30:1: error: stray ‘\240’ in program

    nodemcu_server:31:1: error: stray ‘\302’ in program

     Serial.println(WiFi.localIP());

    ^

    nodemcu_server:31:1: error: stray ‘\240’ in program

    nodemcu_server:32:1: error: stray ‘\302’ in program

     server.on(“/data.txt”, [](){

    ^

    nodemcu_server:32:1: error: stray ‘\240’ in program

    nodemcu_server:33:1: error: stray ‘\302’ in program

      text = (String)data;

    ^

    nodemcu_server:33:1: error: stray ‘\240’ in program

    nodemcu_server:34:1: error: stray ‘\302’ in program

       server.send(200, “text/html”, text);

    ^

    nodemcu_server:34:1: error: stray ‘\240’ in program

    nodemcu_server:34:1: error: stray ‘\302’ in program

    nodemcu_server:34:1: error: stray ‘\240’ in program

    nodemcu_server:34:1: error: stray ‘\302’ in program

    nodemcu_server:34:1: error: stray ‘\240’ in program

    nodemcu_server:35:1: error: stray ‘\302’ in program

     });

    ^

    nodemcu_server:35:1: error: stray ‘\240’ in program

    nodemcu_server:36:1: error: stray ‘\302’ in program

     server.on(“/”, [](){

    ^

    nodemcu_server:36:1: error: stray ‘\240’ in program

    nodemcu_server:54:2: error: stray ‘\302’ in program

      server.send(200, “text/html”, page);

    ^

    nodemcu_server:54:2: error: stray ‘\240’ in program

    nodemcu_server:54:2: error: stray ‘\302’ in program

    nodemcu_server:54:2: error: stray ‘\240’ in program

    nodemcu_server:57:1: error: stray ‘\302’ in program

     server.begin();

    ^

    nodemcu_server:57:1: error: stray ‘\240’ in program

    nodemcu_server:58:1: error: stray ‘\302’ in program

     Serial.println(“Web server started!”);

    ^

    nodemcu_server:58:1: error: stray ‘\240’ in program

    nodemcu_server:62:1: error: stray ‘\302’ in program

     data = analogRead(A0);

    ^

    nodemcu_server:62:1: error: stray ‘\240’ in program

    nodemcu_server:63:1: error: stray ‘\302’ in program

     delay(1000);

    ^

    nodemcu_server:63:1: error: stray ‘\240’ in program

    nodemcu_server:64:1: error: stray ‘\302’ in program

     server.handleClient();

    ^

    nodemcu_server:64:1: error: stray ‘\240’ in program

    exit status 1
    stray ‘\302’ in program

    I tried toggling line code but I still got the same error.

    Can You please help me fix this.

    Thank you.

    • Hi,

      It looks like a formatting concern. Have you tried toggling to plain code? Click the “<>” on the upper right.

  12. Gibran Berriel

    Es posible graficar los resultados directamente desde el nodemcu?
    Is it possible to graph the results directly from the nodemcu?

  13. Thanks for this project. How is it possible to add an input field? I would like to be able to adjust the threshold value for my ‘Smoke Alarm’ project for my wife. Is there project that shows how to add an interger field?

  14. server.on(“/”, [](){
    page = “Sensor to Node MCU Web ServerData: “”\r\n”;
    page += “\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 += “\r\n”;
    server.send(200, “text/html”, page);
    });

    In this function i want to put id value in array format is there possible or not.
    if possible then how to write a statment
    page = “Sensor to Node MCU Web ServerData: “”\r\n”;

Leave a Reply

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

Contents

Index