// ============================================================
// SMART WEATHER STATION + AUTO VENTILATION
// Arduino UNO | Wokwi Simulation | MakeMindz Summer Course
// ============================================================
#include <DHT.h> // Temperature & humidity sensor library
#include <Wire.h> // I2C communication (for LCD)
#include <LiquidCrystal_I2C.h> // LCD display control
#include <Servo.h> // Servo motor control
// ── Pin definitions ──────────────────────────
#define DHT_PIN 7 // DHT22 data wire
#define DHT_TYPE DHT22
#define SERVO_PIN 9 // Servo PWM signal (~pin)
#define LED_GREEN 2 // Green status LED
#define LED_YELLOW 3 // Yellow status LED
#define LED_RED 4 // Red alarm LED
#define BUZZER_PIN 5 // Buzzer
#define BTN_PIN 6 // Push button for LCD screens
// ── Library objects ──────────────────────────
DHT dht(DHT_PIN, DHT_TYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2); // LCD at I2C address 0x27
Servo ventServo;
// ── State variables ──────────────────────────
float tempC = 0, humidity = 0, heatIndex = 0;
int ventAngle = 0, screen = 0;
bool alarmOn = false, blinkState = false, prevBtn = HIGH;
unsigned long lastRead = 0, lastBlink = 0, lastBuzz = 0, dbBtn = 0;
void setup() {
dht.begin();
lcd.init();
lcd.backlight();
ventServo.attach(SERVO_PIN);
ventServo.write(0); // Start with vent fully CLOSED
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_YELLOW, OUTPUT);
pinMode(LED_RED, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(BTN_PIN, INPUT_PULLUP); // Uses internal pull-up resistor
// Splash screen for 1.8 seconds
lcd.setCursor(2, 0); lcd.print("WeatherStation");
lcd.setCursor(3, 1); lcd.print("Auto Vent v1");
delay(1800);
lcd.clear();
// Boot LED test — light each LED one by one
digitalWrite(LED_GREEN, HIGH); delay(200);
digitalWrite(LED_YELLOW, HIGH); delay(200);
digitalWrite(LED_RED, HIGH); delay(200);
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_YELLOW, LOW);
digitalWrite(LED_RED, LOW);
}
void loop() {
unsigned long now = millis();
// ── Read sensor every 2 seconds (non-blocking) ──
if (now - lastRead >= 2000) {
lastRead = now;
float t = dht.readTemperature();
float h = dht.readHumidity();
if (!isnan(t) && !isnan(h)) {
tempC = t; humidity = h;
heatIndex = dht.computeHeatIndex(t, h, false);
}
// ── Smooth servo movement (5° per step) ──
int targetAngle = tempToVent(tempC);
if (ventAngle < targetAngle) ventAngle = min(ventAngle + 5, targetAngle);
else if (ventAngle > targetAngle) ventAngle = max(ventAngle - 5, targetAngle);
ventServo.write(ventAngle);
// ── Update LEDs ──
if (tempC < 28) {
digitalWrite(LED_GREEN, HIGH); digitalWrite(LED_YELLOW, LOW); digitalWrite(LED_RED, LOW);
alarmOn = false;
} else if (tempC < 35) {
digitalWrite(LED_GREEN, LOW); digitalWrite(LED_YELLOW, HIGH); digitalWrite(LED_RED, LOW);
alarmOn = false;
} else {
digitalWrite(LED_GREEN, LOW); digitalWrite(LED_YELLOW, LOW);
alarmOn = true;
}
// ── Refresh LCD ──
lcd.clear();
switch (screen) {
case 0: showScreenTemp(); break;
case 1: showScreenHeatIdx(); break;
case 2: showScreenVent(); break;
}
}
// ── Blink red LED every 300ms when alarm ──
if (alarmOn && now - lastBlink >= 300) {
lastBlink = now; blinkState = !blinkState;
digitalWrite(LED_RED, blinkState ? HIGH : LOW);
}
// ── Sound buzzer every 800ms when alarm ──
if (alarmOn && now - lastBuzz >= 800) {
lastBuzz = now;
tone(BUZZER_PIN, 1200, 120); // 1200Hz for 120ms
}
// ── Button: cycle LCD screens with debounce ──
bool btn = digitalRead(BTN_PIN);
if (prevBtn == HIGH && btn == LOW && now - dbBtn > 200) {
screen = (screen + 1) % 3; // Cycle: 0 → 1 → 2 → 0
dbBtn = now; lcd.clear();
}
prevBtn = btn;
delay(20);
}
// Maps temperature to vent angle using proportional control
int tempToVent(float t) {
if (t < 25.0) return 0; // Cool → CLOSED
if (t < 30.0) return map(t*10, 250, 300, 0, 60); // Warm → partial
if (t < 38.0) return map(t*10, 300, 380, 60, 160); // Hot → wide open
return 170; // Critical → FULLY open
}
// Screen 0: Temperature + Humidity bar
void showScreenTemp() {
lcd.setCursor(0, 0); lcd.print("Temp: "); lcd.print(tempC, 1); lcd.print("\xDFC");
lcd.setCursor(0, 1); lcd.print("Hum: "); lcd.print((int)humidity); lcd.print("%");
}
// Screen 1: Heat Index + comfort level
void showScreenHeatIdx() {
lcd.setCursor(0, 0); lcd.print("Heat Index:");
lcd.setCursor(0, 1);
if (heatIndex < 27) lcd.print("Comfort ");
else if (heatIndex < 32) lcd.print("Caution ");
else if (heatIndex < 41) lcd.print("Warning! ");
else lcd.print("DANGER!! ");
lcd.print(heatIndex, 1); lcd.print("\xDFC");
}
// Screen 2: Vent status + progress bar
void showScreenVent() {
int pct = map(ventAngle, 0, 170, 0, 100);
lcd.setCursor(0, 0); lcd.print("Vent: "); lcd.print(pct); lcd.print("% ");
lcd.setCursor(0, 1); lcd.print("[");
for (int i = 0; i < 12; i++) lcd.print(i < pct/9 ? "#" : "-");
lcd.print("]");
}