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

// Inisialisasi RTC DS3231
RTC_DS3231 rtc;

// Inisialisasi LCD 20x4 I2C
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Pengaturan untuk relay
const byte relayPins[4] = {5, 4, 3, 2};  // Pin untuk Relay 1, 2, 3, 4

// Pengaturan Keypad 4x4
const byte ROWS = 4; // 4 baris
const byte COLS = 4; // 4 kolom
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {13, 12, 11, 10};  // Pin yang terhubung ke baris keypad
byte colPins[COLS] = {9, 8, 7, 6};      // Pin yang terhubung ke kolom keypad

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

// Variabel untuk menyimpan waktu ON dan OFF untuk masing-masing relay
byte onHour[4] = {18, 0, 0, 0}; // Waktu ON default
byte onMinute[4] = {0, 0, 0, 0}; // Menit ON default
byte offHour[4] = {23, 0, 0, 0}; // Waktu OFF default
byte offMinute[4] = {0, 0, 0, 0}; // Menit OFF default

// Variabel untuk mengontrol waktu RTC
unsigned long previousMillis = 0;  // Variabel untuk menyimpan waktu sebelumnya
const long rtcInterval = 1000;  // Interval waktu pembacaan RTC dalam milidetik (1 detik)

// Variabel untuk menyimpan waktu sekarang
byte currentHour = 0;
byte currentMinute = 0;
byte currentSecond = 0;

void setup() {
  // Inisialisasi komunikasi serial
  Serial.begin(9600);
  
  // Inisialisasi RTC
  if (!rtc.begin()) {
    Serial.println(F("RTC tidak terdeteksi!"));
    while (1);
  }
  
  // Ambil waktu awal dari RTC
  DateTime now = rtc.now();
  currentHour = now.hour();
  currentMinute = now.minute();
  currentSecond = now.second();

  // Atur relay sebagai output dan matikan relay di awal
  for (int i = 0; i < 4; i++) {
    pinMode(relayPins[i], OUTPUT);
    digitalWrite(relayPins[i], HIGH);  // HIGH berarti relay mati (NO)
  }
  
  // Inisialisasi LCD
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print(F("Programmable Timer"));
  delay(2000);
  lcd.clear();
}

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

  // Update waktu dari RTC setiap interval
  if (currentMillis - previousMillis >= rtcInterval) {
    previousMillis = currentMillis;

    // Update waktu dari RTC
    DateTime now = rtc.now();
    currentHour = now.hour();
    currentMinute = now.minute();
    currentSecond = now.second();

    // Tampilkan waktu saat ini di LCD
    lcd.setCursor(0, 0);
    lcd.print(F("Time: "));
    if (currentHour < 10) lcd.print('0');
    lcd.print(currentHour);
    lcd.print(':');
    if (currentMinute < 10) lcd.print('0');
    lcd.print(currentMinute);
    lcd.print(':');
    if (currentSecond < 10) lcd.print('0');
    lcd.print(currentSecond);

    // Tampilkan pengaturan waktu ON/OFF relay
    for (int i = 0; i < 4; i++) {
      lcd.setCursor(0, i + 1);
      lcd.print(F("R"));
      lcd.print(i + 1);
      lcd.print(F(" ON "));
      if (onHour[i] < 10) lcd.print('0');
      lcd.print(onHour[i]);
      lcd.print(':');
      if (onMinute[i] < 10) lcd.print('0');
      lcd.print(onMinute[i]);
      
      lcd.print(F(" OFF "));
      if (offHour[i] < 10) lcd.print('0');
      lcd.print(offHour[i]);
      lcd.print(':');
      if (offMinute[i] < 10) lcd.print('0');
      lcd.print(offMinute[i]);
    }
  }

  // Cek apakah ada input dari keypad untuk mengubah waktu
  char key = keypad.getKey();
  if (key) {
    if (key == 'A') {
      setRelayTime(0);  // Atur waktu Relay 1
    } else if (key == 'B') {
      setRelayTime(1);  // Atur waktu Relay 2
    } else if (key == 'C') {
      setRelayTime(2);  // Atur waktu Relay 3
    } else if (key == 'D') {
      setRelayTime(3);  // Atur waktu Relay 4
    }
  }

  // Cek apakah waktunya untuk menghidupkan/mematikan relay
  for (int i = 0; i < 4; i++) {
    // Jika waktu sekarang sama dengan waktu ON relay, nyalakan relay
    if ((currentHour == onHour[i] && currentMinute == onMinute[i]) ||
        (currentHour > onHour[i] && currentHour < offHour[i]) ||
        (currentHour == offHour[i] && currentMinute < offMinute[i])) {
      digitalWrite(relayPins[i], LOW);  // Nyalakan relay
    }

    // Jika waktu sekarang sama dengan waktu OFF relay, matikan relay
    if (currentHour == offHour[i] && currentMinute == offMinute[i]) {
      digitalWrite(relayPins[i], HIGH);  // Matikan relay
    }
  }
}

void setRelayTime(int relayIndex) {
  // Fungsi untuk mengatur waktu ON/OFF relay melalui keypad
  byte hour, minute;
  
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(F("Set ON Time R"));
  lcd.print(relayIndex + 1);
  
  lcd.setCursor(0, 1);
  lcd.print(F("Hour: "));
  hour = getNumberInput();
  lcd.setCursor(0, 2);
  lcd.print(F("Minute: "));
  minute = getNumberInput();
  onHour[relayIndex] = hour;
  onMinute[relayIndex] = minute;
  
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(F("Set OFF Time R"));
  lcd.print(relayIndex + 1);
  
  lcd.setCursor(0, 1);
  lcd.print(F("Hour: "));
  hour = getNumberInput();
  lcd.setCursor(0, 2);
  lcd.print(F("Minute: "));
  minute = getNumberInput();
  offHour[relayIndex] = hour;
  offMinute[relayIndex] = minute;
  
  lcd.clear();
}

byte getNumberInput() {
  // Fungsi untuk mendapatkan input angka dari keypad
  byte num = 0;
  char key;
  while (true) {
    key = keypad.getKey();
    if (key >= '0' && key <= '9') {
      num = num * 10 + (key - '0');
      lcd.print(key);
    } else if (key == '#') {
      return num;
    }
  }
}
$abcdeabcde151015202530fghijfghij
GND5VSDASCLSQWRTCDS1307+
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module