Mini Weather Station with OLED Display on NodeMCU
Mini Weather Station with ESP8266, DHT22 & DS3231 RTC

Mini Weather Station with ESP8266, DHT22 & DS3231 RTC

01 Overview

We are building a Mini weather station to provide real-time environment information for a localized area, room or office. It continuously senses ambient temperature and humidity, providing immediate and accurate readings on an OLED display. Additionally, it has a precise real-time clock (RTC) that makes sure that time and date information is available even when the gadget loses power. It also has the potential to grow into an advanced smart home or IoT application in the future.

02 Hardware and Software Components

Gather everything below before you start.

Hardware Components

Component Description
ESP8266 NodeMCU Wi-Fi-capable microcontroller board used as the main controller
DHT22 Temperature and Humidity Sensor Measures ambient temperature and humidity
DS3231 RTC Module Keeps accurate time and date even when power is lost
LCD I2C Module 20x4 character display used in Version 2 of the build
OLED Display 0.96" display used in Version 1 of the build
Jumper Wires Used to connect all modules to the NodeMCU
Breadboard Used for prototyping the circuit

Software Tools

Software Version / Details
Arduino IDE Used to write and upload the firmware

03 Application Discussion

Here is what each component does and why it is part of this project.

ESP8266

The NodeMCU V1.0 (ESP8266) is a small IoT development platform that includes a Wi-Fi-capable microcontroller, a USB interface both for power and programming, a voltage regulator, a few GPIO pins that can be used to connect sensors and devices, a single ADC for analog input, built-in flash memory, and an integrated antenna for wireless communication.

ESP8266 12-E NodeMCU Kit pinout diagram gpios pins

DHT22

DHT22 temperature and humidity sensor

The DHT22 measures temperature and humidity with good accuracy and low power. It uses a single digital pin, making it easy to connect to a microcontroller like an Arduino or ESP8266. The DHT22 has three main parts: the humidity sensing component, the temperature sensing component, and a signal processing component that produces calibrated digital output. The DHT22 is often used in weather stations, smart homes, HVAC systems, and science/educational projects for monitoring the environment.

DS3231 RTC

DS3231 RTC module

The DS3231 is a digital real-time clock module that keeps accurate time and date even when the rest of the circuit loses power, thanks to its onboard battery backup. It communicates over I2C, making it simple to wire alongside other I2C devices such as the OLED or LCD display, and it is commonly used in weather stations, smart homes, HVAC systems, and educational projects that need reliable timekeeping.

LCD

20x4 LCD character module

A 20x4 LCD is a display module that can show 20 characters per line for a total of 4 lines, which makes it useful for applications that require more information to be displayed at once. It has a built-in HD44780-compatible controller, and uses a backlight which enhances visibility in low-light environments. It has an included I2C interface module so only two data lines for communication (SDA and SCL) together with Power and Ground are needed, which simplifies wiring connection.

OLED

0.96 inch OLED display module

The 0.96 inch OLED is a small and low-power display that can be used to display text, graphic images, or sensory data. This display uses organic light-emitting diode (OLED) technology, meaning each pixel emits its own light without needing a backlight. This also means it provides lots of contrast and rich colors, with low power, and wide viewing angles. It uses the SSD1306 driver chip that controls the operation of each of the pixels. It uses either I2C or serial (SPI) to communicate with the microcontroller (NodeMCU or Arduino). I2C is typically what is used, as it requires less wiring.

04 Hardware Setup

Wire the components to the board using the diagrams and tables below. There are two versions of this build: Version 1 uses the OLED display, and Version 2 uses the LCD display.

Version 1 (OLED)

Version 1 wiring diagram with OLED display
ESP8266 Pin Connects To
3V3 DHT VCC
GND DHT GND
D4 DHT DATA PIN
D2 (GPIO4) RTC SDA
D1 (GPIO5) RTC SCL
3V3 RTC VCC
GND RTC GND
D2 (GPIO4) OLED SDA
D1 (GPIO5) OLED SCL
3V3 OLED VCC
GND OLED GND

Summary:

  • D1 (GPIO5): SCL for both OLED and RTC
  • D2 (GPIO4): SDA for both OLED and RTC
  • D4 (GPIO2): Data for DHT22 sensor
  • 3V3 (or Vin): Power supply for all modules
  • GND: Common ground for all modules

Version 2 (LCD)

Version 2 wiring diagram with LCD display
ESP8266 Pin Connects To
3V3 DHT VCC
GND DHT GND
D4 DHT DATA PIN
D2 (GPIO4) RTC SDA
D1 (GPIO5) RTC SCL
3V3 RTC VCC
GND RTC GND
D2 (GPIO4) LCD SDA
D1 (GPIO5) LCD SCL
3V3 LCD VCC
GND LCD GND

Summary:

  • D1 (GPIO5): SCL for both LCD and RTC
  • D2 (GPIO4): SDA for both LCD and RTC
  • D4 (GPIO2): Data for DHT22 sensor
  • 3V3 (or Vin): Power supply for all modules
  • GND: Common ground for all modules

05 Software Setup

Since we make 2 versions of the project using the LCD and the OLED, we set it up in 2 different ways. Open the Arduino IDE, install the required libraries for your chosen version (Wire, Adafruit GFX, Adafruit SSD1306, DHT, and RTClib for Version 1 OLED; or Wire, LiquidCrystal_I2C, DHT, and RTClib for Version 2 LCD), then copy the matching sketch from the Code section below and upload it to your NodeMCU.

06 Code

Copy the sketch below for the version you are building. Read the Code Breakdown section to understand what each part does.

Version 1 Project Code (OLED)

Arduino / C++
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <RTClib.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define DHTPIN D4
#define DHTTYPE DHT22

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
DHT dht(DHTPIN, DHTTYPE);
RTC_DS3231 rtc;

const unsigned char temp_icon[] PROGMEM = {
  0x1c,0x00,0x22,0x02,0x2b,0x05,0x2a,0x02,0x2b,0x38,0x2a,0x60,0x2b,0x40,
  0x2a,0x40,0x2a,0x60,0x49,0x38,0x9c,0x80,0xae,0x80,0xbe,0x80,0x9c,0x80,
  0x41,0x00,0x3e,0x00
};
const unsigned char hum_icon[] PROGMEM = {
  0x04,0x00,0x04,0x00,0x0c,0x00,0x0e,0x00,0x1e,0x00,0x1f,0x00,0x3f,0x80,
  0x3f,0x80,0x7e,0xc0,0x7f,0x40,0xff,0x60,0xff,0xe0,0x7f,0xc0,0x7f,0xc0,
  0x3f,0x80,0x0f,0x00
};
const unsigned char heat_index_icon[] PROGMEM = {
  0x01,0x00,0x21,0x08,0x10,0x10,0x03,0x80,0x8c,0x62,0x48,0x24,0x10,0x10,
  0x10,0x10,0x10,0x10,0x48,0x24,0x8c,0x62,0x03,0x80,0x10,0x10,0x21,0x08,
  0x01,0x00,0x00,0x00
};

void setup() {
  Serial.begin(115200);
  Wire.begin(D2, D1);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  dht.begin();

  if (!rtc.begin()) {
    display.setCursor(0, 0);
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.println("RTC Error!");
    display.display();
    while (true);
  }

  delay(1500);
}

void loop() {
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float hi = dht.computeHeatIndex(t, h, false);
  DateTime now = rtc.now();

  if (isnan(h) || isnan(t)) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("Sensor Error!");
    display.display();
    delay(2000);
    return;
  }

  char timeBuf[9], dateBuf[11];
  sprintf(timeBuf, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
  sprintf(dateBuf, "%02d/%02d/%d", now.month(), now.day(), now.year());

  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);

  display.setCursor(0, 0);
  display.println("Mini");
  display.println("Weather");
  display.println("Station");

  display.setCursor(SCREEN_WIDTH - 6 * strlen(dateBuf), 0);
  display.print(dateBuf);
  display.setCursor(SCREEN_WIDTH - 6 * strlen(timeBuf), 9);
  display.print(timeBuf);

  display.drawBitmap(0, 30, temp_icon, 16, 16, SSD1306_WHITE);
  display.setCursor(19, 34);
  display.print("T:");
  display.print(t, 1); display.cp437(true); display.write(167); display.print("C");

  display.drawBitmap(0, 48, hum_icon, 11, 16, SSD1306_WHITE);
  display.setCursor(18, 50);
  display.print("H:");
  display.print(h, 0); display.print("%");

  display.drawBitmap(65, 48, heat_index_icon, 15, 16, SSD1306_WHITE);
  display.setCursor(83, 50);
  display.print("HI:");
  display.print(hi, 0);
  display.write(167); display.print("C");

  display.display();
  delay(1000);
}

Version 2 Project Code (LCD)

Arduino / C++
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <RTClib.h>

#define DHTPIN D4
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);

LiquidCrystal_I2C lcd(0x27, 20, 4);

RTC_DS3231 rtc;

char daysOfTheWeek[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

void setup() {
  Serial.begin(115200);
  Serial.println("NodeMCU Mini Weather Station with RTC Starting...");
  Serial.println("-------------------------------------------------");

  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Weather Station");
  lcd.setCursor(0, 1);
  lcd.print("Loading sensors...");
  delay(1000);

  dht.begin();
  Serial.println("DHT sensor initialized.");

  Serial.print("Initializing RTC... ");
  if (!rtc.begin()) {
    Serial.println("FAILED! Couldn't find RTC.");
    Serial.println("Please check RTC wiring (SDA to D2, SCL to D1, VCC/GND)");
    Serial.println("Also ensure the RTC module has a battery.");
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("RTC ERROR!");
    lcd.setCursor(0, 1);
    lcd.print("Check wiring/battery!");
    while (1);
  }
  Serial.println("SUCCESS! RTC found.");

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, time needs to be set!");
    lcd.setCursor(0, 2);
    lcd.print("RTC Lost Power!");
    lcd.setCursor(0, 3);
    lcd.print("Setting Time...");
    delay(2000);

    Serial.print("Setting RTC to compile time: ");
    DateTime compiled = DateTime(F(__DATE__), F(__TIME__));
    rtc.adjust(compiled);
    Serial.print(compiled.year(), DEC);
    Serial.print("/");
    Serial.print(compiled.month(), DEC);
    Serial.print("/");
    Serial.print(compiled.day(), DEC);
    Serial.print(" ");
    Serial.print(compiled.hour(), DEC);
    Serial.print(":");
    Serial.print(compiled.minute(), DEC);
    Serial.print(":");
    Serial.print(compiled.second(), DEC);
    Serial.println();

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("RTC Set! Re-upload");
    lcd.setCursor(0,1);
    lcd.print("with line commented");
    delay(5000);
  } else {
    Serial.println("RTC is running and time is preserved.");
  }

  Serial.println("Setup complete.");
  lcd.clear();
}

void loop() {
  delay(2000);

  DateTime now = rtc.now();

  if (now.year() < 2024) {
    Serial.println("RTC is not providing valid time (likely stuck on default).");
    Serial.println("Re-check setup errors or wiring.");
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("RTC NOT WORKING!");
    lcd.setCursor(0, 1);
    lcd.print("Check Serial/Wiring");
    delay(5000);
    return;
  }

  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float f = dht.readTemperature(true);

  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println("Error: Failed to read from DHT sensor!");
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("DHT Sensor Error!");
    lcd.setCursor(0, 1);
    lcd.print("Check wiring!");
    delay(3000);
    return;
  }

  float hif = dht.computeHeatIndex(f, h);
  float hic = dht.computeHeatIndex(t, h, false);

  lcd.clear();

  lcd.setCursor(0, 0);
  char dateBuffer[11];
  sprintf(dateBuffer, "%04d/%02d/%02d", now.year(), now.month(), now.day());
  lcd.print(dateBuffer);

  lcd.setCursor(0, 1);
  char timeBuffer[11];
  sprintf(timeBuffer, "%02d:%02d:%02d %s",
          now.hour(), now.minute(), now.second(), daysOfTheWeek[now.dayOfTheWeek()]);
  lcd.print(timeBuffer);

  lcd.setCursor(0, 2);
  lcd.print("T:");
  lcd.print(t, 1);
  lcd.print((char)223);
  lcd.print("C (");
  lcd.print(f, 1);
  lcd.print((char)223);
  lcd.print("F)");

  lcd.setCursor(0, 3);
  lcd.print("H:");
  lcd.print(h, 1);
  lcd.print(" %");
  lcd.print(" HI:");
  lcd.print(hic, 1);
  lcd.print((char)223);
  lcd.print("C");

  Serial.print("Local Time: ");
  Serial.print(now.year(), DEC);
  Serial.print("/");
  Serial.print(now.month(), DEC);
  Serial.print("/");
  Serial.print(now.day(), DEC);
  Serial.print(" (");
  Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
  Serial.print(") ");
  Serial.print(now.hour(), DEC);
  Serial.print(":");
  Serial.print(now.minute(), DEC);
  Serial.print(":");
  Serial.print(now.second(), DEC);
  Serial.println();

  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.print(" %\t");
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.print(" *C (");
  Serial.print(f);
  Serial.print(" *F)\t");
  Serial.print("Heat index: ");
  Serial.print(hic);
  Serial.print(" *C (");
  Serial.print(hif);
  Serial.println(" *F)");
  Serial.println("----------------------------------------");
}

07 Code Breakdown

Here is what each part of the code does.

Libraries

Library Purpose
Wire.h Handles I2C communication
Adafruit_GFX.h / Adafruit_SSD1306.h Drives the OLED display (Version 1)
LiquidCrystal_I2C.h Drives the 20x4 LCD over I2C (Version 2)
DHT.h Operates the DHT22 temperature and humidity sensor
RTClib.h Operates the DS3231 real-time clock module

Key Functions

setup()

This function runs once when the device starts. It sets up the display, sensor, and RTC. It also checks if the RTC is connected and working.

loop()

Continuously runs after setup. It reads temperature and humidity, gets the current date and time, calculates the heat index, and shows the values on the screen.

dht.readTemperature() and dht.readHumidity()

Gets live values from the DHT22. If it fails, it shows an error message.

dht.computeHeatIndex()

Computes how hot it actually feels by combining temperature and humidity.

rtc.now()

Reads the current time and date from the RTC for display on the screen. For this to return valid values, the DS3231 must have its time set at least once, otherwise it will output its default fallback date.

08 Testing and Calibration

During testing, we initially connected the power source to the 5V pin, but the system did not work properly. We found that the ESP8266 module (NodeMCU) is designed to run on 3.3V, not 5V.

  • To fix the issue, we transferred the power source from the 5V pin to the 3V3 (3.3V) pin on the ESP8266, and the device worked correctly.
  • After fixing the power issue, we tested the DHT22 sensor and RTC to make sure they displayed temperature, humidity, and time correctly.
  • We also checked if the display (OLED or LCD) was showing values clearly and updated in real-time.
  • Minor adjustments were done to sensor reading intervals and display formatting for better visibility and accuracy.
Final Adjustments:
  • Make sure all components are properly connected and not loose.
  • Ensure power supply is stable to avoid flickering or resetting.

09 System Demonstration

Mini Weather Station with OLED

Mini weather station with OLED display

Mini Weather Station with LCD

Mini weather station with LCD display

Video Demonstration

10 Conclusion

This tutorial demonstrates real-time environmental monitoring. First, the serial communication, I2C connections, OLED screen, DHT22 sensor, and RTC module are initialized. To identify and notify in the event that the RTC or sensor fails, it incorporates error handling. After obtaining temperature and humidity readings from the DHT22 sensor, the code computes the heat index, which is a measure of perceived heat. It simultaneously gets the current time and date from the RTC. Temperature, humidity, and heat index readings, along with a corresponding custom-drawn icon, are displayed on the OLED display along with a formatted mini weather station title and the current date and time. In addition to temperature and heat index readings, the Celsius degree symbol is shown. In a small and easy-to-use format, the display shows current weather and time information, updating every second.

11 References

  • ESP32/ESP8266: DHT Temperature and Humidity Readings in OLED Display
  • Weather station with OLED and WiFi - using ESP8266, OLED SSD1306, and sensors DHT11 or SHTC3
  • IoT Made Simple: Home Weather Station With NodeMCU and OLED

12 Project Authors

  • Glydelle Arellano
  • Arcel Alfaro

Quality Checked By

  • Elijah Joseph Orias
  • Lukie-Mar Lonzaga
  • Miles Darren Bagnol
Mini Weather Station with OLED Display on NodeMCU – CreateLabz
Dht22, Ds3231 rtc, Esp8266, Lcd 20x4, Nodemcu, Oled, Oled display, Rtc, Weather station

Leave a comment

All comments are moderated before being published