Monday, May 22, 2017

Demo 13: How to display temperature/humidity using Google Chart/Jquery and control LED through Arduino ESP32 Web Server

1. Introduction
In this tutorial,we will combine previous tutorial to make a simple project. This project combines previous tutorials:
- Turn the ESP32 into Web Server (Demo 12: How to turn the ESP32 into a Web Server)
- Load the html chart page from Sdcard and respond to web browser (Demo 7: How to use Arduino ESP32 to store data to sdcard)
- Measure temperature/humidity using DHT22 (Demo 3: How to use Arduino ESP32 to read temperature/humidity from DHT11/DHT22)
- Control LED (Demo 1: Blinky - a Hello World on Arduino ESP32)
- mDNS for HTTP service (Demo 9: How to use mDNS to resolve host names to ESP32 IP addresses)
So when browser access "http://esp32.local" a chart of temperature/humidity will occur along with a button name "LED" to control LED on/off. This button have green color when led is on and red color when led is off.
2. Hardware
You need modules below:  
- A module micrSD with memory card
- A DHT22 sensor
- A LED
- ESP32 board
Connections:
Connect VCC and GND of microSD (VCC=5V), DHT22 (VCC=3.3V) to VCC (5V-3.3V) and GND of ESP32.
[ESP32 IO15 - DHT22 DATA]
[ESP32 IO2 - LED ANODE]
[ESP32 GND - LED CATHODE]
[ESP32 IO26 - microSD CS]
[ESP32 IO27 - microSD SCK]
[ESP32 IO14 - microSD MOSI]
[ESP32 IO12 - microSD MISO]
Figure: ESP32 connect to microSD, DHT22, LED
3. Software
- Create a chrt.html file in memory card at root "/" with content:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<!DOCTYPE html>
<head>
   <meta charset="utf-8" />
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1.1','packages':['corechart','gauge','line','imagelinechart']}]}"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<style>
.btn {
    background-color: #4CAF50;
    border: none;
    color: white;
    padding: 15px 32px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
    margin: 4px 2px;
    cursor: pointer;
}
.red {background-color: #f44336;}
</style>
</head>
<body>
<div align="center"><h1>IoTSharing.com Chart Demo</h1></div> 
<div id="htchart"></div>
<p><button id="led" class="btn red">LED</button></p>
<script>
google.charts.setOnLoadCallback(draw);
var data, chart;
var cnt = 0;
var points = 14;
var got = 0;
var led = 0;
var opt = {
    hAxis: {
        title:'Time'
    },
    vAxis: {
        title:'Temp/Hum'
    }
};    
function draw(){
    data = new google.visualization.DataTable();
    chart = new google.visualization.LineChart(document.getElementById('htchart'));
    data.addColumn('string','Time');
    data.addColumn('number','temp');
    data.addColumn('number','hum');
    data.addRows([
        [' ', 0, 0]  
    ]);
    chart.draw(data, opt);
}
$("#led").click(function() {
    if(led == 0){
        $.get("/led1", function(d, s){
            led = 1;
            $("#led").removeClass("btn red");$("#led").addClass("btn");
     });
    }else{led=0;
        $.get("/led0", function(d, s){
            led = 0; 
            $("#led").removeClass("btn");$("#led").addClass("btn red");
     });
    } 
});
function update() {
    if(got == 0){
        got = 1;
        $.get("/dht22", function(j, s){
            cnt ++;
            var cur = new Date();
            data.addRows([[cur.getMinutes() + ":" + cur.getSeconds(), j.temp, j.hum]]);
            if(cnt == points){
                for (i = 0; i < points/2; i++) {
                    data.removeRow(i);
                }
                cnt = i;
            }
            got = 0;
            chart.draw(data, opt);
     });
    }else{
        got ++;
        if(got == points/3){
            got = 0;        
        }
    }  
}
setInterval(update, 1000);
</script>
</body>
</html>
The html code using Google chart API for drawing the values of temperature/humidity under line chart style and Jquery to query the value of DHT22 (through update() function every 1 second) "setInterval(update, 1000)".In the update() function we use Jquery "$.get("/dht22", function(j, s)" to query "/dht22" temperature/humidity. We also create a "led" button and process "click" action when user press it through "$("#led").click(function()". In click processing function we check if current status of LED is 0 we create a Jquery to request the LED on through "$.get("/led1", function(d, s)" and vice versa. About Google chart code, whenever we got new data from DHT22 we add it into data table and re-draw the chart.
- In this project we use Json style to respond the dht22 request from client. So we download Json library at: https://github.com/bblanchon/ArduinoJson.git . The unzipping the downloaded folder and copy it to Arduino/libraries.
- Then we create an Arduino project and Save as esp32chart with code:
Note: I explain the code by detail comments in the code, so I will not mention more here.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <WiFiClient.h>
#include <ESP32WebServer.h>
#include <WiFi.h>
#include <ESPmDNS.h>
#include "DHT.h"
#include <ArduinoJson.h>
#include <SPI.h>
#include <mySD.h>

#define DHTPIN 15
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

const char* ssid = "dd-wrt";
const char* password = "0000000000";

ESP32WebServer server(80);

float humidity = 0;
float temperature = 0;

const int led = 2;


void handleRoot() {
  /* we load the chart.html from microSD */
  File myFile = SD.open("CHRT~1.HTM");
  if (myFile) {  
    /* respond the content of file to client by calling streamFile()*/
    size_t sent = server.streamFile(myFile, "text/html");
    /* close the file */
    myFile.close();
  } else {
    Serial.println("error opening test.txt");
  }
}
void handleLed1() {
  digitalWrite(led, 1);
  server.send(200, "text/html", "1");
}
void handleLed0() {
  digitalWrite(led, 0);
  server.send(200, "text/html", "0");
}
void handleDHT(){
  /* read the data from dht22 sensor */
  humidity = dht.readHumidity();
  temperature = dht.readTemperature();
  StaticJsonBuffer<100> jsonBuffer;
  JsonObject& root = jsonBuffer.createObject();
  /* failed to read the data then return HTTP status code 503 sensor failed */
  if (isnan(humidity) || isnan(temperature)) {
    server.send(503, "text/html", "sensor failed");
  } else {
    /* we use Json "{"hum":#value, "temp": #value}" to respond the /dht22 request */
    root["hum"] = humidity;
    root["temp"] = temperature;
    char jsonChar[100];
    root.printTo((char*)jsonChar, root.measureLength() + 1);
    /* we respond Json style so content-type is text/json */
    server.send(200, "text/json", jsonChar);
  }
}
/* cannot handle request so return 404 */
void handleNotFound(){
  digitalWrite(led, 1);
  String message = "File Not Found\n\n";
  server.send(404, "text/plain", message);
  digitalWrite(led, 0);
}

void setup(void){
  pinMode(led, OUTPUT);
  digitalWrite(led, 0);
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  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());

  if (MDNS.begin("esp32")) {
    Serial.println("MDNS responder started");
  }
  /* register the callbacks to process client request */
  /* root request we will read the memory card to get 
  the content of chrt.html and respond that content to client */
  server.on("/", handleRoot);
  /* this callback handle /dht22 request, 
  read the sensor form json string and respond*/
  server.on("/dht22", handleDHT);
  /* this callback handle /led1 request, just turn on led */
  server.on("/led1", handleLed1);
  /* this callback handle /led0 request, just turn off led */
  server.on("/led0", handleLed0);
  server.onNotFound(handleNotFound);
  server.begin();
  dht.begin();
  Serial.println("HTTP server started");
  Serial.print("Initializing SD card...");
  /* initialize microSD */
  if (!SD.begin(26, 14, 12, 27)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
}

void loop(void){
  server.handleClient();
}
4. Result
Figure: esp32 webserver + dht22 + led + google chart + jquery 


 Figure: esp32 webserver + dht22 + led + google chart + jquery demo

Figure: esp32 webserver + dht22 + led + google chart + jquery demo

7 comments:

David Bell said...

Do you know if it is possible to save the html file to the esp32 flash instead of sd card? I haven't found a way yet.

Until then I am using this batch file
(
echo R"!~!(
type somefile.html
echo ^)!~!"
) > somefile.html.h
called before build,

then with C++11 string literals main file it's just

String s =
#include somefile.html.h
;

I find it convenient to edit the html in a different editor and it saves a lot of escaping etc.

DB

iotsharing dotcom said...

Hi

You can do like following post:

http://www.iotsharing.com/2017/06/how-to-control-servo-via-arduino-esp32-webserver.html

RGs

Pjort said...

This doesn't work for me. I got the correct libaries, and I am able to see the html on http://esp32.local

But the LED button doesn't work, and the there is no chart. Just "IoTSharing.com Chart Demo" and LED button.

if I go to http://esp32.local/dht22 I can see the values changin, but still no chart...

Did something change? Maybe with the api?

Pjort said...

Looks like the update doesn't trigger somehow, see screenshot of the network and the get metodes not getting called: https://imgur.com/ibQyrEi

Anonymous said...

Hi I am getting the same I can see the LED button but it doesn't work and there is no chart. I can get the humidity and temperature by using esp32.local/dht22. Can you please give me some advice thanks Bob

Anonymous said...

I have managed to alter the html file to display the graph by adding

google.charts.load('current', {packages: ['corechart']});

before line 28

Bob

iotsharing dotcom said...

Hi friends,

Check this post;
http://www.iotsharing.com/2018/05/how-to-build-iot-dashboard-using-node-red.html

It is easy to implement :)

Regards