/* 
  Kevin Setya Nugraha - 30 October 2023
  Project Demo at https://wokwi.com/projects/379964121870835713

  Link for Libraries used in this sketch
  1. LiquidCrystal_I2C - https://www.arduinolibraries.info/libraries/liquid-crystal-i2-c
  2. Button2 - https://github.com/LennartHennigs/Button2/tree/master
  3. ESPRotary - https://github.com/LennartHennigs/ESPRotary/tree/master

  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files. 
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

#include "Button2.h"
Button2 b;
#define BUTTON_PIN 2

#include "ESPRotary.h"
ESPRotary r;
#define ROTARY_PIN1 7
#define ROTARY_PIN2 6
#define CLICKS_PER_STEP 4
#define MIN_POS 0
#define MAX_POS 59
#define START_POS 0
#define INCREMENT 1   
int setValue;

byte setTimer = 1;
int setHour, setMinute, setSecond;
bool getReady, onResume;
String readyText, pausedText;

#define LED 4

unsigned long now = millis();
unsigned long lastTrigger = 0;
unsigned long previousMillis = 0;
const long interval = 1000;  // for countdown timer
const long interval2 = 200; // for each funciton


void setup() {
  Serial.begin(9600);
  lcd.init();
  // lcd.backlight();
  lcd.clear();

  r.begin(ROTARY_PIN1, ROTARY_PIN2, CLICKS_PER_STEP, MIN_POS, MAX_POS, START_POS, INCREMENT);
  r.setChangedHandler(rotate);
  r.setLowerOverflowHandler(lower);
  r.setUpperOverflowHandler(upper);
  r.retriggerEvent(false);

  b.begin(BUTTON_PIN);
  b.setTapHandler(click);

  pinMode(LED, OUTPUT);
}

void click(Button2& b) {
  setTimer++;
  lcd.clear();
  r.resetPosition();
}

void rotate(ESPRotary& r) {
  setValue = r.getPosition();
}

void upper(ESPRotary& r) {
  //  Serial.println("upper bound hit");
}

void lower(ESPRotary& r) {
  //  Serial.println("lower bound hit");
}

void loop() {
  now = millis();
  r.loop();
  b.loop();

  if (setTimer == 1) {                        // Hour Configuration
    if (now - previousMillis >= interval2) {
      hourConfig();
      previousMillis = now;
    }
  } else if (setTimer == 2) {                 // Minute Configuration
    if (now - previousMillis >= interval2) {
      minuteConfig();
      previousMillis = now;
    }
  } else if (setTimer == 3) {                 // Second Configuration
    if (now - previousMillis >= interval2) {
      secondConfig();
      previousMillis = now;
    }
  } else if (setTimer == 4) {                 // Decision to start
    if (now - previousMillis >= interval2) {
      isReady();
      previousMillis = now;
    }
  } else if (setTimer == 5) {                 // Time is running
    startTimer();  
  } else if (setTimer == 6) {                 // Time is Paused
    if (now - previousMillis >= interval2) {
      onPaused();
      previousMillis = now;
    }
  } else if (setTimer == 7) {                 // Resume or Restart?
    if (onResume) {
      setTimer = 5;
    } else {
      getReady = false;
      setTimer = 1;
    }  
  } 

}

void hourConfig() {
  lcd.setCursor(0,0);
  lcd.print("Set Hour");
  setHour = setValue;
  lcd.setCursor(14,0);
  lcd.print(DuaDigit(setHour) + " ");
}
void minuteConfig() {
  lcd.setCursor(0,0);
  lcd.print("Set Minute");
  setMinute = setValue;
  lcd.setCursor(14,0);
  lcd.print(DuaDigit(setMinute) + " ");
}
void secondConfig() {
  lcd.setCursor(0,0);
  lcd.print("Set Second");
  setSecond = setValue;
  lcd.setCursor(14,0);
  lcd.print(DuaDigit(setSecond) + " ");
}
void isReady() {
  lcd.setCursor(0,0);
  lcd.print("Start Timer?");
  if (setValue % 2 == 0) {
    readyText = ">YES  NO";
    getReady = true;
  } else {
    readyText = " YES >NO";
    getReady = false;
  }
  lcd.setCursor(0,1);
  lcd.print(readyText);
}
void startTimer() {
  if (getReady) {
    digitalWrite(LED, HIGH);
    if (now - previousMillis >= interval) {
      setSecond--;
      previousMillis = now;
    }
    if (setSecond < 0) {
      setSecond = 59;
      setMinute = setMinute - 1;
    }
    if (setMinute < 0) {
      setMinute = 59;
      setHour = setHour - 1;
    }
    lcd.setCursor(0,0);
    lcd.print(" REMAINING TIME ");
    lcd.setCursor(4,1);
    lcd.print(DuaDigit(setHour) + ":" + DuaDigit(setMinute) + ":" + DuaDigit(setSecond));
    if (setHour == 0 && setMinute == 0 && setSecond == 0) {
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("   TIME IS UP  ");
      digitalWrite(LED, LOW);
      delay(5000);
      lcd.clear();
      getReady = false;
      setTimer = 1;
    }
  } else {
    setTimer = 1;
  }
}
void onPaused() {
  digitalWrite(LED, LOW);
  lcd.setCursor(0,0);
  lcd.print("Paused, " + DuaDigit(setHour) + ":" + DuaDigit(setMinute) + ":" + DuaDigit(setSecond));
  if (setValue % 2 == 0) {
    pausedText = ">YES  NO";
    onResume = true;
  } else {
    pausedText = " YES >NO";
    onResume = false;
  }
  lcd.setCursor(0,1);
  lcd.print("Resume? " + pausedText);
}

String DuaDigit(int angka) {
  if (angka > 9) {
    return String(angka);
  } else {
    String tmp = " ";
    tmp.concat(angka);
    return tmp;
  }
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL
led1:A
led1:C
encoder1:CLK
encoder1:DT
encoder1:SW
encoder1:VCC
encoder1:GND