#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <HX711.h>
#include <ESP32Servo.h>
// Inisialisasi LCD I2C
LiquidCrystal_I2C lcd(0x27, 16, 2); // Alamat I2C LCD bisa bervariasi (0x27 atau 0x3F)
// Servo setup
#define SERVO_PIN 15 
Servo servoMotor;
int servoOpenAngle = 0;
int servoCloseAngle = 90;
// Konfigurasi keypad 4x4
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {23, 19, 18, 5}; // Pin GPIO untuk baris
byte colPins[COLS] = {17, 16, 4, 2};  // Pin GPIO untuk kolom
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// Inisialisasi HX711 untuk loadcell
#define DT 25 // Data pin HX711
#define SCK 26 // Clock pin HX711
HX711 scale;
float target = 0; // Variabel target berat
bool loadcellActive = false;
// Faktor kalibrasi yang dihitung berdasarkan perbandingan antara berat sebenarnya dan yang terukur
float calibrationFactor = 4.2; // 0.8 kg / 2.41 kg
void setup() {
  Serial.begin(115200); // Debugging
  servoMotor.attach(SERVO_PIN);
  servoMotor.write(servoCloseAngle); // Start with closed position
  Serial.println("Servo Initialized");
  // Inisialisasi LCD
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("ATM BERAS");
  lcd.setCursor(0,1);
  lcd.print("Al-Mu'minun");
  
  delay(3000);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Masukan KG:");
  // Inisialisasi HX711
  scale.begin(DT, SCK);
  scale.set_scale(calibrationFactor); // Set nilai kalibrasi awal yang mendekati
  scale.tare(); // Kalibrasi awal (menghilangkan berat beban awal)
}
void loop() {
  static String inputBuffer = "";
  char key = keypad.getKey();
  if (!loadcellActive) {
    if (key) {
      if (key >= '0' && key <= '9') {
        // Menambahkan angka ke buffer input
        inputBuffer += key;
        lcd.setCursor(0, 1);
        lcd.print(inputBuffer);
      } else if (key == '#') {
        // Konfirmasi input target
        target = inputBuffer.toFloat();
        inputBuffer = "";
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Mengambil ");
        lcd.print(target);
        lcd.print("kg");
        loadcellActive = true;
      } else if (key == '*') {
        // Reset input
        inputBuffer = "";
        lcd.setCursor(0, 1);
        lcd.print("                ");
      }
    }
  } else {
    // Membaca berat terukur dan mengalikan dengan faktor kalibrasi
    float weight = scale.get_units()/100;
    servoMotor.write(servoOpenAngle); // membuka servo
    Serial.println("Servo terbuka");
    lcd.setCursor(0, 1);
    lcd.print(weight, 2);
    lcd.print(" kg      ");
    if (weight >= target) {
      servoMotor.write(servoCloseAngle); // menutup servo
      Serial.println("Servo tertutup");
      loadcellActive = false;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Silakan Ambil");
      lcd.setCursor(0, 1);
      lcd.print(target);
      lcd.print(" kg      ");
      delay(5000); // Tampilkan "Berhasil" selama 5 detik
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Masukan KG:");
    }
  }
}