Simple Weather Device using LCD and Sensors (DHT11/BME280) on ESP32

Xavier Prasetyo
6 min readFeb 17, 2020

--

Hi Folks !

Today I’m going to share my project on creating a simple weather device using a display (LCD) and a weather sensor (DHT11 and BME280). Okay, Let’s get started!

Using LCD as a display

First, let’s test the LCD to display some text using esp32. LCD use 16 pins to communicate, but we can use a converter to I2C (Inter-Integrated Circuit). I2C is a serial computer bus used to communicate using 4 pins, VIN, Ground, SDA, and SCL. In ESP32 there are dedicated pins that can be used to communicate using I2C. Pin 21 is the SDA pin and Pin 22 is the SCL pin. Next, let’s make a circuit that looked like this.

Source : https://randomnerdtutorials.com/esp32-esp8266-i2c-lcd-arduino-ide/#more-67483

Next, download LCD library for Arduino from here and rename it to LiquidCrystal_I2C. Put the folder to Arduino IDE installation libraries folder.

Getting LCD Address

I2C devices communicates based on the address of each device. We must first identifies the lcd address to use it. To do this we used a library called Wire.h. Here are the code to search for I2C device addresses.

#include <Wire.h>

void setup() {
Wire.begin();
Serial.begin(115200);
Serial.println("\nI2C Scanner");
}

void loop() {
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ ) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
nDevices++;
}
else if (error==4) {
Serial.print("Unknow error at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found\n");
}
else {
Serial.println("done\n");
}
delay(5000);
}

Upload it to ESP32 and open serial monitor at 115200 baud. You should see the LCD address represented in hexadecimals if the wiring is connected properly. Sometimes the board would not detect the device. In this case try to change the jumper wire or breadboard in case of a faulty wire.

Displaying Text In LCD

To display some text, upload this code to your ESP32 board. Use the address from the previous section to specify LCD address. In this project I used 16x2 LCD.

#include <LiquidCrystal_I2C.h>

// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;

// set LCD address, number of columns and rows
// if you don't know your display address, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);

void setup(){
// initialize LCD
lcd.init();
// turn on LCD backlight
lcd.backlight();
}

void loop(){
// set cursor to first column, first row
lcd.setCursor(0, 0);
// print message
lcd.print("Hello, World!");
delay(1000);
// clears the display to print new message
lcd.clear();
// set cursor to first column, second row
lcd.setCursor(0,1);
lcd.print("Hello, World!");
delay(1000);
lcd.clear();
}

This code will display ‘Hello World’ In the first row for 1 second and then display another ‘Hello World’ in the second row for 1 second. If The LCD doesn’t display anything or it does displaying something but at a low contrast, we can tune the LCD contrast using the blue box in the I2C converter.

Blue Box in The I2C Converter to control contrast.

We can tune this box using a screwdriver to rotate it so we can add some contrast and see the text displayed. Here are my result in displaying Hello World on LCD.

Testing LCD using ESP32

Integrating Display with DHT11 Sensor

To Integrate the sensor with a display, we must know how the component communicates with each other. DHT11 uses GPIO to communicate, which is different from the LCD which uses I2C to communicate. First, let’s make a circuit like this.

Weather Station Board Layout with DHT11

Next, upload this code to initiate reading from the sensors and display it through LCD. In this project I used GPIO 4 as my DHTPIN and 0x27 as my LCD address that I got from my previous project.

#include "DHT.h"
#define DHTPIN 4
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
unsigned long delayTime;// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);void setup() {
// put your setup code here, to run once:
lcd.init();
lcd.backlight();
dht.begin();

}
void loop() {
// put your main code here, to run repeatedly:

delay(1000);
// Check if any reads failed and exit early (to try again).

printValues();
}
void printValues() {
lcd.setCursor(0,0);
lcd.print(F("Hum: "));
lcd.print(dht.readHumidity());
lcd.print(F(" %"));

lcd.setCursor(0,1);
lcd.print(F("Temp: "));
lcd.print(dht.readTemperature());
lcd.print(F(" *C "));
delay(2000);
lcd.clear();
}

In this code I create a new function called printValues to integrate dht readings and print it to LCD. Sometimes the LCD would display some unknown symbols. This indicates that the communications between components are faulty. In my case, I tried to change several cables and breadboard holes until the circuit works. Here are some readings from my project.

DHT Readings displayed on LCD

Integrating Display with BME280 Sensor

Next, I’m going to integrate LCD and BME280 sensors. These 2 component communicates using I2C, which mean we must use a different approach to make the circuit than the DHT11 sensors. Let’s make a circuit like this.

Weather Station Board Layout with BME280

If there are multiple devices connected using I2C communication, ESP32 distinguished the devices using their unique address. Therefore we must run the address checker code from the LCD section in this blog to get their address. In my project, I get 0x27 as my LCD address and 0x76 as my BME280 address. Here are my code.

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C
unsigned long delayTime;
// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;
// set LCD address, number of columns and rows
// if you don't know your display address, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);
void setup(){
// initialize LCD
lcd.init();
// turn on LCD backlight
lcd.backlight();
Serial.begin(9600);
Serial.println(F("BME280 test"));

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);
}
Serial.println("-- Default Test --");
delayTime = 1000;
Serial.println();
}
void loop(){
printValues();
delay(delayTime);
}
void printValues() {
lcd.setCursor(0,0);
lcd.print("Temp= ");
lcd.print(bme.readTemperature());
lcd.print(" *C");

lcd.setCursor(0,1);
lcd.print("Press= ");
lcd.print(bme.readPressure() / 100.0F);
lcd.print(" hPa");
delay(4000);

lcd.clear();

lcd.setCursor(0,0);
lcd.print("Alt= ");
lcd.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
lcd.print(" m");

lcd.setCursor(0,1);
lcd.print("Hum= ");
lcd.print(bme.readHumidity());
lcd.print(" %");
delay(4000);

lcd.clear();
}

In this program, I initiate a serial communication to my laptop to ease some debugging in case my cicuit or my program should fail. Here are some footage of BME280 readings.

BME280 Readings displayed on LCD

Conclusion

In this project, I learned various communication types like serial and I2C. Making the weather station is a bit tricky because of a lot of wiring and multiple components to connect with. The LCD that I used is also a bit disappointing because of its low contrast, I hardly see the displayed content. That’s it for this project, thank you for reading and see you on my next project!

--

--