#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <EEPROM.h>
#include "Adafruit_Thermal.h"
#include "SoftwareSerial.h"

#define TX_PIN 10 // Arduino transmit YELLOW WIRE labeled RX on the printer
#define RX_PIN 11 // Arduino receive GREEN WIRE labeled TX on the printer

SoftwareSerial mySerial(RX_PIN, TX_PIN);
Adafruit_Thermal printer(&mySerial);

LiquidCrystal_I2C lcd(0x27, 20, 4);

const int LDR_PIN[] = {A0, A1}; // Gunakan dua pin analog saja
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] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

int calibrationValue = 500;
char password[] = "1234";
bool calibrationCompleted = false;
int currentMenu = 0;
bool stopDisplayingValues = false;

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(2, 0);
  lcd.print("HEADLIGHT TESTER");
  lcd.setCursor(7, 2);
  lcd.print("SPACE");
  delay(2000);
  Serial.begin(9600);
  mySerial.begin(9600);
  printer.begin();
  printer.justify('C');
  printer.setSize('S');
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("A. Measurement");
  lcd.setCursor(0, 1);
  lcd.print("C. Calibration");
  lcd.setCursor(0, 2);
  lcd.print("D. Detail");
  lcd.setCursor(0, 3);
  lcd.print("B. Back");
  EEPROM.get(0, calibrationValue);
}

float measureLight(int pin) {
  int sensorValue = analogRead(pin);
  float voltage = (sensorValue / 1023.0) * 5.0;
  float resistance = (5.0 - voltage) / voltage;
  return calibrationValue / resistance * 1000;
}

void displayLightValues() {
  float luxValues[2];
  for (int i = 0; i < 2; i++) {
    luxValues[i] = measureLight(LDR_PIN[i]);
  }

  float maxLux = max(luxValues[0], luxValues[1]);
  String beamInfo = (luxValues[0] > luxValues[1]) ? "High Beam" : "Low Beam";

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Brightness:");
  lcd.setCursor(0, 1);
  lcd.print("Cd");
  lcd.setCursor(8, 1);
  lcd.print(maxLux, 0);
  lcd.setCursor(0, 2);
  lcd.print("Beam: ");
  lcd.print(beamInfo);
  delay(1000);
}

void printValues() {
  float luxValues[2];
  for (int i = 0; i < 2; i++) {
    luxValues[i] = measureLight(LDR_PIN[i]);
  }

  float maxLux = max(luxValues[0], luxValues[1]);
  String beamInfo = (luxValues[0] > luxValues[1]) ? "High Beam" : "Low Beam";

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("PRINTING.....");
  delay(2000);
  displayLightValues();
  printer.justify('C');
  printer.setSize('S');
  printer.doubleHeightOn();
  printer.print("SPACE");
  printer.doubleHeightOff();
  printer.println();
  printer.println("HEADLIGHT TESTER");
  printer.println();
  printer.underlineOn();
  printer.println("Measurement Data");
  printer.underlineOff();
  printer.println();
  printer.print("Intensity: " + String(maxLux, 0));
  printer.println(" Cd");
  printer.println("Beam Info: " + beamInfo);
  printer.println();
  printer.underlineOn();
  printer.println("Matur Nuwun");
  printer.underlineOff();
  printer.println();
  printer.feed(3);
  printer.sleep();
}

void calibrateSensor() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Enter Calibration Lux:");
  char buffer[7];
  int bufferIndex = 0;
  while (1) {
    char key = keypad.getKey();
    if (key) {
      if (key == '#') {
        calibrationValue = atoi(buffer);
                EEPROM.put(0, calibrationValue);
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Calibration Value:");
        lcd.setCursor(0, 1);
        lcd.print(calibrationValue);
        lcd.setCursor(0, 2);
        lcd.print("Calibration Success");
        delay(2000);
        calibrationCompleted = true;
        return;
      } else if (key == '*') {
        bufferIndex = 0;
      } else {
        buffer[bufferIndex++] = key;
        lcd.setCursor(bufferIndex - 1, 1);
        lcd.print(key);
      }
    }
  }
}


void displayDetailValues() {
  lcd.clear();
  stopDisplayingValues = false;
  while (!stopDisplayingValues) {
    for (int i = 0; i < 2; i++) {
      lcd.setCursor(0, i);
      lcd.print("Sensor ");
      lcd.print(i + 1);
      lcd.setCursor(9, i);
      float lux = measureLight(LDR_PIN[i]);
      Serial.print("Sensor ");
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(lux);
      Serial.println(" Cd");
      lcd.print(lux, 0);
    }
    delay(1000);
    lcd.clear();
    char key = keypad.getKey();
    if (key == 'B') {
      stopDisplayingValues = true;
    }
  }
}

void loop() {
  char key = keypad.getKey();
  if (key) {
    switch (key) {
      case 'A':
        currentMenu = 1;
        displayMenu(currentMenu);
        break;
      case 'C':
        if (checkPassword()) {
          currentMenu = 2;
          displayMenu(currentMenu);
        }
        break;
      case 'D':
        currentMenu = 3;
        displayMenu(currentMenu);
        break;
      case 'B':
        currentMenu = 0;
        displayMenu(currentMenu);
        break;
      case '*':
        printValues();
        break;
    }
  }
}

bool checkPassword() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Enter Password:");
  char enteredPassword[5];
  int passwordIndex = 0;
  while (1) {
    char key = keypad.getKey();
    if (key) {
      if (key == '#') {
        enteredPassword[passwordIndex] = '\0';
        if (strcmp(enteredPassword, password) == 0) {
          return true;
        } else {
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Invalid Password!");
          delay(2000);
          return false;
        }
      } else if (key == '*') {
        passwordIndex = 0;
      } else {
        enteredPassword[passwordIndex++] = key;
        lcd.setCursor(passwordIndex - 1, 1);
        lcd.print('*');
      }
    }
  }
}

void displayMenu(int menu) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Menu:");
  switch (menu) {
    case 0:
      lcd.setCursor(0, 1);
      lcd.print("1. Measurement     A");
      lcd.setCursor(0, 2);
      lcd.print("2. Calibration     C");
      lcd.setCursor(0, 3);
      lcd.print("3. Detail          D");
      stopDisplayingValues = false;
      break;
    case 1:
      displayLightValues();
      break;
    case 2:
      calibrateSensor();
      break;
    case 3:
      displayDetailValues();
      break;
  }
}
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
ldr1:VCC
ldr1:GND
ldr1:DO
ldr1:AO
ldr2:VCC
ldr2:GND
ldr2:DO
ldr2:AO
ldr3:VCC
ldr3:GND
ldr3:DO
ldr3:AO
ldr4:VCC
ldr4:GND
ldr4:DO
ldr4:AO
keypad1:R1
keypad1:R2
keypad1:R3
keypad1:R4
keypad1:C1
keypad1:C2
keypad1:C3
keypad1:C4
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL