#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <Servo.h>
// ---------- PIN CONNECTIONS ----------
#define INDOOR_PIN 2
#define OUTDOOR_PIN 3
#define RAIN_PIN A0
#define DUST_PIN A1
#define BUZZER_PIN 8
#define SERVO_PIN 9
#define DHTTYPE DHT22
// ---------- THRESHOLDS ----------
const float HOT_TEMP = 30.0;
// Wokwi potentiometers simulate rain and dust.
// Rain: value below 500 = rain
// Dust: value above 700 = dust/storm
const int RAIN_THRESHOLD = 500;
const int DUST_THRESHOLD = 700;
// ---------- COMPONENTS ----------
DHT indoorDHT(INDOOR_PIN, DHTTYPE);
DHT outdoorDHT(OUTDOOR_PIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo windowServo;
// Servo positions
const int WINDOW_CLOSED = 0;
const int WINDOW_HALF = 45;
const int WINDOW_OPEN = 90;
int currentAngle = -1;
void setWindow(int angle) {
if (currentAngle != angle) {
currentAngle = angle;
windowServo.write(angle);
}
}
void setup() {
Serial.begin(9600);
indoorDHT.begin();
outdoorDHT.begin();
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
windowServo.attach(SERVO_PIN);
setWindow(WINDOW_CLOSED);
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("SMART WINDOW");
lcd.setCursor(0, 1);
lcd.print("Starting...");
delay(1500);
}
void loop() {
float indoor = indoorDHT.readTemperature();
float outdoor = outdoorDHT.readTemperature();
int rainValue = analogRead(RAIN_PIN);
int dustValue = analogRead(DUST_PIN);
// Check for invalid DHT readings
if (isnan(indoor) || isnan(outdoor)) {
setWindow(WINDOW_CLOSED);
digitalWrite(BUZZER_PIN, LOW);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("DHT READ ERROR");
lcd.setCursor(0, 1);
lcd.print("Window CLOSED");
Serial.println("DHT error - window closed");
delay(1000);
return;
}
bool rainDetected = (rainValue < RAIN_THRESHOLD);
bool dustDetected = (dustValue > DUST_THRESHOLD);
// ---------- MAIN CONTROL LOGIC ----------
// Priority 1: Dust/storm -> fully close
if (dustDetected) {
setWindow(WINDOW_CLOSED);
}
// Priority 2: Rain detected
else if (rainDetected) {
// Very hot inside + cooler outside -> half open
if (indoor > HOT_TEMP && outdoor < indoor) {
setWindow(WINDOW_HALF);
} else {
// All other rainy conditions -> fully close
setWindow(WINDOW_CLOSED);
}
}
// Priority 3: No rain and no dust -> temperature control
else {
if (indoor > HOT_TEMP && outdoor < indoor) {
setWindow(WINDOW_OPEN);
} else {
setWindow(WINDOW_CLOSED);
}
}
// Buzzer alerts for rain or dust/storm
if (rainDetected || dustDetected) {
digitalWrite(BUZZER_PIN, HIGH);
} else {
digitalWrite(BUZZER_PIN, LOW);
}
// ---------- LCD DISPLAY ----------
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("In:");
lcd.print(indoor, 1);
lcd.print(" Out:");
lcd.print(outdoor, 1);
lcd.setCursor(0, 1);
if (dustDetected) {
lcd.print("DUST: CLOSED");
} else if (rainDetected && currentAngle == WINDOW_HALF) {
lcd.print("RAIN: HALF OPEN");
} else if (rainDetected) {
lcd.print("RAIN: CLOSED");
} else if (currentAngle == WINDOW_OPEN) {
lcd.print("Window: OPEN");
} else {
lcd.print("Window: CLOSED");
}
// ---------- SERIAL MONITOR ----------
Serial.print("Indoor: ");
Serial.print(indoor, 1);
Serial.print(" C | Outdoor: ");
Serial.print(outdoor, 1);
Serial.print(" C | Rain ADC: ");
Serial.print(rainValue);
Serial.print(" | Dust ADC: ");
Serial.print(dustValue);
Serial.print(" | Servo: ");
Serial.print(currentAngle);
Serial.println(" degrees");
delay(1000);
}