#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <dht.h>
#include <Keypad.h>

const uint8_t ROWS = 4;
const uint8_t COLS = 4;
char keys[ROWS][COLS] = {
  { '1', '2', '3', 'A' },
  { '4', '5', '6', 'B' },
  { '7', '8', '9', 'C' },
  { '*', '0', '#', 'D' }
};

uint8_t colPins[COLS] = { 3, 2, 1, 0 }; // Pins connected to C1, C2, C3, C4
uint8_t rowPins[ROWS] = { 7, 6, 5, 4 }; // Pins connected to R1, R2, R3, R4

Keypad keyboard = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

int alarmHour;
int alarmMinute;
int alarmStatus; //1 is for ON, 0 is for OFF

LiquidCrystal_I2C lcd(0x27, 20, 4);
RTC_DS1307 rtc;
DateTime now;
dht DHT;

#define DHT22_PIN 19

char daysOfTheWeek[7][10] = {"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"};

#define redLED 11
#define greenLED 12

#define setTimer A0
#define onTimer A1
#define offTimer A2

#define buzzer 13

void systemMalfunction(){
  lcd.clear();
  lcd.print("SYSTEM MALFUNCTION!");
  lcd.setCursor(0, 1);
  lcd.print("Check all connection");
  lcd.setCursor(0, 2);
  lcd.print("If not fixed,");
  lcd.setCursor(0, 3);
  lcd.print("replace a new one!");

  digitalWrite(redLED, LOW);
  digitalWrite(greenLED, LOW);

  int a = 0;
  do{
  }while(a == 0);
}

void rtcNotOK(){
  lcd.clear();
  lcd.print("RTC Error!");
  lcd.setCursor(0, 1);
  lcd.print("Check the connection");
  lcd.setCursor(0, 2);
  lcd.print("If not fixed,");
  lcd.setCursor(0, 3);
  lcd.print("replace a new one!");

  digitalWrite(redLED, LOW);
  digitalWrite(greenLED, LOW);

  int a = 0;
  do{
  }while(a == 0);
}

void dhtNotOK(){
  lcd.clear();
  lcd.print("DHT Error!");
  lcd.setCursor(0, 1);
  lcd.print("Check the connection");
  lcd.setCursor(0, 2);
  lcd.print("If not fixed,");
  lcd.setCursor(0, 3);
  lcd.print("replace a new one!");

  digitalWrite(redLED, LOW);
  digitalWrite(greenLED, LOW);

  int a = 0;
  do{
  }while(a == 0);
}

void soundAlarm() {
  tone(buzzer, 330);
  delay(150);
  tone(buzzer, 392);
  delay(150);
  tone(buzzer, 659);
  delay(150);
  tone(buzzer, 523);
  delay(150);
  tone(buzzer, 597);
  delay(150);
  tone(buzzer, 784);
  delay(150);
  noTone(buzzer);
  delay(500);
}




void setup() {

  lcd.init();
  lcd.backlight();

  rtc.begin();
  now = rtc.now();

  alarmHour = 15;
  alarmMinute = 0;
  alarmStatus = 1;

  pinMode(redLED, OUTPUT);
  pinMode(greenLED, OUTPUT);

  pinMode(setTimer, INPUT);
  pinMode(onTimer, INPUT);
  pinMode(offTimer, INPUT);

  pinMode(buzzer, OUTPUT);

  digitalWrite(greenLED, HIGH);
  digitalWrite(redLED, HIGH);

}

void update_screen()
{
  /*------------------------------------- ROW 1 ----------------------------------------*/
  lcd.setCursor(0, 0);

  lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
  lcd.print(" ");
  if(now.month() < 10){
    lcd.print(0);
  }
  lcd.print(now.month());
  lcd.print('/');
  if(now.day() < 10){
    lcd.print(0);
  }
  lcd.print(now.day());
  lcd.print('/');
  lcd.print(now.year()); 
  lcd.print("  ");

/*------------------------------------- ROW 2 ----------------------------------------*/
  lcd.setCursor(0, 1);

  int hour = now.hour();
  if(hour < 10){
    lcd.print(0); 
  }
  lcd.print(hour);
  lcd.print(':');

  int minute = now.minute();
  if(minute < 10){
    lcd.print(0);
  }
  lcd.print(minute);
  lcd.print(':');

  int second = now.second();
  if(second < 10){
    lcd.print(0);
  }
  lcd.print(second);

/*------------------------------------- ROW 3 ----------------------------------------*/




/*------------------------------------- ROW 4 ----------------------------------------*/
  lcd.setCursor(0, 3);

  DHT.read22(DHT22_PIN);

  lcd.print(DHT.temperature, 1);
  lcd.print((char)223);//For degree symbol
  lcd.println('C');

  lcd.print(DHT.humidity, 1);
  lcd.print('%');
}

void screen()
{
  /*------------------------------------- ROW 1 ----------------------------------------*/
  lcd.setCursor(0, 0);

  lcd.print(daysOfTheWeek[now.dayOfTheWeek()]);
  lcd.print(" ");
  if(now.month() < 10){
    lcd.print(0);
  }
  lcd.print(now.month());
  lcd.print('/');
  if(now.day() < 10){
    lcd.print(0);
  }
  lcd.print(now.day());
  lcd.print('/');
  lcd.print(now.year()); 
  lcd.print("  ");

/*------------------------------------- ROW 2 ----------------------------------------*/
  lcd.setCursor(0, 1);

  int hour = now.hour();
  if(hour < 10){
    lcd.print(0); 
  }
  lcd.print(hour);
  lcd.print(':');

  int minute = now.minute();
  if(minute < 10){
    lcd.print(0);
  }
  lcd.print(minute);
  lcd.print(':');

  int second = now.second();
  if(second < 10){
    lcd.print(0);
  }
  lcd.print(second);

/*------------------------------------- ROW 3 ----------------------------------------*/
  lcd.setCursor(0, 2);

  if(alarmHour < 10){
    lcd.print(0);
  }
  lcd.print(alarmHour);
  lcd.print(':');

  if(alarmMinute < 10){
    lcd.print(0);
  }
  lcd.print(alarmMinute);
  lcd.print(' ');

  if(alarmStatus == 1){
    digitalWrite(redLED, HIGH);
    lcd.print("ON ");
  }else if(alarmStatus == 0){
    digitalWrite(redLED, LOW);
    lcd.print("OFF");
  }

/*------------------------------------- ROW 4 ----------------------------------------*/
  lcd.setCursor(0, 3);

  DHT.read22(DHT22_PIN);

  lcd.print(DHT.temperature, 1);
  lcd.print((char)223);//For degree symbol
  lcd.println('C');

  lcd.print(DHT.humidity, 1);
  lcd.print('%');
}


void loop() {
   
  screen();

  if(DHT.read22(DHT22_PIN) != DHTLIB_OK && ! rtc.begin())
  {
    systemMalfunction();
  }
  else if(DHT.read22(DHT22_PIN) != DHTLIB_OK)
  {
    dhtNotOK();
  }
  else if(! rtc.begin())
  {
    rtcNotOK();
  }

/*----------------------------------- Button Check --------------------------------------*/
  if(digitalRead(setTimer) == 0){
    tone(buzzer, 750, 10);
    update_screen();
    lcd.setCursor(0, 2);
    alarmHour = hours();
    alarmMinute = minutes();
    int dowhile = 0;
    while(dowhile == 0)
    {
      char KEY = keyboard.getKey();
      if(KEY == 'A')
      {
        tone(buzzer, 500, 10);
        dowhile = 1;
        lcd.clear();
      }
    }
  }

  if(digitalRead(onTimer) == 0){
    tone(buzzer, 1000, 10);
    alarmStatus = 1;
  }

  if(digitalRead(offTimer) == 0){
    tone(buzzer, 500, 10);
    alarmStatus = 0;
  }

  if(alarmHour == now.hour() && alarmMinute == now.minute() && alarmStatus == 1){
    soundAlarm();
  }

  now = rtc.now();
}



/*------------------------------- Alarm Time Input Functions -------------------------------*/

int hours(){

  int hours = 0;
  int timerHour = 0;
  
  lcd.setCursor(0, 2);

  lcd.print("Alarm Time: ");
  lcd.setCursor(14, 2);
  lcd.print(":");
  lcd.setCursor(12, 2);

  int a = 0;
  while(a == 0)
  {
    char KEY = keyboard.getKey();
    if(KEY == '0' || KEY == '1' || KEY == '2')
    {
      lcd.print(KEY);
      hours = KEY - 48;
      tone(buzzer, 1000, 10);       
      a = 1;
    }
  }

  timerHour = hours * 10;
  hours = 0;

  a = 0;
  while(a == 0)
  {
    char KEY = keyboard.getKey();
    if(timerHour == 20)
    {
      if(KEY == '0' || KEY == '1' || KEY == '2' || KEY == '3')
      {     
        lcd.print(KEY);
        hours = KEY - 48;
        tone(buzzer, 1000, 10);
        a = 1;
      }
    }
    else
    {
      if(KEY != NULL)
      {
        if(isdigit(KEY))
        {
          tone(buzzer, 1000, 10);
          lcd.print(KEY);
          hours = KEY - 48;
          a = 1;
        } 
      }
    } 
  }

  timerHour = timerHour + hours;
  return timerHour;
}

int minutes(){
  int minutes = 0;
  int timerMinutes = 0;

  lcd.setCursor(15, 2);

  int a = 0;
  while(a == 0)
  {
    char KEY = keyboard.getKey();
    if(KEY == '0' || KEY == '1' || KEY == '2' || KEY == '3' || KEY == '4' || KEY == '5')
    {
      lcd.print(KEY);
      minutes = KEY - 48;
      tone(buzzer, 1000, 10);
      a = 1;
    }
  }

  timerMinutes = minutes * 10;
  minutes = 0;

  a = 0;
  while(a == 0){
    char KEY = keyboard.getKey();
    if(KEY != NULL)
    {
      if(isdigit(KEY))
      {
        lcd.print(KEY);
        minutes = KEY - 48;
        tone(buzzer, 1000, 10);
        a = 1;
      }
    }
  }

  timerMinutes = timerMinutes + minutes;
  
  return timerMinutes;
}
GND5VSDASCLSQWRTCDS1307+