In this tutorial you will learn how to plot sensor data from ESP8266 to web page. It requires when you are doing a IoT project where sensor data play important role in analytic or you want to monitoring sensor data graphically. If you know this how to plot, it will help in understanding what exactly going on in your project. Therefore, I am plotting a sensor data i.e DHT22 sensor data to web page. It will update temperature & humidity in every one second automatically . You don’t need to refresh the web page. If you want you can change the update time. So let’s get started.

Components Required:
  1. NodeMCU ESP8266 12E,
  2. DHT22 sensor,
  3. 10K ohms Resistor,
  4. Breadboard,
  5. Jumper Wire.
Libraries Required:
  1. DHT22 Library,
  2. Adafruit Sensor, (If you haven’t installed yet)
  3. ESPAsyncWebServer,
  4. ESPAsyncTCP.

How to add library in Arduino IDE.

Make sure you already setup ESP8266 for Arduino IDE. If you didn’t setup yet. You can read How to setup ESP8266 for first time in Arduino IDE.

Also make sure before uploading code, insert your wifi network name and password.

const char* ssid = "Your_SSID";
const char* password = "Your_Password";
Circuit Diagram for ESP8266 Live Sensor Data Plotter:

ESP8266 Weather Station

Code for ESP8266 Live Sensor Data Plotter:
#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>
#include "DHT.h"
#include <ESPAsyncTCP.h>


// Replace with your network credentials
const char* ssid = "Your_SSID";
const char* password = "Your_Password";

#define DHTPIN 4 // Digital pin 2 (GPIO 4) connected to the DHT sensor

// Uncomment the type of sensor in use:
//#define DHTTYPE DHT11 // DHT 11
#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)

DHT dht(DHTPIN, DHTTYPE);

// current temperature & humidity, this will be updated in loop function
float t = 0.0;
float tf = 0.0;
float h = 0.0;

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

unsigned long previousMillis = 0; //stoe last time DHT was updated
const long interval = 1000; // Updates DHT readings every 1 seconds

//web page
const char index_html[] PROGMEM = R"webpage(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://code.highcharts.com/8.0/highcharts.js"></script>
<style>
body {
min-width: 300px;
max-width: 800px;
height: 400px;
margin: 0 auto;
}
h2 {
font-family: Arial;
font-size: 2.5rem;
text-align: center;
}
</style>
</head>
<body>
<h2>ESP8266 Weather Station Chart</h2>
<div id="temperature-chart" class="container"></div>
<div id="fahrenheit-chart" class="container"></div>
<div id="humidity-chart" class="container"></div>
</body>
<script>
var chartT = new Highcharts.Chart({
chart:{ renderTo : 'temperature-chart' },
title: { text: 'Temperature in Degree Celsius' },
series: [{
showInLegend: false,
data: []
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: true }
},
series: { color: '#059e8a' }
},
xAxis: { type: 'datetime',
dateTimeLabelFormats: { second: '%H:%M:%S' }
},
yAxis: {
title: { text: 'Temperature (Celsius)' }
},
credits: { enabled: false }
});
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var x = (new Date()).getTime(),
y = parseFloat(this.responseText);
if(chartT.series[0].data.length > 50) {
chartT.series[0].addPoint([x, y], true, true, true);
} else {
chartT.series[0].addPoint([x, y], true, false, true);
}
}
};
xhttp.open("GET", "/temperature", true);
xhttp.send();
}, 1000 ) ;

var chartF = new Highcharts.Chart({
chart:{ renderTo:'fahrenheit-chart' },
title: { text: 'Temperature in Fahrenheit' },
series: [{
showInLegend: false,
data: []
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: true }
}
},
xAxis: {
type: 'datetime',
dateTimeLabelFormats: { second: '%H:%M:%S' }
},
yAxis: {
title: { text: 'fahrenheit (F)' }
},
credits: { enabled: false }
});
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var x = (new Date()).getTime(),
y = parseFloat(this.responseText);
//console.log(this.responseText);
if(chartF.series[0].data.length > 50) {
chartF.series[0].addPoint([x, y], true, true, true);
} else {
chartF.series[0].addPoint([x, y], true, false, true);
}
}
};
xhttp.open("GET", "/fahrenheit", true);
xhttp.send();
}, 1000 ) ;

var chartH = new Highcharts.Chart({
chart:{ renderTo:'humidity-chart' },
title: { text: 'Humidity (%)' },
series: [{
showInLegend: false,
data: []
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: true }
},
series: { color: '#18009c' }
},
xAxis: {
type: 'datetime',
dateTimeLabelFormats: { second: '%H:%M:%S' }
},
yAxis: {
title: { text: 'Humidity (%)' }
},
credits: { enabled: false }
});
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var x = (new Date()).getTime(),
y = parseFloat(this.responseText);
//console.log(this.responseText);
if(chartH.series[0].data.length > 50) {
chartH.series[0].addPoint([x, y], true, true, true);
} else {
chartH.series[0].addPoint([x, y], true, false, true);
}
}
};
xhttp.open("GET", "/humidity", true);
xhttp.send();
}, 1000 ) ;
</script>
</html>)webpage";

void setup(){
// Serial port for debugging purposes
Serial.begin(115200);


// Connect to Wi-Fi
WiFi.begin(ssid, password);
Serial.println("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println(".");
}

// Print ESP32 Local IP Address
Serial.println(WiFi.localIP());

// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html);
});
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(t).c_str());
});
server.on("/fahrenheit", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(tf).c_str());
});
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(h).c_str());
});

// Start server
server.begin();
dht.begin();
}

void loop(){ 
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you updated the DHT values
previousMillis = currentMillis;
// Read temperature as Celsius (the default)
float currentT = dht.readTemperature();

// if temperature read failed, we don't want to change t value
if (isnan(currentT)) {
Serial.println("Failed to read from DHT sensor!");
Serial.println(currentT);
}
else {
t = currentT;
Serial.println(t);
}
// Read temperature as Fahrenheit 
float currentTf = dht.readTemperature(true);
// if temperature read failed, we don't want to change tf value
if (isnan(currentTf)) {
Serial.println("Failed to read from DHT sensor!");
}
else {
tf = currentTf;
Serial.println(tf);
}


// Read Humidity
float currentH = dht.readHumidity();
// if humidity read failed, we don't want to change h value 
if (isnan(currentH)) {
Serial.println("Failed to read from DHT sensor!");
}
else {
h = currentH;
Serial.println(h);
}
}
}
Code Explanation:

Import required library.

#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>
#include "DHT.h"
#include <ESPAsyncTCP.h>

Modify this with your network credential.

const char* ssid = "Your_SSID";
const char* password = "Your_Password";

DHT pin connected to GPIO 4 (D2).

#define DHTPIN 4

Uncomment DHT TYPE you are using and comment out rest of type.

//#define DHTTYPE DHT11 // DHT 11
#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)

Creating float variable it will store temperature in degree Celsius and temperature in Fahrenheit and humidity. Which will be updated in loop().

float t = 0.0;
float tf = 0.0;
float h = 0.0;

Create AsyncWebServer object on port 80.

AsyncWebServer server(80);

We are updating DHT22 sensor reading every one second. If you want you can change this to any number of seconds.

unsigned long previousMillis = 0; // will store last time DHT was updated
const long interval = 1000; // Updates DHT readings every 1 seconds
Web Page:

<meta> tag will make your web page responsive to any web browser.

<meta name="viewport" content="width=device-width, initial-scale=1">

First of all, we need to include highcharts library to display chart.

<script src="https://code.highcharts.com/8.0/highcharts.js"></script>

We have to also create <div> section for each chart with unique id. Here in case, temperature-chart, fahrenheit-chart, humidity-chart.

<div id="temperature-chart" class="container"></div>
<div id="fahrenheit-chart" class="container"></div>
<div id="humidity-chart" class="container"></div>
Style:

Here you can style the web page by chart size, font, font size etc. here we have given minimum width for chart is 300px (mostly used for mobile) and maximum width 800px (for computer). Chart height is 400px.

<style>
body {
min-width: 300px;
max-width: 800px;
height: 400px;
margin: 0 auto;
}
h2 {
font-family: Arial;
font-size: 2.5rem;
text-align: center;
}
</style>
Update chart Automatically:

Here we are using some JavaScript for updating chart automatically in every one second. You can change this time to any number, I have just used this for demonstration.

This is temperature chart. You can set chart title, axis labels etc. Similarly it is done for other chart.

var chartT = new Highcharts.Chart({
chart:{ renderTo : 'temperature-chart' },
title: { text: 'Temperature in Degree Celsius' },
series: [{
showInLegend: false,
data: []
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: true }
},
series: { color: '#059e8a' }
},
xAxis: { type: 'datetime',
dateTimeLabelFormats: { second: '%H:%M:%S' }
},
yAxis: {
title: { text: 'Temperature (Celsius)' }
},
credits: { enabled: false }
});

SetInterval function adding a point in every one second. It means our chart updated in every one second. You can change the time to any number. For changing time you just need to change last line i.e 1000, it is in millisecond. It will add 50 points on the chart, as a result you can see, last 50 points on the chart. You may increase or decrease points on the chart depends on what you want do.

setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var x = (new Date()).getTime(),
y = parseFloat(this.responseText);
if(chartT.series[0].data.length > 50) {
chartT.series[0].addPoint([x, y], true, true, true);
} else {
chartT.series[0].addPoint([x, y], true, false, true);
}
}
};
xhttp.open("GET", "/temperature", true);
xhttp.send();
}, 1000 ) ;

Similarly it is done for Fahrenheit and Humidity.

Connect to Wifi network and print local IP address in serial monitor.

WiFi.begin(ssid, password);
Serial.println("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println(".");
}
Serial.println(WiFi.localIP());

These lines will handle the web server. When we make a request on root URL, we send the index_html variable. We are also adding three additional handlers to update temperature in Celsius, temperature in Fahrenheit and humidity.

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html);
});
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(t).c_str());
});
server.on("/fahrenheit", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(tf).c_str());
});
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(h).c_str());
});

Finally we start the server.

server.begin();

storing current temperature in “currentT”

float currentT = dht.readTemperature();

if “currentT” is not a number, we don’t want to change our “t” value, so it will print “failed to read”

if (isnan(currentT)) {
Serial.println("Failed to read from DHT sensor!");
}

else update “t” with current temperature value

Similiarly it is done fahrenheit & humidity.

else {
t = currentT;
Serial.println(t);

This is how you can plot the sensor value from ESP8266.

For more video please subscribe my youtube channel.

Till then keep learning keep making.

Video: