//Header
#include <WiFi.h>
#include <DHT.h>
#include <Keypad.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>

//DHT(Tempearture & Humidity)
#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

//LED
#define REDPIN 2
#define YELPIN 14
#define GREPIN 27

//PIR Sensor
#define PIRPIN 12
bool pirTriggered = false;

//Buzzer
#define BUZPIN 5

//Dot Matrix
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4 
#define CLK_PIN 22    
#define DATA_PIN 23   
#define CS_PIN 21     
MD_Parola matrix = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

//Keypad Setting
const byte ROWS = 4; 
const byte COLS = 4; 
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowpins[ROWS] = {16, 17, 18, 19}; 
byte colpins[COLS] = {25, 26, 32, 33}; 

Keypad keypad = Keypad(makeKeymap(keys), rowpins, colpins, ROWS, COLS);

//Password setting
const String secretNum = "0712";
String inputNum = "";

//Timing Setting
unsigned long previousMillisDHT = 0;
unsigned long previousMillisPIR = 0;
unsigned long previousMillisKeypad = 0;
const long intervalDHT = 3000;
const long intervalPIR = 3000;
const long intervalKeypad = 300;

void setup() {
  Serial.begin(115200);
  dht.begin();

  // Initialize LED
  pinMode(REDPIN, OUTPUT);
  pinMode(YELPIN, OUTPUT);
  pinMode(GREPIN, OUTPUT); 

  // Initialize PIR sensor
  pinMode(PIRPIN, INPUT);

  // Initialize Buzzer
  pinMode(BUZPIN, OUTPUT);

  // Initialize Dot Matrix
  matrix.begin();
  matrix.setIntensity(0);  
  matrix.displayClear();
  displayMessage("Ready");

  Serial.println("System Ready.");
  delay(3000); //3 seconds delay
}

void loop() {
  unsigned long currentMillis = millis();

  // DHT sensor reading
  if(currentMillis - previousMillisDHT >= intervalDHT) {
    previousMillisDHT = currentMillis;
    float t = dht.readTemperature();
    float h = dht.readHumidity();
    if (isnan(t) || isnan(h)) {
      Serial.println("Failed to read DHT sensor.");
    } else {
      Serial.print("Temperature: ");
      Serial.print(t);
      Serial.print("*C / Humidity: ");
      Serial.print(h);
      Serial.println("%");

      // Control LEDs based on temperature and humidity
      if (t >= 50 && h >= 85) {
        digitalWrite(REDPIN, HIGH);
        digitalWrite(YELPIN, LOW);
        digitalWrite(GREPIN, LOW);
      } else if (t >= 35 && h >= 50) {
        digitalWrite(REDPIN, LOW);
        digitalWrite(YELPIN, HIGH);
        digitalWrite(GREPIN, LOW);
      } else {
        digitalWrite(REDPIN, LOW);
        digitalWrite(YELPIN, LOW);
        digitalWrite(GREPIN, HIGH);
      }
    }
  }

  // PIR sensor to detect human 
  if(currentMillis - previousMillisPIR >= intervalPIR) {
    previousMillisPIR = currentMillis;
    int pirState = digitalRead(PIRPIN);
    if (pirState == HIGH) {
      if (!pirTriggered) {
        Serial.println("Person detected.");
        pirTriggered = true;
      }
    } else {
      pirTriggered = false; 
      Serial.println("No person detected.");
    }
  }

  // Keypad reading
  if(currentMillis - previousMillisKeypad >= intervalKeypad) {
    previousMillisKeypad = currentMillis;
    char key = keypad.getKey();
    if (key) {
      Serial.print("Key Pressed: ");
      Serial.println(key);
      inputNum += key;
      Serial.println(inputNum);

      // If the input code matches the secret Number
      if (inputNum.length() == secretNum.length()) {
        if (inputNum == secretNum) {
          displayO(); 
          Serial.println("Password is Correct!");
          digitalWrite(BUZPIN, HIGH);
          delay(1000); 
          digitalWrite(BUZPIN, LOW);
          inputNum = ""; // If the password is correct, reset
        } else {
          displayX(); 
          inputNum = ""; 
          Serial.println("Password is Wrong.");
        }
      }
    }
  }
}

void displayMessage(const char* message) {
  matrix.displayClear();
  matrix.print(message);
  matrix.displayAnimate();
  delay(1000);
}

void displayO() {
  matrix.displayClear();
  matrix.print("O");
  matrix.displayAnimate();
  delay(1000);
  matrix.displayClear();
}

void displayX() {
  matrix.displayClear();
  matrix.print("X");
  matrix.displayAnimate();
  delay(1000);
  matrix.displayClear();
}
$abcdeabcde151015202530fghijfghij