Design a site like this with WordPress.com
Get started

ESP32/ESP8266 Plot Sensor Readings in Real Time Charts – Web Server

Learn how to plot sensor readings (temperature, humidity, and pressure) on a web server using the ESP32 or ESP8266 with Arduino IDE. The ESP will host a web page with three real time charts that have new readings added every 30 seconds.

Project Overview

In this tutorial we’ll build an asynchronous web server using the ESPAsyncWebServer library.

The HTML to build the web page will be stored on the ESP32 or ESP8266 Filesystem (SPIFFS). To learn more about building a web server using SPIFFS, you can refer to the next tutorials:

We’ll display temperature, humidity and pressure readings from a BME280 sensor on a chart, but you can modify this project to display sensor readings from any other sensor. To learn more about the BME280, read our guides:

To build the charts, we’ll use the Highcharts library. We’ll create three charts: temperature, humidity and pressure over time. The charts display a maximum of 40 data points, and a new reading is added every 30 seconds, but you change these values in your code.

Prerequisites

Make sure you check all the prerequisites in this section before continuing with the project in order to compile the code.

1. Install ESP Board in Arduino IDE

We’ll program the ESP32 and ESP8266 using Arduino IDE. So, you must have the ESP32 or ESP8266 add-on installed. Follow one of the next tutorials to install the ESP add-on:

2. Filesystem Uploader Plugin

To upload the HTML file to the ESP32 and ESP8266 flash memory, we’ll use a plugin for Arduino IDE: Filesystem uploader. Follow one of the next tutorials to install the filesystem uploader depending on the board you’re using:

3. Installing Libraries

To build the asynchronous web server, you need to install the following libraries.

These libraries aren’t available to install through the Arduino Library Manager, so you need to copy the library files to the Arduino Installation folder.

To get readings from the BME280 sensor module you need to have the next libraries installed:

You can install these libraries through the Arduino Library Manager.

Parts Required

To follow this tutorial you need the following parts:

  • ESP32 or ESP8266 (read ESP32 vs ESP8266)
  • BME280 sensor
  • Breadboard
  • Jumper wires

Schematic Diagram

The BME280 sensor module we’re using communicates via I2C communication protocol, so you need to connect it to the ESP32 or ESP8266 I2C pins.

BME280 wiring to ESP32

BME280ESP32
SCK (SCL Pin)GPIO 22
SDI (SDA pin)GPIO 21

So, assemble your circuit as shown in the next schematic diagram.

Recommended reading: ESP32 Pinout Reference Guide

BME280 wiring to ESP8266

BME280ESP8266
SCK (SCL Pin)GPIO 5
SDI (SDA pin)GPIO 4

Assemble your circuit as in the next schematic diagram if you’re using an ESP8266 board.

Recommended reading: ESP8266 Pinout Reference Guide

Organizing your Files

To build the web server you need two different files. The Arduino sketch and the HTML file. The HTML file should be saved inside a folder called data inside the Arduino sketch folder, as shown below:

Creating the HTML File

<!DOCTYPE HTML><html>


Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. -->
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  https://code.highcharts.com/highcharts.js tags.

The following spinet creates the temperature chart. You define the chart id, you can set the title, the axis labels, etc…

var chartT = new Highcharts.Chart({
  chart:{ renderTo : 'chart-temperature' },
  title: { text: 'BME280 Temperature' },
  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)' }
    //title: { text: 'Temperature (Fahrenheit)' }
  },
  credits: { enabled: false }
});

Then, the setInvertal() function adds points to the charts. Every 30 seconds it makes a request to the /temperature URL to get the temperature readings from your ESP32 or ESP8266.

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(chartT.series[0].data.length > 40) {
        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();
}, 30000 ) ;

The other graphics are created in a similar way. We make a request on the /humidity and /pressure URLs to get the humidity and pressure readings, respectively.

In the Arduino sketch, we should handle what happens when we receive those requests: we should send the corresponding sensor readings.

Arduino Sketch

. Then, you need to type your network credentials (SSID and password) to make it work.

/*********
  Gnd_To_Vcc
 
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*********/

// Import required libraries
#ifdef ESP32
  #include <WiFi.h>
  #include <ESPAsyncWebServer.h>
  #include <SPIFFS.h>
#else
  #include <Arduino.h>
  #include <ESP8266WiFi.h>
  #include <Hash.h>
  #include <ESPAsyncTCP.h>
  #include <ESPAsyncWebServer.h>
  #include <FS.h>
#endif
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

/*#include <SPI.h>
#define BME_SCK 18
#define BME_MISO 19
#define BME_MOSI 23
#define BME_CS 5*/

Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

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

String readBME280Temperature() {
  // Read temperature as Celsius (the default)
  float t = bme.readTemperature();
  // Convert temperature to Fahrenheit
  //t = 1.8 * t + 32;
  if (isnan(t)) {    
    Serial.println("Failed to read from BME280 sensor!");
    return "";
  }
  else {
    Serial.println(t);
    return String(t);
  }
}

String readBME280Humidity() {
  float h = bme.readHumidity();
  if (isnan(h)) {
    Serial.println("Failed to read from BME280 sensor!");
    return "";
  }
  else {
    Serial.println(h);
    return String(h);
  }
}

String readBME280Pressure() {
  float p = bme.readPressure() / 100.0F;
  if (isnan(p)) {
    Serial.println("Failed to read from BME280 sensor!");
    return "";
  }
  else {
    Serial.println(p);
    return String(p);
  }
}

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);
  
  bool status; 
  // default settings
  // (you can also pass in a Wire library object like &Wire2)
  status = bme.begin(0x76);  
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

  // Initialize SPIFFS
  if(!SPIFFS.begin()){
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }

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

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

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/index.html");
  });
  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readBME280Temperature().c_str());
  });
  server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readBME280Humidity().c_str());
  });
  server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readBME280Pressure().c_str());
  });

  // Start server
  server.begin();
}
 
void loop(){
  
}

How the code works

Let’s take a quick look at the code and see how it works.

Including libraries

First, include the necessary libraries. You include different libraries depending on the board you’re using. If you’re using an ESP32, the code loads the following libraries:

#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>

If you’re using an ESP8266, the code loads these libraries:

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <Hash.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <FS.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

Create an instance to communicate with the BME280 sensor using I2C:

Adafruit_BME280 bme; // I2C

Insert your network credentials in the following variables:

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Create AsyncWebServer object on port 80:

AsyncWebServer server(80);

Read Temperature, Humidity and Pressure

Then, we create three functions readBME280Temperature(), readBME280Humidity() and readBME280Pressure(). These functions request the temperature, humidity and pressure from the BME280 sensor and return the readings as a String type.

String readBME280Temperature() {
  // Read temperature as Celsius (the default)
  float t = bme.readTemperature();
  // Convert temperature to Fahrenheit
  //t = 1.8 * t + 32;
  if (isnan(t)) {
    Serial.println("Failed to read from BME280 sensor!");
    return "";
  }
  else {
    Serial.println(t);
    return String(t);
  }
}

Init BME280

In the setup(), initialize the sensor:

status = bme.begin(0x76);
if (!status) {
  Serial.println("Could not find a valid BME280 sensor, check wiring!");
  while (1);
}

Init SPIFFS

Initialize the filesystem (SPIFFS):

if(!SPIFFS.begin()){
  Serial.println("An Error has occurred while mounting SPIFFS");
  return;
}

Connect to Wi-Fi

Connect to Wi-Fi and print the IP address in the Serial Monitor:

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

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

Handle requests

Then, we need to handle what happens when the ESP receives a request.

When it receives a request on the root URL, we send the HTML text that is saved in SPIFFS under the index.html name:

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send(SPIFFS, "/index.html");
});

When we receive a request on the /temperature/humidity or /pressure URLs, call the functions that return the sensor readings.

For example, if we receive a request on the /temperature URL, we call the readBME280Temperature() function that returns the temperature.

server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/plain", readBME280Temperature().c_str());
});

The same happens for the other readings.

Finally, start the server:

server.begin();

Because this is an asynchronous web server we don’t need to write anything in the loop().

void loop(){

}

Uploading Code and Files

Save the code as ESP_Chart_Web_Server . Go to Sketch > Show Sketch Folder, and create a folder called data. Inside that folder you should save the HTML file created previously.

Now you need to upload the HTML file to the ESP32 or ESP8266 filesystem. Go to Tools ESP32/ESP8266 Data Sketch Upload and wait for the files to be uploaded.

Then, upload the code to your board. Make sure you have the right board and COM port selected. Also, make sure you’ve inserted your networks credentials in the code.

When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200. Press the board “EN/RST” button, and it should print its IP address.

Demonstration

Open a browser on your local network and type the ESP32 or ESP8266 IP address. You should see three charts. A new data point is added every 30 seconds to a total of 40 points. New data keeps being displayed on the charts as long as you have your web browser tab open.

Here is an example of the humidity chart:

You can select each point to see the exact timestamp.

Wrapping Up

In this tutorial you’ve learned how to create charts to display data in your web server. You can modify this project to create as many charts as you want and using any other sensors.

Next, we recommend building a project that displays charts from data stored on your database. Here’s other tutorials that you might like:

Thank you for reading.

Advertisement

Published by Gnd_To_Vcc

Here to spread my knowledge . Knowledge should always be spread not stored.

3 thoughts on “ESP32/ESP8266 Plot Sensor Readings in Real Time Charts – Web Server

  1. Hi, thank you for sharing the idea and code. However I am not able to create the index.html file. Seems like there is something missing. Or am I wrong?

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: