Arduino Weather Station Project using DHT22, BMP180, MQ135 & 20x4 I2C LCD (Wokwi Simulation)

Arduino Weather Station with Multiple Sensors – Wokwi Tutorial | MakeMindz
🌦 Advanced IoT Project

Arduino Weather Station with Multiple Sensors

Measure temperature, humidity, rainfall, air quality, atmospheric pressure, and sunlight — all displayed live on a 20×4 I2C LCD. Fully simulated in Wokwi, no hardware needed.

🌡 DHT22 🔵 BMP180 💨 MQ-135 🌧 Rain Sensor ☀️ LDR 🖥 20×4 I2C LCD

🚀 No hardware? Simulate this entire weather station in your browser for free

▶ Open in Wokwi Simulator
📐

Project Overview

6Sensors Used
20×4I2C LCD Display
4LED Indicators
100msRefresh Rate

This advanced Arduino weather station integrates six environmental sensors into a single system. Each sensor feeds data to the Arduino Uno, which processes the readings and displays live values on all four rows of a 20×4 I2C LCD. LED indicators fire automatically when conditions cross alert thresholds.

🎓 Ideal For:
Engineering Mini Projects STEM Exhibitions Robotics Competitions IoT Learning Environmental Monitoring
🔧

Sensors & Components

🌡
DHT22
Temperature & Humidity
🔵
BMP180
Atmospheric Pressure
💨
MQ-135 (Gas Sensor)
Air Quality (AQI %)
🌧
Rain Sensor
Rain Detection YES/NO
☀️
LDR (Photoresistor)
Sunlight Intensity %
🖥
20×4 I2C LCD
Real-Time Display
Key Features
Multi-sensor environmental monitoring
Real-time display on 20×4 I2C LCD
Air quality % with safety level classification
Atmospheric pressure in hPa
Rain detection (digital HIGH/LOW)
Sunlight intensity monitoring
LED-based automatic alert indicators
Serial monitor debugging output
Fully simulated in Wokwi (free)
📟 Hardware Pin Assignments (Arduino Uno)
D5 — DHT22 Data
D8 — Rain Sensor
A0 — LDR (light)
A1 — MQ-135 (air)
A2 — Pressure pot
A4/A5 — SDA/SCL (LCD)
D1–D4 — LED indicators
🔗

Wiring Connections

All sensors connect through a breadboard to the Arduino Uno. Follow each table carefully. Resistors (220Ω) are required for all four LEDs.

DHT22 Temperature & Humidity Sensor
DHT22 PinArduino PinNotes
VCC5V (breadboard+)Power via breadboard
GNDGND (breadboard−)Ground via breadboard
DATAD5With 220Ω pull-up to VCC
MQ-135 Air Quality Gas Sensor
MQ-135 PinArduino PinNotes
VCC5VBreadboard power rail
GNDGNDBreadboard ground rail
AOUTA1Analog concentration reading
DOUTNot used in this sketch
LDR Photoresistor Sensor (Light Intensity)
LDR PinArduino PinNotes
VCC5VPower rail
GNDGNDGround rail
AOA0Analog light reading
Rain Sensor (Slide Switch in Wokwi)
Switch PinArduino PinNotes
Pin 1 (VCC)5V railPower
Pin 2 (SIG)D8Digital rain signal
Pin 3 (GND)GND railGround
Pressure Potentiometer (Simulating BMP180)
Pot PinArduino PinNotes
VCC5V railPower
GND (signal)A2Mapped 950–1050 hPa
20×4 I2C LCD Display
LCD PinArduino PinWire Color
VCC5V (breadboard) Red
GNDGND.3 Black
SDAA4 Gold
SCLA5 Blue
💡

LED Alert Indicators

Four LEDs (each with a 220Ω resistor) provide instant visual feedback when sensor readings cross alert thresholds. They connect via breadboard to Arduino digital pins 1–4.

Blue LED (D1)
Rain detected — activates when rain sensor reads HIGH
Red LED (D2)
Temperature alert — fires when temp > 35°C
Purple LED (D4)
Air quality warning — fires when air > 60%
Orange LED (D3)
Sunlight alert — fires when light intensity > 70%
Air Quality Classification
0–30%
Safe
31–60%
Moderate
61–100%
GET OUT!!
📋

Step-by-Step Build Guide

1
Open Wokwi & Create a New Arduino Project
Go to wokwi.com, click New Project, and select Arduino Uno as your board template.
💡 Use the Wokwi button at the top of this page to open a pre-loaded simulation if available.
2
Paste the diagram.json
Click the diagram.json tab and replace all content with the JSON from Step 6 below. This sets up all components — the Arduino, breadboard, all 6 sensors, 4 LEDs, resistors, and 20×4 LCD — with pre-wired connections.
💡 You won't need to drag or connect anything manually. All wiring paths are encoded in the JSON.
3
Install Required Libraries
This project needs three libraries. In Wokwi, add them in the Libraries panel. In the Arduino IDE, use Sketch → Manage Libraries:

LiquidCrystal_I2C by Frank de Brabander
DHT sensor library by Adafruit
Wire (built-in, no install needed)
⚠️ If the LCD stays blank, try changing 0x27 to 0x3F in the code.
4
Paste the Arduino Code
Open the sketch.ino tab and replace all content with the full code from Step 7. Verify that pin numbers (D5, D8, A0, A1, A2, A4, A5, D1–D4) match what's defined in the diagram.json.
5
Run the Simulation
Click the green ▶ Play button. The LCD will show the METEOSTAT splash screen for 2 seconds, then switch to live data. Four rows display: sunlight status, temperature, rain state, and air quality. Interact with the Wokwi sensor sliders to change readings in real time.
💡 Drag the slide potentiometer to simulate changing atmospheric pressure between 950–1050 hPa.
6
Monitor the Serial Output
Open the Serial Monitor (baud: 9600) at the bottom of Wokwi. All six readings are printed every 100ms — humidity, temperature, rain state, air quality level, pressure (hPa), and sunlight level with alert text.
7
Test the LED Alerts
In the Wokwi simulation, adjust the gas sensor slider above 60% to trigger the purple air LED. Increase the LDR slider above 70% for the orange sunlight LED. Toggle the slide switch to simulate rain (blue LED). Set the DHT22 temperature above 35°C for the red LED.
🗺

Wokwi diagram.json

Copy and paste this entire JSON into the diagram.json tab in Wokwi. It defines all components, positions, and every wiring connection.

📄 diagram.json
{
  "version": 1,
  "author": "MakeMindz",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-breadboard", "id": "bb1",
      "top": 93, "left": 434.8,
      "attrs": { "color": "#eeefed" }
    },
    { "type": "wokwi-arduino-uno", "id": "uno",
      "top": -143.4, "left": 719.4, "attrs": {} },

    { "type": "wokwi-led", "id": "led1",
      "top": 174.4, "left": 647.4, "rotate": 180,
      "attrs": { "color": "blue" }
    },
    { "type": "wokwi-led", "id": "led2",
      "top": 174.4, "left": 781.8, "rotate": 180,
      "attrs": { "color": "red" }
    },
    { "type": "wokwi-led", "id": "led4",
      "top": 174.4, "left": 906.6, "rotate": 180,
      "attrs": { "color": "purple" }
    },
    { "type": "wokwi-led", "id": "led5",
      "top": 174.4, "left": 1021.8, "rotate": 180,
      "attrs": { "color": "orange" }
    },
    { "type": "wokwi-bmp180", "id": "bmp1",
      "top": -68.265, "left": -184.791, "attrs": {} },
    { "type": "wokwi-lcd2004", "id": "lcd1",
      "top": -166.4, "left": 1080.8,
      "attrs": { "pins": "i2c" }
    },
    { "type": "wokwi-gas-sensor", "id": "gas1",
      "top": 219.4, "left": 493.7, "rotate": 270, "attrs": {} },
    { "type": "wokwi-dht22", "id": "dht1",
      "top": -76.5, "left": 465, "attrs": {} },
    { "type": "wokwi-photoresistor-sensor", "id": "ldr1",
      "top": 236.9, "left": 388.3, "rotate": 270, "attrs": {} },
    { "type": "wokwi-bmp180", "id": "bmp2",
      "top": -58.665, "left": -175.191, "attrs": {} },
    { "type": "wokwi-resistor", "id": "r2",
      "top": 167.45, "left": 977.8, "rotate": 180,
      "attrs": { "value": "220" }
    },
    { "type": "wokwi-resistor", "id": "r3",
      "top": 43.2, "left": 383.45, "rotate": 90,
      "attrs": { "value": "220" }
    },
    { "type": "wokwi-resistor", "id": "r4",
      "top": 167.15, "left": 739.2,
      "attrs": { "value": "220" }
    },
    { "type": "wokwi-resistor", "id": "r5",
      "top": 167.15, "left": 864,
      "attrs": { "value": "220" }
    },
    { "type": "wokwi-resistor", "id": "r6",
      "top": 167.15, "left": 604.8,
      "attrs": { "value": "220" }
    },
    { "type": "wokwi-bmp180", "id": "bmp3",
      "top": 18.135, "left": -98.391, "attrs": {} },
    { "type": "wokwi-slide-switch", "id": "sw1",
      "top": -34, "left": 627.1, "attrs": {} },
    { "type": "wokwi-slide-potentiometer", "id": "pot1",
      "top": 33.8, "left": 1122.2,
      "attrs": { "travelLength": "30" }
    },
    { "type": "wokwi-bmp180", "id": "bmp4",
      "top": -237.493, "left": 384.925, "attrs": {} }
  ],
  "connections": [
    [ "bb1:55t.c", "uno:1",     "violet", ["v-86.4","h48","v-220.8","h-67.2"] ],
    [ "bb1:62t.d", "bb1:tn.50", "black",  ["v0"] ],
    [ "bb1:43t.c", "uno:2",     "violet", ["v-86.4","h-172.8","v-220.8","h249.6"] ],
    [ "bb1:50t.c", "bb1:tn.40", "black",  ["v-48","h-9.6"] ],
    [ "bb1:30t.c", "uno:3",     "violet", ["v-76.8","h-57.6","v-240","h249.6"] ],
    [ "bb1:37t.d", "bb1:tn.30", "black",  ["v0"] ],
    [ "bb1:16t.c", "uno:4",     "violet", ["v-326.4","h326.4"] ],
    [ "bb1:23t.d", "bb1:tn.18", "black",  ["v0"] ],
    [ "lcd1:GND",  "uno:GND.3", "black",  ["h-19.2","v192","h0","v9.6","h-134.4"] ],
    [ "lcd1:VCC",  "bb1:tp.38", "red",    ["h-9.6","v211.3","h-19.2"] ],
    [ "dht1:VCC",  "bb1:tp.16", "red",    ["v48","h172.8"] ],
    [ "dht1:GND",  "bb1:tn.17", "black",  ["v28.8","h153.6"] ],
    [ "bb1:1t.c",  "bb1:tp.1",  "red",    ["v0"] ],
    [ "bb1:2t.a",  "bb1:tn.1",  "black",  ["v0"] ],
    [ "bb1:4t.a",  "uno:A0",    "white",  ["v-86.4","h441.6"] ],
    [ "bb1:3t.a",  "uno:6",     "violet", ["v-9.6","h57.6","v-192","h374.4"] ],
    [ "bb1:12t.a", "bb1:tn.9",  "black",  ["v0"] ],
    [ "bb1:13t.a", "bb1:tp.10", "red",    ["v-19.2","h9.6","v-19.2"] ],
    [ "bb1:10t.a", "uno:A1",    "white",  ["v-124.8","h384"] ],
    [ "sw1:1",     "bb1:tp.15", "red",    ["v0"] ],
    [ "sw1:2",     "uno:8",     "violet", ["v9.6","h144.1","v-86.4","h105.6"] ],
    [ "sw1:3",     "bb1:tn.15", "black",  ["v38.4","h-9.4","v76.8"] ],
    [ "pot1:VCC",  "bb1:tp.31", "red",    ["h-28.8","v-76.8","h-268.8"] ],
    [ "pot1:SIG",  "bb1:tn.48", "black",  ["h-67.2","v37.6","h-38.4"] ],
    [ "pot1:GND",  "uno:A2",    "white",  ["v0","h24.4","v-48","h-403.2"] ],
    [ "dht1:SDA",  "r3:1",      "red",    ["v9.6","h-57.5","v-38.4","h-19.2"] ],
    [ "r3:2",      "bb1:tp.16", "red",    ["h67.2","v-1.2","h0"] ],
    [ "dht1:SDA",  "uno:5",     "violet", ["v9.6","h316.9","v-86.4","h124.8"] ],
    [ "uno:5V",    "bb1:tp.28", "red",    ["v19.1","h-92.2"] ],
    [ "uno:GND.2", "bb1:tn.26", "black",  ["v38.3","h-130.5","v28.8"] ],
    [ "lcd1:SDA",  "uno:A4",    "gold",   ["h0"] ],
    [ "lcd1:SCL",  "uno:A5",    "blue",   ["h0"] ],
    [ "led1:A",    "bb1:22t.e", "",       ["$bb"] ],
    [ "led1:C",    "bb1:23t.e", "",       ["$bb"] ],
    [ "led2:A",    "bb1:36t.e", "",       ["$bb"] ],
    [ "led2:C",    "bb1:37t.e", "",       ["$bb"] ],
    [ "led5:A",    "bb1:61t.e", "",       ["$bb"] ],
    [ "led5:C",    "bb1:62t.e", "",       ["$bb"] ],
    [ "gas1:AOUT", "bb1:10t.e", "",       ["$bb"] ],
    [ "gas1:DOUT", "bb1:11t.e", "",       ["$bb"] ],
    [ "gas1:GND",  "bb1:12t.e", "",       ["$bb"] ],
    [ "gas1:VCC",  "bb1:13t.e", "",       ["$bb"] ],
    [ "ldr1:VCC",  "bb1:1t.e",  "",       ["$bb"] ],
    [ "ldr1:GND",  "bb1:2t.e",  "",       ["$bb"] ],
    [ "ldr1:DO",   "bb1:3t.e",  "",       ["$bb"] ],
    [ "ldr1:AO",   "bb1:4t.e",  "",       ["$bb"] ],
    [ "r2:1",      "bb1:61t.d", "",       ["$bb"] ],
    [ "r2:2",      "bb1:55t.d", "",       ["$bb"] ],
    [ "r4:1",      "bb1:30t.d", "",       ["$bb"] ],
    [ "r4:2",      "bb1:36t.d", "",       ["$bb"] ],
    [ "r5:1",      "bb1:43t.d", "",       ["$bb"] ],
    [ "r5:2",      "bb1:49t.d", "",       ["$bb"] ],
    [ "r6:1",      "bb1:16t.d", "",       ["$bb"] ],
    [ "r6:2",      "bb1:22t.d", "",       ["$bb"] ],
    [ "led4:A",    "bb1:49t.e", "",       ["$bb"] ],
    [ "led4:C",    "bb1:50t.e", "",       ["$bb"] ]
  ],
  "dependencies": {}
}
💻

Arduino Code (sketch.ino)

Paste this into the sketch.ino tab in Wokwi, or upload to your physical Arduino Uno.

⚙️ sketch.ino (Arduino / C++)
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>

// LCD: I2C address 0x27, 16 cols, 4 rows (20x4 mode)
LiquidCrystal_I2C lcd(0x27, 16, 4);

// Pin definitions
#define DHTPIN  5    // DHT22 data pin
#define RAINPIN 8    // Rain sensor (slide switch)
#define BARPIN  A2   // Pressure potentiometer
#define AIRPIN  A1   // MQ-135 air quality sensor
#define LDRPIN  A0   // LDR light sensor

#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

// LED alert pins
#define LedRain 1   // Blue  – rain detected
#define LedSun  2   // Orange – high sunlight
#define LedTemp 3   // Red   – high temperature
#define LedAir  4   // Purple – poor air quality

// Global variables
int temperature;
int humidity;
float lightPercent;
float airPercent;
float rain;
float pressure;
int   rainState;
int   barValue;
int   airValue;

void setup() {
  Serial.begin(9600);

  lcd.init();
  lcd.backlight();

  // Splash screen
  lcd.setCursor(4, 0); lcd.print("METEOSTAT");
  lcd.setCursor(2, 1); lcd.print("STEM UMSSN 2026");
  lcd.setCursor(4, 2); lcd.print("Team Xenodi");
  delay(2000);

  // Pin modes
  pinMode(LedRain, OUTPUT);
  pinMode(LedSun,  OUTPUT);
  pinMode(LedTemp, OUTPUT);
  pinMode(LedAir,  OUTPUT);
  pinMode(LDRPIN,  INPUT);
  pinMode(AIRPIN,  INPUT);
  pinMode(RAINPIN, INPUT);
  pinMode(BARPIN,  INPUT);

  dht.begin();
}

void loop() {

  // --- Read all sensors ---
  int rainState   = digitalRead(RAINPIN);
  int barRaw      = analogRead(BARPIN);
  int pressure    = map(barRaw, 0, 1023, 950, 1050);
  int airRaw      = analogRead(AIRPIN);
  int airPercent  = map(airRaw, 0, 1023, 0, 100);
  int lightRaw    = analogRead(LDRPIN);
  int lightPercent = map(lightRaw, 0, 1023, 0, 100);

  float temperature = dht.readTemperature();
  float humidity    = dht.readHumidity();

  // --- Serial monitor output ---
  Serial.print("Humidity: ");
  Serial.print((int)humidity);
  Serial.println("%");

  Serial.print("Temp: ");
  Serial.print((int)temperature);
  Serial.println("C");

  Serial.print("Rain: ");
  if (rainState == HIGH) {
    Serial.println("YES");
  } else {
    Serial.println("NO");
  }

  Serial.print("Air Quality: ");
  Serial.print((int)airPercent);
  Serial.print("%");
  if (airPercent < 30) {
    Serial.println(" Safe");
  } else if (airPercent < 60 && airPercent > 31) {
    Serial.println(" Moderate");
  } else if (airPercent < 100 && airPercent > 61) {
    Serial.println(" GET OUT!!");
  }

  Serial.print("Pressure: ");
  Serial.print(pressure);
  Serial.println("hPa");

  Serial.print("Sun: ");
  Serial.print((int)lightPercent);
  Serial.print("%");
  if (lightPercent < 30) {
    Serial.println(" SAFE");
  } else if (lightPercent < 60 && lightPercent > 31) {
    Serial.println(" MEDIUM");
  } else if (lightPercent < 100 && lightPercent > 61) {
    Serial.println(" TAKE COVER!!");
  }

  delay(100);

  // --- LCD display ---
  lcd.clear();

  // Row 0: Sunlight
  lcd.setCursor(0, 0);
  lcd.print("Sun: ");
  lcd.print((int)lightPercent);
  lcd.print("%");
  if (lightPercent < 30) {
    lcd.print(" SAFE");
  } else if (lightPercent < 60 && lightPercent > 31) {
    lcd.print(" MEDIUM");
  } else if (lightPercent < 100 && lightPercent > 61) {
    lcd.print(" TAKE COVER!!");
  }

  // Row 1: Temperature
  lcd.setCursor(0, 1);
  lcd.print("Temp: ");
  lcd.print((int)temperature);
  lcd.print("C");

  // Row 2: Rain status
  lcd.setCursor(0, 2);
  if (rainState == HIGH) {
    lcd.print("Rain: YES");
  } else {
    lcd.print("Rain: NO");
  }

  // Row 3: Air quality
  lcd.setCursor(0, 3);
  lcd.print("Air: ");
  lcd.print((int)airPercent);
  lcd.print("%");
  if (airPercent < 30) {
    lcd.print(" Safe");
  } else if (airPercent < 60 && airPercent > 31) {
    lcd.print(" Moderate");
  } else if (airPercent < 100 && airPercent > 61) {
    lcd.print(" GET OUT!!");
  }

  delay(100);

  // --- LED alert logic ---
  if (RAINPIN == HIGH) {                   // Blue: rain
    digitalWrite(LedRain, HIGH);
  } else {
    digitalWrite(LedRain, LOW);
  }
  if (airPercent > 60) {                  // Purple: air quality
    digitalWrite(LedAir, HIGH);
  } else {
    digitalWrite(LedAir, LOW);
  }
  if (temperature > 35) {               // Red: high temp
    digitalWrite(LedTemp, HIGH);
  } else {
    digitalWrite(LedTemp, LOW);
  }
  if (lightPercent > 70) {              // Orange: bright sun
    digitalWrite(LedSun, HIGH);
  } else {
    digitalWrite(LedSun, LOW);
  }
}
📌 Key Code Notes
  • map(raw, 0, 1023, 950, 1050) — converts potentiometer to hPa pressure range
  • map(raw, 0, 1023, 0, 100) — converts analog reads to 0–100% for air and light
  • 0x27 — default I2C LCD address; try 0x3F if the screen stays blank
  • dht.readTemperature() returns Celsius by default; pass true for Fahrenheit
  • delay(100) — 100ms refresh rate; increase to reduce LCD flicker
  • The splash screen (METEOSTAT) displays for 2 seconds on power-on before live data starts

🧪 Simulate the Full Weather Station Free

No Arduino, no breadboard, no wiring. Paste the JSON and code from this tutorial and run the entire weather station live in Wokwi.

▶ Launch Wokwi Simulator
✓ Free to use ✓ Adjustable sensor sliders ✓ Real-time serial monitor ✓ No downloads needed

Comments

try for free