Esp32 All in One Weather Station
Esp32 All in One Weather Station
In this project I’ll show you how you can build an all-in-one ESP32 weather station shield and display the sensor readings
on a web server. The web server displays data from all the sensors and automatically updates the readings every ten
seconds, without the need to refresh the web page.
This guide is available in video format (watch below) and in written format (continue reading).
JLCPCB
The previous video was sponsored by JLCPCB. JLCPCB is a well known PCB prototype company in China. It is specialized
in quick PCB prototype and small-batch production. You can order a minimum of 10 PCBs for just $2.
If you want to turn your breadboard circuits into real boards and make your projects look more professional, you just
have to upload the Gerber files to order high quality PCBs for low prices. We’ll show you how to do this later in this blog
post.
Resources
You can find all the resources needed to build this project in the bullets below.
HTML page
Schematic diagram
Gerber files
To build this project, I’ve designed a PCB for the ESP32 DEVKIT V1 DOIT board. The PCB I’ve built only works with the
version with 30 GPIOs.
I’ve designed the shield to be a compact weather station. The PCB has a lot of features so that it can suit a lot of
different projects for different applications. In fact, I didn’t use all the PCB features in this project.
Additionally, this shield can also be used as a learning shield as it comes with some of the most used components when
starting to learn how to program the ESP32.
The shield allows you to control:
2x SMD LEDs
1x Pushbutton
1x Trimpot
2x Terminal blocks – that give you access to 3 GPIOs to connect other components
The microSD card module is a very interesting addition to the shield: it can be used to store readings if you want to build
a data logger, or it can store an HTML file to serve a web page – as we’ll do in this project. I think this is a better and
easier way to build a web server that requires more complex web pages.
The following table describes the pin assignment for each component on the shield:
Note: there’s a small problem with our pin assignment. Currently the Arduino WiFi library uses GPIO 4 that is connected
to the LDR. So, you’ll probably have trouble taking readings from the LDR when you use the WiFi library. To make it
work, you can solder a wire from the LDR to another available GPIO (must support ADC).
Before designing the shield, I’ve assembled the circuit on a breadboard. If you don’t want to make a PCB, you can still
follow this project by assembling the circuit on a breadboard.
Parts Required
2x 5mm LED
1x Pushbutton
1x BMP180
Breadboard
Jumper wires
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the
best price!
Schematic
After gathering all the needed parts, you can assemble the circuit by following the next schematic diagram:
Important: if you’re using a different board, you need to double-check the pinout.
After making sure the circuit was working properly, I’ve designed the PCB version on KiCad. KiCad is an open-source
software used to design PCBs.
I won’t explore how I’ve designed the PCB, but I provide all the files if you want to modify the PCB for yourself. Click here
to download the KiCad project files.
You don’t need to know how to design the PCB to order one. You just have to:
2. Go to JLCPCB.com, click the “QUOTE NOW” button, and upload the .zip file you’ve just downloaded.
3. You’ll see a success message at the bottom. Then, you can use the “Gerber Viewer” link at the bottom right corner to
check if everything went as expected. You can view the top and bottom of the PCB. You can view or hide the solder-
mask, silkscreen, copper, etc.
With the default settings, you can order 10 PCBs for just $2. However, if you want to select other settings like a different
PCB Color it will cost you a few more dollars.
When, you’re happy with your order. Click the “SAVE TO CART” button to complete the order.
My PCBs took 1 day to be manufactured and they arrived in 5 business days using DHL delivery option.
Unboxing
After a week, I received my PCBs at my office. Everything came well packed, and I also received a pen from JLCPCB.
Taking a closer look at the PCBs, I must say that I’m really impressed with the quality. I don’t think you can get a better
PCB service for this price.
The next step was soldering the components to the PCB. I used SMD LEDs and SMD resistors. I know it’s a bit difficult to
solder SMD components, but they can save a lot of space on the PCB. I’ve solder header pins to attach the ESP32, and
the sensors. This way, I can easily replace the sensors, if needed.
Here’s a list of all the components you need to solder on the PCB:
2x SMD LEDs
1x Trimpot (10k)
1x Pushbutton
1x SD card module
ESP32 DOIT DEVKIT V1 Board (version with 30 GPIOs) – you can get this board from Banggood, or from eBay
The following figure shows how the PCB looks like after soldering all the components.
In order to upload code to your ESP32 using Arduino IDE, you should install an add-on for the Arduino IDE that allows
you to program the ESP32 using the Arduino IDE and its programming language. Follow the next tutorial to prepare your
Arduino IDE:
DHT sensor library
Code
The next step is writing the code to read the sensors and build the web server. The code for this project is divided into
two parts:
The code in Arduino IDE to read the sensors and host a web server
An HTML file to build the web page. This HTML file should be saved in the microSD card.
Copy the code provided to the Arduino IDE. The code for this project is a bit long, but it’s fairly easy to understand. I’ve
also added various comments along the code. Don’t upload the code yet.
/*
* Rui Santos
*/
#include <WiFi.h>
#include "SD.h"
#include "DHT.h"
#include <Wire.h>
#include <Adafruit_BMP085.h>
// uncomment one of the lines below for whatever DHT sensor type you're using
Adafruit_BMP085 bmp;
File webFile;
// IMPORTANT: At the moment, GPIO 4 doesn't work as an ADC when using the Wi-Fi library
// This is a limitation of this shield, but you can use another GPIO to get the LDR readings
float tempC;
float tempF;
float humi;
String header;
WiFiServer server(80);
void setup(){
Serial.begin(115200);
dht.begin();
if (!bmp.begin()){
while (1) {}
// initialize SD card
if(!SD.begin()){
return;
if(cardType == CARD_NONE){
return;
// initialize SD card
Serial.println("Initializing SD card...");
if (!SD.begin()) {
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
delay(500);
Serial.print(".");
Serial.println("");
Serial.println("WiFi connected.");
Serial.println(WiFi.localIP());
server.begin();
void loop(){
while (client.connected()) {
header += c;
// if the current line is blank, you got two newline characters in a row.
// If client already on the web page, browser requests with AJAX the latest
if (header.indexOf("update_readings") >= 0) {
client.println("Content-Type: text/xml");
client.println("Connection: keep-alive");
client.println();
sendXMLFile(client);
// When the client connects for the first time, send it the index.html file
else {
client.println("Content-Type: text/html");
client.println("Connection: keep-alive");
client.println();
webFile = SD.open("/index.html");
if (webFile) {
while(webFile.available()) {
client.write(webFile.read());
webFile.close();
break;
// every line of text received from the client ends with \r\n
if (c == '\n') {
// last character on line of received text
currentLineIsBlank = true;
else if (c != '\r') {
currentLineIsBlank = false;
} // end if (client.available())
header = "";
client.stop();
Serial.println("Client disconnected.");
} // end if (client)
readDHT();
cl.print("<inputs>");
cl.print("<reading>");
cl.print(tempC);
cl.println("</reading>");
cl.print("<reading>");
cl.print(tempF);
cl.println("</reading>");
cl.print("<reading>");
cl.print(humi);
cl.println("</reading>");
cl.print("<reading>");
cl.print(currentTemperatureC);
cl.println("</reading>");
cl.print("<reading>");
cl.print(currentTemperatureF);
cl.println("</reading>");
cl.print("<reading>");
cl.print(bmp.readPressure());
cl.println("</reading>");
cl.print("<reading>");
cl.print(analogRead(potPin));
cl.println("</reading>");
cl.print("<reading>");
cl.print(analogRead(LDRPin));
cl.println("</reading>");
cl.print("</inputs>");
void readDHT(){
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
humi = dht.readHumidity();
tempC = dht.readTemperature();
tempF = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
return;
}
/*Serial.print("Humidity: ");
Serial.print(humi);
Serial.print(tempC);
Serial.print(" *C ");
Serial.print(tempF);
Serial.println(" *F");*/
Before uploading the code, you need to modify the following lines to add your SSID and password.
Then, press the upload button to upload the sketch to your ESP32. Make sure you have the right board and COM port
selected.
Create a new file using a text editor, and copy the following code. Alternatively, you can click here to download the
index.html file.
<!DOCTYPE html>
<html>
<head>
<script>
function DisplayCurrentTime() {
currentTime.innerHTML = time;
};
function GetReadings() {
nocache = "&nocache";
request.onreadystatechange = function() {
if (this.status == 200) {
if (this.responseXML != null) {
var count;
document.getElementsByClassName("reading")[count].innerHTML =
this.responseXML.getElementsByTagName('reading')
[count].childNodes[0].nodeValue;
request.send(null);
DisplayCurrentTime();
setTimeout('GetReadings()', 10000);
document.addEventListener('DOMContentLoaded', function() {
DisplayCurrentTime();
GetReadings();
}, false);
</script>
<style>
body {
text-align: center;
font-family: "Trebuchet MS", Arial;
table {
border-collapse: collapse;
width:60%;
margin-left:auto;
margin-right:auto;
th {
padding: 16px;
background-color: #0043af;
color: white;
tr {
padding: 16px;
tr:hover {
background-color: #bcbcbc;
td {
border: none;
padding: 16px;
.sensor {
color:white;
font-weight: bold;
background-color: #bcbcbc;
padding: 8px;
</style>
</head>
<body>
<table>
<tr>
<th>SENSOR</th>
<th>MEASUREMENT</th>
<th>VALUE</th>
</tr>
<tr>
<td><span class="sensor">DHT</span></td>
<td>Temp. Celsius</td>
</tr>
<tr>
<td><span class="sensor">DHT</span></td>
<td>Temp. Fahrenheit</td>
</tr>
<tr>
<td><span class="sensor">DHT</span></td>
<td>Humidity</td>
</tr>
<tr>
<td><span class="sensor">BMP180</span></td>
<td>Temp. Celsius</td>
</tr>
<tr>
<td><span class="sensor">BMP180</span></td>
<td>Temp. Fahrenheit</td>
<td><span class="reading">...</span> *F</td>
</tr>
<tr>
<td><span class="sensor">BMP180</span></td>
<td>Pressure</td>
</tr>
<tr>
<td><span class="sensor">POT</span></td>
<td>Position</td>
<td><span class="reading">...</span>/4095</td>
</tr>
<tr>
<td><span class="sensor">LDR</span></td>
<td>Luminosity</td>
<td><span class="reading">...</span>/4095</td>
</tr>
</table>
</body>
</html>
This is HTML, and it will build your web page. In this file you can change how your web page looks, the headings, the
table, etc… The ESP32 will send this HTML text to your browser when you make an HTTP request on the ESP32 IP
address.
Save the file as index.html. Copy the HTML file to your microSD card, and insert the microSD card into the SD card
module.
Open the serial monitor at a baud rate of 115200, and check the ESP32 IP address.
By the end of the project, you have your own ESP32 weather station web server, and all the hardware is well compacted
on a PCB.
Open your browser, type the IP address and you should see a table with the latest sensor readings. The web server
displays the DHT22, BMP180, potentiometer and LDR readings. The readings are updated every 10 seconds without the
need to refresh the web page.
To update the readings without refreshing the web page, we use AJAX. As you can read here, AJAX is a developer’s
dream, because it can update the web page without reloading the page, request and receive data from a server, after
the page has loaded, and send data to a server in the background.
Taking it Further
There’s still room to improve this project, you can use the extra terminals to connect other sensors or a relay. You can
also program the ESP32 to trigger an event when a reading is below or above a certain threshold. The idea is that you
modify the code provided to use the shield in a way that meets your own specific needs.
If you want to get your own all-in-one ESP32 weather station shield, you just need to upload the .zip file with the Gerber
files to the JLCPCB website. You’ll get high quality PCBs for a very reasonable price.