In this tutorial we will see how to make your own weather station using ESP8266. ESP8266 weather station will update current temperature in degree Celsius and Fahrenheit and also update humidity in every one second. It will update sensor value automatically without refreshing your web page. Web page has custom CSS to style the page with some cool icons which make more sense to sensor data. So, let’s get started.

Components required:
  1. NodeMCU ESP8266 12E,
  2. DHT22 sensor,
  3. 10K ohms Resistor,
  4. Breadboard,
  5. Jumper Wire.
ESP8266 Weather Station Circuit diagram:

ESP8266 Weather Station

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";
ESP8266 Weather Station Code:
// Import required libraries
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "DHT.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

const char index_html[] PROGMEM = R"webpage(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<style>
html {
font-family: Arial;
display: inline-block;
margin: 0px auto;
text-align: center;
}
h2 { font-size: 2.0rem; }
p { font-size: 3.0rem; }
.units { font-size: 1.2rem; }
.sensor-labels{
font-size: 1.3rem;
vertical-align:middle;
padding-bottom: 15px;
}
</style>
</head>
<body>
<h2>ESP8266 Weather Station</h2>
<p>
<i class="fas fa-thermometer" style="color:#ffd700;"></i> 
<span class="sensor-labels">Temperature</span> 
<span id="temperature">%TEMPERATURE%</span>
<sup class="units">&deg;C</sup>
</p>
<p>
<i class="fas fa-cloud-sun" style="color:#f99600;"></i> 
<span class="sensor-labels">Fahrenheit</span>
<span id="fahrenheit">%FAHRENHEIT%</span>
<sup class="units">&deg;F</sup>
</p>
<p>
<i class="fas fa-tint" style="color:#00add6;"></i> 
<span class="sensor-labels">Humidity</span>
<span id="humidity">%HUMIDITY%</span>
<sup class="units">%</sup>
</p>
</body>
<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();
}, 1000 ) ;

setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("fahrenheit").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/fahrenheit", true);
xhttp.send();
}, 1000 ) ;

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();
}, 1000 ) ;
</script>
</html>)webpage";

// Replaces placeholder with DHT values
String processor(const String& var){
//Serial.println(var);
if(var == "TEMPERATURE"){
return String(t);
}
else if(var == "FAHRENHEIT"){
return String(tf);
}
else if(var == "HUMIDITY"){
return String(h);
}
return String();
}

void setup(){
Serial.begin(115200);
dht.begin();

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

// Print ESP8266 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, processor);
});
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();
}

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!");
}
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);
}
}
}

Before uploading code make sure, you have selected correct board and port (Your port number may be different).

Select NodeMCU 1.0 12E board

Select NodeMCU 1.0 12E board

Select port for ESP8266

Select port for ESP8266

After uploading code, Open Serial monitor to find out ESP8266 local IP address. If you can’t see IP address (Only temperature and humidity reading which it printing in every one second). Press reset button on ESP8266. Now you will able see it. For example 192.168.0.105

ESP8266 Weather Staion IoT project dont need to refresh web page

Type that IP address to any browser and you will be able to see your live weather station, which is updating in every one second.

Code Explanation:

Import required libraries.

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

Replace with your wifi network name and password.

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 value in degree Celsius and temperature in Fahrenheit and humidity. Which 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);

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

All HTML text with style is stored in index_html variable.

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

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

the <link> tag needed to load icon from fontawesome.com website. We will discuss it later.

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
Styles:

We are adding some CSS to style the web page. Here you can set font type, text alignment. Heading (h2) font size, paragraph (p) font size, unit font size and sensor labels and bottom padding. You can play with this if you want to change size of font.

<style>
html {
font-family: Arial;
display: inline-block;
margin: 0px auto;
text-align: center;
}
h2 { font-size: 2.0rem; }
p { font-size: 3.0rem; }
.units { font-size: 1.2rem; }
.sensor-labels{
font-size: 1.3rem;
vertical-align:middle;
padding-bottom: 15px;
}
</style>

From <head> to </head> tag contains a tag content, which is not directly visible to user.

HTML Body:
<body>
<h2>ESP8266 Weather Station</h2>
<p>
<i class="fas fa-thermometer-half" style="color:#FF0000;"></i>
<span class="sensor-labels">Temperature</span>
<span id="temperature">%TEMPERATURE%</span>
<sup class="units">&deg;C</sup>
</p>
<p>
<i class="fas fa-cloud-sun" style="color:#f99600;"></i>
<span class="sensor-labels">Fahrenheit</span>
<span id="fahrenheit">%FAHRENHEIT%</span>
<sup class="units">&deg;F</sup>
</p>
<p>
<i class="fas fa-tint" style="color:#00add6;"></i>
<span class="sensor-labels">Humidity</span>
<span id="humidity">%HUMIDITY%</span>
<sup class="units">%</sup>
</p>
</body>

Inside <body></body> contain web page content. This body contain One heading and total three paragraph. First paragraph for Temperature in Celsius, second for Temperature in Fahrenheit. and third for Humidity.

<h2> tag add heading to web page. You can give any heading to web page.

<h2>ESP8266 Weather Station</h2>

<i> tag show fontawesome icon, for temperature and humidity, you can change icon from fontawesome.com  and also change color by giving hexadecimal number.

<i class="fas fa-thermometer-half" style="color:#FF0000;"></i>

This will be printed on first paragraph i.e Temperature

<span class="sensor-labels">Temperature</span>

Next line will temperature value. % TEMPERATURE% act as a variable. This will be replace by DHT sensor value.

<span id="temperature">%TEMPERATURE%</span>

This line will show units.

<sup class="units">&deg;C</sup>

In same way it is done for Fahrenheit & Humidity.

How to change Icon and Color:

Go to Fontawesome.com, Search icon. For example we want icon for tempeture, type temperature and search.

Search for Icon

don’t use pro, use it if you are planning to buy it. You can filter result by clicking on free button. Copy HTML code and paste it here. for example “fas fa-thermometer-half”.

<i class="fas fa-thermometer-half" style="color:#FF0000;"></i>
Copy HTML code for icon

HTML code for ICON

For changing color go to color-hex website, choose color and copy HTML code for color and paste here in the code.  for example #FF0000.

<i class="fas fa-thermometer-half" style="color:#FF0000;"></i>
copy HTML code for color

HTML code for color

Update reading automatically:

There is some JavaScript in our code to automatically update temperature & humidity reading every 1 second.

<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();
}, 1000 ) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("fahrenheit").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/fahrenheit", true);
xhttp.send();
}, 1000 ) ;
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();
}, 1000 ) ;
</script>

This section of code will replace placeholder (%TEMPERATURE%)from HTML text to DHT reading values.

String processor(const String& var){
//Serial.println(var);
if(var == "TEMPERATURE"){
return String(t);
}
else if(var == "FAHRENHEIT"){
return String(tf);
}
else if(var == "HUMIDITY"){
return String(h);
}
return String();
}

These lines will handle the web server. When we make a request on root URL, we send the index_html variable and we are also passing processor to replace all placeholder to dht value. 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, processor);
});
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();

In loop function we are updating current temperature and humidity. 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 for humidity.

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

I hope you will like the ESP8266 IoT Project where you don’t need to refresh web page to update sensor data. Subscribe my YouTube channel for more updates.

Till Then Keep Learning Keep Making.

Video: