#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Keypad.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <ESP32Servo.h>
#include "RTClib.h"

// #include <Adafruit_GFX.h>
// #include <Adafruit_SSD1306.h>
// #include <Fonts/FreeSansBold9pt7b.h>
// #include <Fonts/Picopixel.h>
//#include <DS3231.h> //mengincludekan library DS3231
// #include <TimeLib.h>

LiquidCrystal_I2C lcd(0x27, 20, 4);
//RTC_DS1307 rtc; //wokwi
RTC_DS3231 rtc; // inisialisasi penggunaan i2c
Servo servoMotor;

const int ledHijau = 18;
const int ledMerah = 19;
const int HCSR_TRIG = 26;
const int HCSR_ECHO = 27;
const int Buzzer = 23;
const int tombol = 5;
int servoPin = 25; // select the input pin for Serv

float cm;
int currentPos;
int lastSecond, lastMinute, lastHour, nextUnix;

String pesan1= String("=====> ENTRY <=====");
String pesan2= String("PRESS GREEN BUTTON");
int detikDelay= int(180); //dalam detik
int statusTombol=0;
int derajatOpen=90; //sudut motor servo open
int derajatClose=0; //sudut motor servo Close

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] = { 12, 13, 14, 15 }; // Pins connected to C1, C2, C3, C4
uint8_t rowPins[ROWS] = { 32, 33, 34, 35 }; // Pins connected to R1, R2, R3, R4

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

// Adafruit_SSD1306 display(128, 64, &Wire, -1);

const char* ssid = "Hotspot L1";
const char* password = "pengumuman@#";
const char* mqtt_server = "test.mosquitto.org";

WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE  (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;

// =========================================================

void setup() {
  Serial.begin(9600);
  
  pinMode(ledMerah, OUTPUT);
  pinMode(ledHijau, OUTPUT);
  pinMode(Buzzer, OUTPUT);
  pinMode(HCSR_TRIG, OUTPUT);
  pinMode(HCSR_ECHO, INPUT);

  rtc.begin();
  servoMotor.attach(servoPin);
  servoMotor.write(0);
  pinMode(tombol, INPUT_PULLUP);

  setup_wifi();
  client.setServer(mqtt_server, 1883);
  // put your setup code here, to run once:
  Serial.println("Hello, UPB Library");
  DateTime now = rtc.now();
  nextUnix = now.unixtime() + detikDelay;
  // frontdisplay();

  Wire.begin(21, 22);
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);  lcd.print("UPB LIBRARY");
  lcd.setCursor(0, 1);  lcd.print("WELCOME");
  lcd.setCursor(0, 2);  lcd.print("SELAMAT DATANG");
  // lcd.setCursor(1, 3);  lcd.print("di Perpustakaan UPB");

  delay(2000);
}

void loop() {
  DateTime now = rtc.now();
  float distance = readDistanceCM();
  
//  if (!client.connected()) {
//    // reconnect();
//    digitalWrite(ledMerah, HIGH);
//    delay(50);
//    digitalWrite(ledHijau, HIGH);
//    delay(50);
//    // updatedisplay();
//  }
//  client.loop();

  
  if(digitalRead(tombol)==LOW){
    statusTombol=1;
  }else{
    statusTombol=0;
  }

  if(currentPos==derajatOpen){
    digitalWrite(ledHijau, LOW);
    digitalWrite(ledMerah, LOW);
  }
  else{
    digitalWrite(ledHijau, HIGH);
    digitalWrite(ledMerah, LOW);
  }

  if (now.unixtime() <= nextUnix) {
    
    if(distance>20 && distance<=50){
      Serial.print("JARAK : "); Serial.println(readDistanceCM());
      closeCurtain();
      updateDisplay(pesan2);
      statusTombol=0;
      // digitalWrite(ledHijau, LOW);
      // digitalWrite(ledMerah, HIGH);
      
    }else if(statusTombol==1){ //jika tombol ditekan / keypad diisi maka open
      Serial.println("Button pressed");
      // tone(Buzzer, 1915);
      // delay(15);
      
      nextUnix = now.unixtime() + detikDelay;
      // if (currentPos == 90){
      openCurtain();
            
      lcd.clear();
      updateDisplay(pesan1);
      
      // }
      statusTombol=0;
    }
    else {
      // tone(Buzzer, 1000);
      // digitalWrite(ledHijau, HIGH);
      // digitalWrite(ledMerah, LOW);
    }
    
  }else{
    if(statusTombol==1){ //jika tombol ditekan / keypad diisi maka open
      Serial.println("Button pressed");
      // tone(Buzzer, 1915);
      // delay(15);
      
      nextUnix = now.unixtime() + detikDelay;
      // if (currentPos == 90){
      openCurtain();
            
      lcd.clear();
      updateDisplay(pesan1);
      // printLocalTime();
      // }
      statusTombol=0;
    }else{
      closeCurtain();
      lcd.clear();
      updateDisplay(pesan2);
      // digitalWrite(ledHijau, LOW);
      // digitalWrite(ledMerah, HIGH);
      statusTombol=0;
     }
    
    
  }

  String p1=":";
  Serial.print("now " ); 
  Serial.print(now.unixtime()); 
  Serial.print(" close at "); 
  Serial.print(nextUnix); 
  Serial.print(" statusTombol "); 
  Serial.print(statusTombol); 
  Serial.print(" jarak "); 
  Serial.println(distance); 
}

// =========================================================
void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("Connected");
      // Once connected, publish an announcement...
      client.publish("/indobot/mqtt/jimin", "Indobot");
      // ... and resubscribe
      client.subscribe("/indobot/mqtt/jimin");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}


void openCurtain() {
  Serial.println("Opening the curtain");
  int pos = derajatOpen;
  servoMotor.write(pos);
  currentPos = pos;
  // Blynk.virtualWrite(V1, true);
}

void closeCurtain() {
  Serial.println("Closing the curtain");
  int pos = derajatClose;
  servoMotor.write(pos);
  currentPos = pos;
  // Blynk.virtualWrite(V1, false);
}

void clearDisplay(){
  lcd.setCursor(0, 0);  lcd.print("");
  lcd.setCursor(0, 1);  lcd.print("");
  lcd.setCursor(0, 2);  lcd.print("");
  lcd.setCursor(0, 3);  lcd.print("");
}

void updateDisplay(String pesan1){
  // String pesan1 = "";
  lcd.setCursor(0, 0);  lcd.print("WELCOME TO ");
  lcd.setCursor(0, 1);  lcd.print("UPB LIBRARY");
  lcd.setCursor(0, 2);  lcd.print(pesan1);
  lcd.setCursor(0, 3);  lcd.print("");
}

float readDistanceCM() {
  digitalWrite(HCSR_TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(HCSR_TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(HCSR_TRIG, LOW);
  int duration = pulseIn(HCSR_ECHO, HIGH);
  return duration * 0.034 / 2;
}


// https://www.youtube.com/watch?v=bwaIEtLUVKQ
GND5VSDASCLSQWRTCDS1307+