#include <Key.h>
#include <Keypad.h>
#include <Wire.h>
#include <Servo.h>
#include <Bridge.h>
#include <BlynkSimpleYun.h>
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#define BLYNK_PRINT Serial
#define DHTPIN 5
#define DHTTYPE DHT11
#define Password_Length 6 
int BuzzerPin = 7; // Buzzer pin
int FlamePin = A2;   // Flame detector pin
int Flame = 0; // Value of flame detector if flame value is low something is on fire
int gasDetector = A1; // Gas detector pin
int gas = 0; // if gas is high value then gas detected.
int lightsensorPin = A0;    // photoresistor pin
int lightVal = 0;       // photoresistor value if value is high then it is dark
int MotionLED = 11; // LED pin for side LED
int BlueFrontLED = 12;
int RedFrontLED = 8; // RED LED Pin for front LED
int GreenFrontLED = 9; // Green LED pin for front LED
int motion = 24;          // pin for motion detector
int motionState = LOW; // set initial motion state to low before checking if there is motion
int MotionVal = 0; // Motion pin value
char auth[] = "hjI13Q9V--WS6Tu-KM0ExSAxihdXUHlv"; // Auth code for Blynk
const byte ROWS = 4; 
const byte COLS = 4; // Rows and cols for the pin pad
// Layout for keyboard
char hexaKeys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {47, 45, 43, 41}; // row pins for keypad
byte colPins[COLS] = {39, 37, 35, 33}; // collum pins for keypad
char UserInput[Password_Length]; 
char Password[Password_Length] = "1234#"; 
byte InputCount = 0;
bool PassCorrect;
char customKey;
SimpleTimer timer;
Servo myservo;
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27,16,2);


// initialise keypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

void MOTIONSENSOR () {
    Console.println("Motion detection has begun");
    MotionVal = digitalRead(motion); // Reads in value
    if (MotionVal == HIGH) // Motion detected
    {           
      digitalWrite(RedFrontLED, HIGH); // Turn on LED
      if (motionState == LOW) // check if state is low IE if state is high motion has already been detected.
      {
        Console.println("Motion detected!");
        motionState = HIGH; // Set state to high so when it loops back round if there is still motion this code wont rerun.
    }
  } 
  else // if no motion 
  {
    digitalWrite(RedFrontLED, LOW);
    if (motionState == HIGH) // checks if motion has been detected before no motion
    {
      Console.println("Motion ended!"); 
      motionState = LOW; // Motion has now ended set state to low
    }
  }
}
void LIGHTSENSOR () {
  Console.println("Checking light levels");
  lightVal = analogRead(lightsensorPin);   // read the value from the sensor 
  Console.print("light val = ");
  Console.println(lightVal);   // Print light value for debugging
  if(lightVal>=400)       // if value is above 400 then it is dark
  {
    digitalWrite(BlueFrontLED, HIGH); // turn on LED
    delay(1000);
  }
  else
  {
     digitalWrite(BlueFrontLED, LOW);  // turn off LED
  } 
}


BLYNK_WRITE(V3) // for opening and closing door in blynk
{
  myservo.write(param.asInt()); // changes servo direction within blynk to open and close door
}

void TEMPSENSOR()
{
  float humidity = dht.readHumidity();
  float temp = dht.readTemperature(); // Read humidity and temp

  if (isnan(humidity) || isnan(temp)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  Blynk.virtualWrite(V5, humidity);
  Blynk.virtualWrite(V6, temp); // Send temp and humidity values to blynk
}
void FIREDETECTION ()
{
  Flame = analogRead(FlamePin);
  if(Flame<500)  // if flame is less than 500 then something is on fire
  {
    digitalWrite(BuzzerPin, LOW);
    
  }
  else // nothing is on fire  
  {
    digitalWrite(BuzzerPin, HIGH);
  } 
}

void GASDETECTION ()
{
  gas = analogRead(gasDetector);
  if(gas>=450) // Gas Detected
  {
    digitalWrite(BuzzerPin, LOW);
  }
  else // No gas
  {
    digitalWrite(BuzzerPin, HIGH);
  } 
}
void clearData(){
  while(InputCount !=0)
  {
    UserInput[InputCount--] = 0; 
  }
  return;
  lcd.clear();
}

void KEYPADENTRY ()
{
  customKey = customKeypad.getKey();
  Console.println("Start the keypad!");
  lcd.setCursor(0,0);
  lcd.print("Enter Password:");
  Console.println("Enter Password:");
  if (customKey){
    UserInput[InputCount] = customKey; // adds user input to array
    lcd.setCursor(InputCount,1); 
    lcd.print(UserInput[InputCount]); 
    Console.println(UserInput[InputCount]);
    InputCount++; 
    }

  if(InputCount == Password_Length-1){
    lcd.clear();
    // Checks if user input matches password
    if(!strcmp(UserInput, Password)){ 
      digitalWrite(GreenFrontLED, HIGH); // turn on LED
      lcd.print("Correct");
      Console.println("Password Correct!");
      myservo.write(90); // change servo to 90 degrees open door
      delay(5000);
      digitalWrite(GreenFrontLED, LOW); // turn on LED
      myservo.write(0); // change servo back to 0 close door
      lcd.clear();
      }
    else{
      lcd.print("Incorrect");
      digitalWrite(RedFrontLED, HIGH); // turn on Red LED
      delay(1000);
      digitalWrite(RedFrontLED, LOW); // turn on Red LED
      } 
      lcd.clear();
    clearData();  
  }
}
void setup()
{
  Bridge.begin();
  Serial.begin(9600);
  Blynk.begin(auth); 
  pinMode(BuzzerPin,OUTPUT);
  pinMode(MotionLED, OUTPUT);
  pinMode(RedFrontLED, OUTPUT);
  pinMode(BlueFrontLED, OUTPUT);
  pinMode(GreenFrontLED, OUTPUT); // Set pins to output
  pinMode(motion, INPUT); // Set pin to input
  myservo.attach(2);
  myservo.write(0);//back to 0 degrees 
  dht.begin();
  lcd.init(); //initialize the lcd
  lcd.backlight(); //open the backlight 
  timer.setInterval(1000, KEYPADENTRY);
  timer.setInterval(1000, LIGHTSENSOR);
  timer.setInterval(10000, GASDETECTION);
  timer.setInterval(10000, FIREDETECTION);
  timer.setInterval(1000, TEMPSENSOR);
  timer.setInterval(1000, MOTIONSENSOR); // Checks each sensor for a set interval then checks the next one using timers.
}

void loop()
{
  timer.run(); // Starts the timer
  Blynk.run(); // Starts blynk
}
