In this project you’ll create a standalone web server with an ESP8266 that displays the temperature and humidity with a DHT11 or DHT22 sensor using the Arduino IDE. The web server you’ll build can be accessed with any device that has a browser on your local network.
Component Required:
ESP8266 12E- v3- 1 no
DHT11- 1no
DHT 11/22/AM2302
Connecting DHT11/DHT22/AM2302 sensor to ESP8266 NodeMCU is fairly simple.
Connect VCC pin on the sensor to the 3.3V pin on the NodeMCU and ground to ground. Also connect Data pin on the sensor to D1 pin of the ESP8266 NodeMCU.
Installing DHT Sensor Library
Communicating with DHT11, DHT22/AM2302 sensors is a bunch of work, as they have their own single wire protocol for data transfer. And this protocol requires precise timing.
To read from the DHT sensor, we’ll use the DHT library from Adafruit. To use this library you also need to install the Adafruit Unified Sensor library. Follow the next steps to install those libraries.
1. Open your Arduino IDE and go to Sketch > Include Library > Manage Libraries. The Library Manager should open.
2. Search for “DHT” on the Search box and install the DHT library from Adafruit version 1.3.4.
3. After installing the DHT library from Adafruit version 1.0.2, type “Adafruit Unified Sensor” in the search box. Scroll all the way down to find the library and install it.
After installing the libraries, restart your Arduino IDE.
ESP8266 Asynchronous Web Server
To build the web server we’ll use the ESPAsyncWebServer library that provides an easy way to build an asynchronous web server. Building an asynchronous web server has several advantages. We recommend taking a quick look at the library documentation on its GitHub page.
Installing the ESPAsyncWebServer library
The ESPAsyncWebServer library is not available to install in the Arduino IDE Library Manager. So, you need to install it manually.
Click here to download the https://github.com/me-no-dev/ESPAsyncWebServer/archive/master.zip
library. You should have a .zip folder in your Downloads folder Unzip the .zip folder and you should get ESPAsyncWebServer-master folder
Rename your folder from ESPAsyncWebServer-master to ESPAsyncWebServer
Move the ESPAsyncWebServer folder to your Arduino IDE installation libraries folder
Installing the ESPAsync TCP Library
The ESPAsyncWebServer library requires the ESPAsyncTCP library to work. Follow the next steps to install that library:
Click here to download the https://github.com/me-no-dev/ESPAsyncTCP/archive/master.zip
library. You should have a .zip folder in your Downloads folder
Unzip the .zip folder and you should get ESPAsyncTCP-master folder
Rename your folder from ESPAsyncTCP-master to ESPAsyncTCP
Move the ESPAsyncTCP folder to your Arduino IDE installation libraries folder
After installing the libraries, restart your Arduino IDE.
Code
Install the ESP8266 Board in Arduino IDE
Open your Arduino IDE and copy the following code.
How the Code Works
In the following paragraphs we’ll explain how the code works. Keep reading if you want to learn more or jump to the Demonstration section to see the final result.
Importing libraries
First, import the required libraries.
Subscribe and Download code.
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <Hash.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
Setting your network credentials
Insert your network credentials in the following variables, so that the ESP8266 can connect to your local network.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Variables definition
Define the GPIO that the DHT data pin is connected to. In this case, it’s connected to GPIO5 (D1).
#define DHTPIN 5 // Digital pin connected to the DHT sensor
Then, select the DHT sensor type you’re using. In our example, we’re using the DHT22. If you’re using another type, you just need to uncomment your sensor and comment all the others.
#define DHTTYPE DHT22 // DHT 22 (AM2302)
Instantiate a DHTobject with the type and pin defined earlier.
DHT dht(DHTPIN, DHTTYPE);
Create an AsyncWebServerobject on port 80.
AsyncWebServer server(80);
Create float variables to hold the current temperature and humidity values. The temperature and humidity are updated in the loop().
float t = 0.0;
float h = 0.0;
Create timer variables needed to update the temperature readings every 10 seconds.
unsigned long previousMillis = 0; // will store last time DHT was updated
// Updates DHT readings every 10 seconds
const long interval = 10000;
Building the Web Page
Proceeding to the web server page.
As you can see in the above figure, the web page shows one heading and two paragraphs. There is a paragraph to display the temperature and another to display the humidity. There are also two icons to style the page.
Let’s see how this web page is created.
All the HTML text with styles included is stored in the index_html variable, refer in final code.
The <i> tags display the fontawesome icons.
How to display icons
To chose the icons, go to the Font Awesome Icons website.
Search the icon you’re looking for. For example, “thermometer”.
Click the desired icon. Then, you just need to copy the HTML text provided.
<i class="fas fa-thermometer-full">
To chose the color, you just need to pass the style parameter with the color in hexadecimal, as follows:
<i class="fas fa-tint" style="color:orange;"></i>
Proceeding with the HTML text…
The next line writes the word “Temperature” into the web page.
<span class="dht-labels">Temperature</span>
The TEMPERATURE text between % signs is a placeholder for the temperature value.
<span id="temperature">%TEMPERATURE%</span>
This means that this %TEMPERATURE% text is like a variable that will be replaced by the actual temperature value from the DHT sensor. The placeholders on the HTML text should go between % signs.
Finally, we add the degree symbol.
<sup class="units">°C</sup>
The <sup></sup> tags make the text superscript.
We use the same approach for the humidity paragraph, but it uses a different icon and the %HUMIDITY% placeholder.
<p>
<i class="fas fa-tint" style="color:#00add6;"></i>
<span class="dht-labels">Humidity</span>
<span id="humidity">%HUMIDITY%</span>
<sup class="units">%</sup>
</p>
Automatic Updates
Finally, there’s some JavaScript code in our web page that updates the temperature and humidity automatically, every 10 seconds.
Scripts in HTML text should go between the <script></script> tags.
<script>
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("temperature").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/temperature", true);
xhttp.send();
}, 10000 ) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("humidity").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/humidity", true);
xhttp.send();
}, 10000 ) ;
</script>
To update the temperature on the background, we have a setInterval() function that runs every 10 seconds.
Basically, it makes a request in the /temperature URL to get the latest temperature reading.
xhttp.open("GET", "/temperature", true);
xhttp.send();
}, 10000 ) ;
When it receives that value, it updates the HTML element whose id is temperature.
if (this.readyState == 4 && this.status == 200) {
document.getElementById("temperature").innerHTML = this.responseText;
}
In summary, this previous section is responsible for updating the temperature asynchronously. The same process is repeated for the humidity readings.
Processor
Now, we need to create the processor() function, that will replace the placeholders in our HTML text with the actual temperature and humidity values.
String processor(const String& var){
//Serial.println(var);
if(var == "TEMPERATURE"){
return String(t);
}
else if(var == "HUMIDITY"){
return String(h);
}
return String();
}
When the web page is requested, we check if the HTML has any placeholders. If it finds the %TEMPERATURE% placeholder, we return the temperature that is stored on the t variable.
if(var == "TEMPERATURE"){
return String(t);
}
If the placeholder is %HUMIDITY%, we return the humidity value.
else if(var == "HUMIDITY"){
return String(h);
}
setup()
In the setup(), initialize the Serial Monitor for debugging purposes.
Serial.begin(115200);
Initialize the DHT sensor.
dht.begin();
Connect to your local network and print the ESP8266 IP address.
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
Finally, add the next lines of code to handle the web server.
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(t).c_str());
});
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(h).c_str());
});
When we make a request on the root URL, we send the HTML text that is stored on the index_html variable. We also need to pass the processorfunction, that will replace all the placeholders with the right values.
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
We need to add two additional handlers to update the temperature and humidity readings. When we receive a request on the /temperature URL, we simply need to send the updated temperature value. It is plain text, and it should be sent as a char, so, we use the c_str() method.
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(t).c_str());
});
The same process is repeated for the humidity.
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(h).c_str());
});
Lastly, we can start the server.
server.begin();
In the loop() is where we get new temperature readings from the sensor every 10 seconds.
Basically, we check if it is time to get new sensor readings:
if (currentMillis - previousMillis >= interval) {
If it is, we store a new temperature reading on the newT variable
float newT = dht.readTemperature();
If the newT variable is a valid temperature readings, we update the t variable.
else {
t = newT;
Serial.println(t);
}
The same process is repeated for the humidity.
// Read Humidity
float newH = dht.readHumidity();
// if humidity read failed, don't change h value
if (isnan(newH)) {
Serial.println("Failed to read from DHT sensor!");
}
else {
h = newH;
Serial.println(h);
}
That’s pretty much how the code works.
Finally Download CODE:
Subscribe and Download code.
Comments