#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <IRremote.hpp>
#include <Keypad.h>
#include <Servo.h>
#include <DHT.h>
// ================== Pin Definitions ==================
#define EXIT_BUTTON_PIN 42
#define IR_RECV_PIN 2
#define BUZZER_PIN 7
#define SERVO_LEFT 3
#define SERVO_RIGHT 4
#define WINDOW_SERVO_PIN 44
#define PIR_IN_PIN 40
#define PIR_OUT_PIN 41
#define LED_IN_PIN 9
#define LED_OUT_PIN 10
#define COOLER_PIN 11
#define COOLER_ACTIVE_HIGH 1
#define RGB_R 45
#define RGB_G 46
#define RGB_B 47
#define HUMID_LED_PIN 5
#define TEMP_LED_PIN 6
#define DHT_PIN 12
#define DHT_TYPE DHT22
#define MQ2_PIN A0
#define MQ2_DIGITAL_PIN 53
#define LDR_PIN A1
// ================== Thresholds ==================
#define TEMP_ON_THRESHOLD 26.0
#define TEMP_OFF_THRESHOLD 25.0
#define TEMP_ALERT_THRESHOLD 40.0
#define HUM_HIGH_THRESHOLD 70.0
#define HUM_LOW_THRESHOLD 40.0
const int GAS_THRESHOLD = 600;
// ================== Timings ==================
const unsigned long SENSOR_INTERVAL = 1000;
const unsigned long FIRE_MIN_ALARM_TIME = 5000;
const unsigned long MQ_WARMUP_TIME = 20000;
const unsigned long GAS_STABLE_TIME = 3000;
const unsigned long SECURITY_BLINK_INTERVAL = 200;
const unsigned long PIR_REARM_MS = 4000;
const unsigned long SECURITY_RESET_GRACE = 3000;
const unsigned long SECURITY_RESET_CHECK = 4000;
const unsigned long MOTION_TIMEOUT = 30000;
const unsigned long TEMP_BLINK_INTERVAL = 90;
const unsigned long HUM_BLINK_INTERVAL = 120;
// ================== State Variables ==================
bool systemOn = false;
int peopleCount = 0;
bool intruderAlarm = false;
unsigned long intruderAlarmStart = 0;
bool fireAlert = false;
bool fireLatched = false;
unsigned long fireLatchStart = 0;
bool mqReady = false;
unsigned long mqWarmupStart = 0;
bool gasStable = false;
unsigned long gasStartTime = 0;
bool manualCoolerMode = false;
bool homeArmed = true;
unsigned long lastSensorRead = 0;
float temperature = 0;
float humidity = 0;
unsigned long lastMotionIn = 0;
unsigned long lastMotionOut = 0;
unsigned long lastSecBlink = 0;
bool secBlinkState = false;
unsigned long lastSuspicious = 0;
int outsideTriggers = 0;
int insideTriggers = 0;
bool manualWindowMode = false;
int manualWindowPos = 0;
byte lcdPage = 0;
unsigned long lcdPageUntil = 0;
const unsigned long PAGE_SHOW_MS = 5000;
// ================== Devices ==================
LiquidCrystal_I2C lcdSmall(0x27, 16, 2);
LiquidCrystal_I2C lcdBig(0x26, 20, 4);
Servo doorLeft, doorRight;
Servo windowServo;
DHT dht(DHT_PIN, DHT_TYPE);
// ================== IR Codes ==================
uint32_t POWER_CODE = 0x5DA2FF00;
uint32_t ZERO_CODE = 0x9768FF00;
uint32_t IR_COOLER_AUTO_CODE = 0xCF30FF00; // 1
uint32_t IR_COOLER_OFF_CODE = 0xE718FF00; // 2
uint32_t IR_COOLER_ON_CODE = 0x857AFF00; // 3
uint32_t IR_WIN_LEFT_CODE = 0x1FE0FF00; // LEFT
uint32_t IR_WIN_RIGHT_CODE = 0x6F90FF00; // RIGHT
uint32_t IR_PAGE1_CODE = 0xAD52FF00; //9
uint32_t IR_PAGE2_CODE = 0xEF10FF00; //4
// ================== Keypad ==================
const byte ROWS = 4, COLS = 4;
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {30, 31, 32, 33};
byte colPins[COLS] = {34, 35, 36, 37};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
String correctPassword = "7887";
String enteredPassword = "";
// ================== Matrix 4x4 ==================
int rowPinsLED[4] = {22, 23, 24, 25};
int colPinsLED[4] = {26, 27, 28, 29};
// ================== Logo Chars ==================
byte name1x6[] = { B10000, B10000, B10111, B10101, B10101, B10010, B10010, B11111 };
byte name0x6[] = { B00001, B00010, B00110, B01100, B01000, B01000, B11111, B10000 };
byte name0x7[] = { B11111, B00000, B00000, B00000, B00000, B00000, B11111, B00000 };
byte name0x8[] = { B10000, B01000, B01100, B00110, B00010, B00010, B11111, B00001 };
byte name1x7[] = { B01110, B11011, B11011, B01110, B00100, B00100, B00100, B11111 };
byte name1x8[] = { B00001, B01111, B11011, B11011, B01111, B00101, B00101, B11111 };
// ================== Startup Melody ==================
int melody[] = {392, 440, 523, 659, 784, 659, 523, 440, 392};
int duration[] = {180, 180, 200, 200, 250, 250, 250, 250, 400};
//Helper Funtions
void playIrSafeTone(unsigned f, unsigned d) {
IrReceiver.stop();
tone(BUZZER_PIN, f, d);
delay(d);
noTone(BUZZER_PIN);
IrReceiver.start();
}
void setStatusRGB(bool r, bool g, bool b) {
digitalWrite(RGB_R, r ? HIGH : LOW);
digitalWrite(RGB_G, g ? HIGH : LOW);
digitalWrite(RGB_B, b ? HIGH : LOW);
}
void setCoolerPower(bool on) {
#if COOLER_ACTIVE_HIGH
digitalWrite(COOLER_PIN, on ? HIGH : LOW);
#else
digitalWrite(COOLER_PIN, on ? LOW : HIGH);
#endif
}
int readLightLevelMode(int ldr) {
if (ldr < 30) return 0; // روز
if (ldr < 200) return 1; // غروب
if (ldr < 700) return 2; // شب
return 3; // تاریکی کامل
}
//LED Matrix Functions
const bool FLIP_H = false;
const bool FLIP_V = false;
inline int mapRow(int r) {
return FLIP_V ? (3 - r) : r;
}
inline int mapCol(int c) {
return FLIP_H ? (3 - c) : c;
}
void scanLedMatrixFrame(const bool frame[4][4], unsigned scanDelay = 2) {
for (int r = 0; r < 4; r++) {
int rr = mapRow(r);
digitalWrite(rowPinsLED[rr], HIGH);
for (int c = 0; c < 4; c++) {
int cc = mapCol(c);
digitalWrite(colPinsLED[cc], frame[r][c] ? LOW : HIGH);
}
delay(scanDelay);
digitalWrite(rowPinsLED[rr], LOW);
}
}
void initLedMatrix() {
for (int r = 0; r < 4; r++) {
pinMode(rowPinsLED[r], OUTPUT);
digitalWrite(rowPinsLED[r], LOW);
}
for (int c = 0; c < 4; c++) {
pinMode(colPinsLED[c], OUTPUT);
digitalWrite(colPinsLED[c], HIGH);
}
}
void clearLedMatrix() {
for (int r = 0; r < 4; r++) digitalWrite(rowPinsLED[r], LOW);
for (int c = 0; c < 4; c++) digitalWrite(colPinsLED[c], HIGH);
}
void playAccessDeniedMatrix(unsigned stepDelay = 50) {
const bool pattern[4][4] = {
{1, 0, 0, 1},
{0, 1, 1, 0},
{0, 1, 1, 0},
{1, 0, 0, 1}
};
unsigned long start = millis();
while (millis() - start < 800) {
scanLedMatrixFrame(pattern, 3);
}
clearLedMatrix();
}
void animateIntruderMatrix(unsigned long now) {
static const bool frames[3][4][4] = {
{
{0, 1, 1, 0},
{0, 1, 1, 0},
{1, 0, 0, 1},
{0, 1, 1, 0}
},
{
{0, 1, 1, 0},
{1, 0, 0, 1},
{0, 1, 1, 0},
{1, 0, 0, 1}
},
{
{1, 1, 1, 1},
{1, 0, 0, 1},
{1, 0, 0, 1},
{1, 1, 1, 1}
}
};
static byte currentFrame = 0;
static unsigned long lastChange = 0;
if (now - lastChange > 150) {
lastChange = now;
currentFrame = (currentFrame + 1) % 3;
}
scanLedMatrixFrame(frames[currentFrame], 2);
}
void playAccessGrantedMatrix() {
const bool frames[6][4][4] = {
{{1, 1, 1, 1}, {1, 0, 0, 1}, {1, 0, 0, 1}, {1, 1, 1, 1}},
{{0, 1, 1, 0}, {1, 0, 0, 1}, {1, 0, 0, 1}, {0, 1, 1, 0}},
{{0, 0, 0, 0}, {0, 1, 1, 0}, {0, 1, 1, 0}, {0, 0, 0, 0}},
{{0, 1, 1, 0}, {1, 0, 0, 1}, {1, 0, 0, 1}, {0, 1, 1, 0}},
{{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}},
{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}
};
for (int f = 0; f < 6; f++) {
unsigned long start = millis();
while (millis() - start < 180) {
scanLedMatrixFrame(frames[f], 3);
}
}
for (int k = 0; k < 4; k++) {
const bool allOn[4][4] = {
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}
};
unsigned long t = millis();
while (millis() - t < 60) scanLedMatrixFrame(allOn, 2);
clearLedMatrix();
delay(40);
}
clearLedMatrix();
}
//UI / Door Functions
void playStartupLogo() {
lcdSmall.clear();
lcdSmall.createChar(0, name0x6);
lcdSmall.createChar(1, name0x7);
lcdSmall.createChar(2, name0x8);
lcdSmall.createChar(3, name1x6);
lcdSmall.createChar(4, name1x7);
lcdSmall.createChar(5, name1x8);
IrReceiver.stop();
int hzPos = -3, lockPos = 16, textPos = 16;
unsigned long lastTone = millis();
int noteIndex = 0;
while (hzPos < 1 || lockPos > 6 || textPos > 9 || noteIndex < 9) {
lcdSmall.clear();
if (hzPos < 1) hzPos++;
lcdSmall.setCursor(hzPos, 0);
lcdSmall.print("H.Z");
if (lockPos > 6) lockPos--;
lcdSmall.setCursor(lockPos, 0);
lcdSmall.write(0); lcdSmall.write(1); lcdSmall.write(2);
lcdSmall.setCursor(lockPos, 1);
lcdSmall.write(3); lcdSmall.write(4); lcdSmall.write(5);
if (textPos > 9) textPos--;
lcdSmall.setCursor(textPos, 1);
lcdSmall.print("SYSTEM");
unsigned long now = millis();
if (noteIndex < 9 && now - lastTone > (unsigned long)duration[noteIndex]) {
tone(BUZZER_PIN, melody[noteIndex], duration[noteIndex]);
lastTone = now;
noteIndex++;
}
delay(90);
}
noTone(BUZZER_PIN);
IrReceiver.start();
lcdSmall.clear();
lcdSmall.setCursor(1, 0);
lcdSmall.print("H.Z");
lcdSmall.setCursor(5, 0);
lcdSmall.write(0); lcdSmall.write(1); lcdSmall.write(2);
lcdSmall.setCursor(5, 1);
lcdSmall.write(3); lcdSmall.write(4); lcdSmall.write(5);
lcdSmall.setCursor(9, 1);
lcdSmall.print("SYSTEM");
}
void openDoor() {
lcdSmall.clear();
lcdSmall.setCursor(2, 0);
lcdSmall.print("welcome");
playAccessGrantedMatrix();
playIrSafeTone(1000, 180);
playIrSafeTone(1200, 180);
for (int pos = 90; pos <= 180; pos += 3) {
doorLeft.write(pos);
doorRight.write(180 - pos);
delay(15);
}
delay(1500);
for (int pos = 180; pos >= 90; pos -= 3) {
doorLeft.write(pos);
doorRight.write(180 - pos);
delay(15);
}
}
void accessDeniedAlert() {
lcdSmall.clear();
lcdSmall.setCursor(2, 0);
lcdSmall.print("Your Password Is Incorrect");
playIrSafeTone(350, 200);
playIrSafeTone(300, 200);
playIrSafeTone(250, 250);
for (int k = 0; k < 2; k++)
playAccessDeniedMatrix(45);
}
void passwordEntryMode() {
lcdSmall.clear();
lcdSmall.setCursor(0, 0);
lcdSmall.print("ENTER YOUR PASSWORD:");
enteredPassword = "";
while (true) {
char key = keypad.getKey();
if (!key) continue;
if (key == '*') {
lcdSmall.setCursor(0, 1);
lcdSmall.print("CHECKING...");
delay(700);
if (enteredPassword == correctPassword) {
openDoor();
peopleCount++;
} else {
accessDeniedAlert();
}
break;
}
if (key == '#') {
enteredPassword = "";
lcdSmall.setCursor(0, 1);
lcdSmall.print(" ");
continue;
}
enteredPassword += key;
lcdSmall.setCursor(0, 1);
lcdSmall.print(enteredPassword);
}
lcdSmall.clear();
lcdSmall.noBacklight();
}
void handleExit() {
static bool lastButtonState = HIGH;
bool buttonState = digitalRead(EXIT_BUTTON_PIN);
if (buttonState == LOW && lastButtonState == HIGH) {
if (peopleCount > 0) {
peopleCount--;
lcdSmall.clear();
lcdSmall.setCursor(2, 0);
lcdSmall.print("EXIT");
playIrSafeTone(1000, 150);
playIrSafeTone(1200, 150);
for (int pos = 90; pos <= 180; pos += 3) {
doorLeft.write(pos);
doorRight.write(180 - pos);
delay(15);
}
delay(1000);
for (int pos = 180; pos >= 90; pos -= 3) {
doorLeft.write(pos);
doorRight.write(180 - pos);
delay(15);
}
} else {
lcdSmall.clear();
lcdSmall.setCursor(2, 0);
lcdSmall.print("NO ONE INSIDE");
playIrSafeTone(300, 300);
}
}
lastButtonState = buttonState;
}
//Climate / Fire / Cooler
void updateClimateSensorsAndAlerts() {
unsigned long now = millis();
if (now - lastSensorRead < SENSOR_INTERVAL) return;
lastSensorRead = now;
float t = dht.readTemperature();
float h = dht.readHumidity();
if (!isnan(t)) temperature = t;
if (!isnan(h)) humidity = h;
static unsigned long lastBlinkTemp = 0, lastBlinkHum = 0;
static bool blinkTempState = false, blinkHumState = false;
if (now - lastBlinkTemp >= TEMP_BLINK_INTERVAL) {
lastBlinkTemp = now;
blinkTempState = !blinkTempState;
}
if (now - lastBlinkHum >= HUM_BLINK_INTERVAL) {
lastBlinkHum = now;
blinkHumState = !blinkHumState;
}
if (temperature >= TEMP_ALERT_THRESHOLD) {
digitalWrite(TEMP_LED_PIN, blinkTempState ? HIGH : LOW);
analogWrite(BUZZER_PIN, 200);
} else {
digitalWrite(TEMP_LED_PIN, LOW);
}
if (humidity > HUM_HIGH_THRESHOLD) {
digitalWrite(HUMID_LED_PIN, blinkHumState ? HIGH : LOW);
if (peopleCount > 0)
analogWrite(BUZZER_PIN, blinkHumState ? 130 : 0);
else
analogWrite(BUZZER_PIN, 190);
} else {
digitalWrite(HUMID_LED_PIN, LOW);
if (temperature < TEMP_ALERT_THRESHOLD)
analogWrite(BUZZER_PIN, 0);
}
}
void updateFireAndGasSystem() {
unsigned long now = millis();
if (intruderAlarm) {
fireAlert = false; fireLatched = false;
setStatusRGB(0, 0, 0);
analogWrite(BUZZER_PIN, 0);
windowServo.write(0);
return;
}
int level = readLightLevelMode(analogRead(LDR_PIN));
if (level == 0) {
fireAlert = false; fireLatched = false;
setStatusRGB(0, 0, 0);
analogWrite(BUZZER_PIN, 0);
windowServo.write(0);
gasStable = false; gasStartTime = 0;
return;
}
if (!mqReady) {
if (now - mqWarmupStart < MQ_WARMUP_TIME) {
fireAlert = false; fireLatched = false;
setStatusRGB(0, 0, 0);
analogWrite(BUZZER_PIN, 0);
windowServo.write(0);
gasStable = false; gasStartTime = 0;
return;
}
mqReady = true;
}
bool gasDigital = (digitalRead(MQ2_DIGITAL_PIN) == LOW);
int mqAnalog = analogRead(MQ2_PIN);
bool gasDetectedNow = gasDigital && (mqAnalog > GAS_THRESHOLD);
if (gasDetectedNow) {
if (gasStartTime == 0) gasStartTime = now;
if (now - gasStartTime >= GAS_STABLE_TIME) gasStable = true;
} else {
gasStartTime = 0;
gasStable = false;
}
bool tempValid = !isnan(temperature);
bool humValid = !isnan(humidity);
bool smokeWithHeatOrDry =
gasStable && (
(tempValid && temperature > 40) ||
(humValid && humidity < HUM_LOW_THRESHOLD)
);
bool extremeFire =
tempValid && humValid &&
(temperature > 45 && humidity < 30);
bool fireConditionNow = smokeWithHeatOrDry || extremeFire;
if (fireConditionNow) {
if (!fireLatched) {
fireLatched = true;
fireLatchStart = now;
}
} else {
if (fireLatched && now - fireLatchStart >= FIRE_MIN_ALARM_TIME) {
fireLatched = false; fireAlert = false;
setStatusRGB(0, 0, 0);
analogWrite(BUZZER_PIN, 0);
windowServo.write(0);
return;
}
}
if (fireLatched) {
fireAlert = true;
windowServo.write(90);
bool blink = (now / 150) % 2;
setStatusRGB(blink, 0, 0);
analogWrite(BUZZER_PIN, blink ? 230 : 120);
return;
}
fireAlert = false; fireLatched = false;
setStatusRGB(0, 0, 0);
analogWrite(BUZZER_PIN, 0);
if (!manualWindowMode) windowServo.write(0);
else windowServo.write(manualWindowPos);
}
void autoCoolerControl() {
if (manualCoolerMode) return;
if (!systemOn || fireAlert) {
setCoolerPower(false);
return;
}
if (temperature > TEMP_ON_THRESHOLD) setCoolerPower(true);
else if (temperature < TEMP_OFF_THRESHOLD) setCoolerPower(false);
}
//Lights / Security
void autoLightControl() {
bool pirInState = (digitalRead(PIR_IN_PIN) == HIGH);
bool pirOutState = (digitalRead(PIR_OUT_PIN) == HIGH);
unsigned long now = millis();
int level = readLightLevelMode(analogRead(LDR_PIN));
if (pirInState) {
digitalWrite(LED_IN_PIN, HIGH);
lastMotionIn = now;
}
if (!pirInState && (now - lastMotionIn > MOTION_TIMEOUT))
digitalWrite(LED_IN_PIN, LOW);
if (level == 0) {
digitalWrite(LED_OUT_PIN, LOW);
return;
}
if (level == 1) {
if (homeArmed && pirOutState) {
digitalWrite(LED_OUT_PIN, secBlinkState ? HIGH : LOW);
lastMotionOut = now;
}
if (!pirOutState && (now - lastMotionOut > MOTION_TIMEOUT))
digitalWrite(LED_OUT_PIN, LOW);
return;
}
if (level >= 2) {
if (pirOutState) {
digitalWrite(LED_OUT_PIN, HIGH);
lastMotionOut = now;
}
if (!pirOutState && (now - lastMotionOut > MOTION_TIMEOUT))
digitalWrite(LED_OUT_PIN, LOW);
}
}
void updateSecuritySystem() {
if (!systemOn) return;
unsigned long now = millis();
if (now - lastSecBlink >= SECURITY_BLINK_INTERVAL) {
lastSecBlink = now;
secBlinkState = !secBlinkState;
}
int level = readLightLevelMode(analogRead(LDR_PIN));
bool pirOut = (digitalRead(PIR_OUT_PIN) == HIGH);
bool pirIn = (digitalRead(PIR_IN_PIN) == HIGH);
static unsigned long lastOutTrigTime = 0, lastInTrigTime = 0;
bool outTrigger = false;
bool inTrigger = false;
if (pirOut && (now - lastOutTrigTime > PIR_REARM_MS)) {
outTrigger = true;
lastOutTrigTime = now;
}
if (pirIn && (now - lastInTrigTime > PIR_REARM_MS)) {
inTrigger = true;
lastInTrigTime = now;
}
homeArmed = (peopleCount == 0);
if (level == 0) {
intruderAlarm = false;
outsideTriggers = 0;
setStatusRGB(0, 0, 0);
analogWrite(BUZZER_PIN, 0);
clearLedMatrix();
return;
}
if (level == 1) {
if (homeArmed && outTrigger) {
setStatusRGB(secBlinkState, secBlinkState, 0);
} else {
setStatusRGB(0, 0, 0);
}
return;
}
if (intruderAlarm) {
const unsigned long ALARM_DURATION = 5000;
if (now - intruderAlarmStart >= ALARM_DURATION) {
intruderAlarm = false;
outsideTriggers = 0;
analogWrite(BUZZER_PIN, 0);
setStatusRGB(0, 0, 0);
clearLedMatrix();
digitalWrite(LED_IN_PIN, LOW);
digitalWrite(LED_OUT_PIN, LOW);
return;
}
bool strobe = (now / 80) % 2;
setStatusRGB(strobe, 0, 0);
analogWrite(BUZZER_PIN, strobe ? 255 : 120);
digitalWrite(LED_IN_PIN, strobe);
digitalWrite(LED_OUT_PIN, strobe);
animateIntruderMatrix(now);
return;
}
if (level >= 2) {
if (outTrigger) {
outsideTriggers++;
lastSuspicious = now;
}
if (inTrigger) insideTriggers++;
if (now - lastSuspicious > 6000) {
outsideTriggers = 0;
}
if (homeArmed && outsideTriggers >= 3) {
intruderAlarm = true;
intruderAlarmStart = now;
return;
}
setStatusRGB(0, 0, 0);
}
}
//LCD Update
void updateMainLCD() {
static unsigned long lastRefresh = 0;
unsigned long now = millis();
if (now - lastRefresh < 1000) return;
lastRefresh = now;
if (lcdPage != 0 && now > lcdPageUntil) {
lcdPage = 0;
}
static String lastL0 = "", lastL1 = "", lastL2 = "", lastL3 = "";
String l0, l1, l2, l3;
if (lcdPage == 0) {
if (isnan(temperature) || isnan(humidity))
l0 = "Temp: --.-C Hum: --%";
else
l0 = "Temp:" + String(temperature, 1) + "C Hum:" + String((int)humidity) + "%";
l1 = "People: " + String(peopleCount);
l2 = "Window: ";
l2 += (fireAlert || manualWindowPos > 0) ? "OPEN" : "CLOSE";
int level = readLightLevelMode(analogRead(LDR_PIN));
if (level == 0) l3 = "DAY";
else if (level == 1) l3 = "SUNSET";
else if (level == 2) l3 = "NIGHT";
else l3 = "DARK";
}
else if (lcdPage == 1) {
int level = readLightLevelMode(analogRead(LDR_PIN));
l0 = "___SECURITY MODE___";
l1 = "LDR Level: " + String(level);
l2 = "Alarm: " + String(homeArmed ? "ARMED" : "DISARM");
l3 = " ";
}
else if (lcdPage == 2) {
int mqVal = analogRead(MQ2_PIN);
bool fireNow = fireAlert || fireLatched;
l0 = "___FIRE / GAS___";
l1 = "Fire: " + String(fireNow ? "YES" : "NO");
l2 = "Gas: " + String(mqVal);
bool homeSafe = !fireNow && !intruderAlarm;
l3 = "Home Safe: " + String(homeSafe ? "YES" : "NO");
}
while (l0.length() < 20) l0 += " ";
while (l1.length() < 20) l1 += " ";
while (l2.length() < 20) l2 += " ";
while (l3.length() < 20) l3 += " ";
l0 = l0.substring(0, 20);
l1 = l1.substring(0, 20);
l2 = l2.substring(0, 20);
l3 = l3.substring(0, 20);
if (l0 != lastL0) {
lastL0 = l0;
lcdBig.setCursor(0, 0);
lcdBig.print(l0);
}
if (l1 != lastL1) {
lastL1 = l1;
lcdBig.setCursor(0, 1);
lcdBig.print(l1);
}
if (l2 != lastL2) {
lastL2 = l2;
lcdBig.setCursor(0, 2);
lcdBig.print(l2);
}
if (l3 != lastL3) {
lastL3 = l3;
lcdBig.setCursor(0, 3);
lcdBig.print(l3);
}
}
void setup() {
mqWarmupStart = millis();
pinMode(BUZZER_PIN, OUTPUT);
pinMode(PIR_IN_PIN, INPUT);
pinMode(PIR_OUT_PIN, INPUT);
pinMode(EXIT_BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_IN_PIN, OUTPUT);
pinMode(LED_OUT_PIN, OUTPUT);
digitalWrite(LED_IN_PIN, LOW);
digitalWrite(LED_OUT_PIN, LOW);
pinMode(COOLER_PIN, OUTPUT);
setCoolerPower(false);
pinMode(TEMP_LED_PIN, OUTPUT);
pinMode(HUMID_LED_PIN, OUTPUT);
pinMode(MQ2_PIN, INPUT);
pinMode(MQ2_DIGITAL_PIN, INPUT_PULLUP);
pinMode(RGB_R, OUTPUT);
pinMode(RGB_G, OUTPUT);
pinMode(RGB_B, OUTPUT);
setStatusRGB(0, 0, 0);
initLedMatrix();
lcdBig.init();
lcdBig.backlight();
lcdSmall.init();
lcdSmall.backlight();
doorLeft.attach(SERVO_LEFT);
doorRight.attach(SERVO_RIGHT);
doorLeft.write(90);
doorRight.write(90);
windowServo.attach(WINDOW_SERVO_PIN);
windowServo.write(0);
dht.begin();
IrReceiver.begin(IR_RECV_PIN, ENABLE_LED_FEEDBACK);
lcdSmall.setCursor(0, 0);
lcdSmall.print("PRESS POWER...");
}
void loop() {
if (IrReceiver.decode()) {
uint32_t code = IrReceiver.decodedIRData.decodedRawData;
if (code == POWER_CODE) {
systemOn = !systemOn;
if (systemOn) {
playStartupLogo();
mqWarmupStart = millis();
mqReady = false;
gasStartTime = 0;
gasStable = false;
fireAlert = false;
} else {
lcdSmall.clear();
lcdSmall.print("SYSTEM OFF");
setStatusRGB(0, 0, 0);
analogWrite(BUZZER_PIN, 0);
clearLedMatrix();
setCoolerPower(false);
}
}
if (systemOn && code == ZERO_CODE) {
lcdSmall.backlight();
lcdSmall.clear();
lcdSmall.print("PASSWORD MODE");
delay(800);
passwordEntryMode();
}
if (systemOn) {
if (code == IR_COOLER_AUTO_CODE) manualCoolerMode = false;
else if (code == IR_COOLER_OFF_CODE) {
manualCoolerMode = true;
setCoolerPower(false);
}
else if (code == IR_COOLER_ON_CODE) {
manualCoolerMode = true;
setCoolerPower(true);
}
if (code == IR_WIN_LEFT_CODE) {
manualWindowMode = true;
manualWindowPos = 90;
windowServo.write(manualWindowPos);
}
if (code == IR_WIN_RIGHT_CODE) {
manualWindowMode = true;
manualWindowPos = 0;
windowServo.write(manualWindowPos);
}
if (code == IR_PAGE1_CODE) {
lcdPage = 1;
lcdPageUntil = millis() + PAGE_SHOW_MS;
lcdBig.clear();
}
if (code == IR_PAGE2_CODE) {
lcdPage = 2;
lcdPageUntil = millis() + PAGE_SHOW_MS;
lcdBig.clear();
}
}
IrReceiver.resume();
}
if (systemOn) {
handleExit();
updateClimateSensorsAndAlerts();
autoLightControl();
updateFireAndGasSystem();
updateSecuritySystem();
autoCoolerControl();
updateMainLCD();
}
}