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

LiquidCrystal_I2C lcd(0x27, 16, 2);
const int analogInPin = 34; // ESP32 analog pin
const int relayPin = 12;
const int buttonPin = 13;
bool isButtonPressed = false;
unsigned long lastButtonPress = 0;

int a, b, c;
long volt, current, power, ah, wh;
unsigned long msec = 0;
float time = 0.0;
int sample = 0;
float totalCharge = 0.0;
float averageAmps = 0.0;
float ampSeconds = 0.0;
long ampHours = 0;

void setup() {
  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, HIGH);
  pinMode(buttonPin, INPUT);
  lcd.begin();
  lcd.backlight();
  Serial.begin(9600);

  lcd.setCursor(0, 0);
  lcd.print("GOOD DAY");

  delay(2000);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Energy Meter");

  delay(2000);
  scrollText("Circuits & Measurements Lab  COURSE PROJECT  ");

  for (int i = 0; i < 2; ++i) {
    lcd.setCursor(0, 1);
    lcd.print("Initializing");
    delay(500);
    lcd.print(".");
    delay(500);
    lcd.print(".");
    delay(500);
    lcd.print(".");
    delay(500);
    lcd.clear();
  }

  lcd.clear();
}

void loop() {
  for (int i = 0; i < 200; i++) {
    c = analogRead(analogInPin);
    a = analogRead(analogInPin);
    volt = volt + a;
    current = current + c;
    delay(1);
  }
  current = (current / 200 - 514);
  if (current < 0.01) current = 0;
  current = current * 10.78260;
  volt = volt / 30;
  power = (volt * current) / 1000;

  sample = sample + 1;

  long msec = millis();
  float time = (float)msec / 1000.0;
  totalCharge = totalCharge + current;
  averageAmps = totalCharge / sample;
  ampSeconds = averageAmps * time;
  ampHours = ampSeconds / 3600;
  wh = ampHours * volt;

  Serial.print("{\"voltage\":");
  Serial.print(volt);
  Serial.print("}  ");
  Serial.print(current);
  Serial.print("mA ");
  Serial.print(power, 6);
  Serial.print("W ");
  Serial.print(ampHours, 6);
  Serial.print("Ah ");
  Serial.print(wh);
  Serial.print(" WATTHOUR   ");
  Serial.print(" units   ");
  Serial.print(wh / 1000.0, 6);
  Serial.println();

  controlRelay();
  updateLCD(volt, current, power, wh);
  delay(1500);

  displayEnergyConsumption(wh);
  delay(1500);

  displayEnergyCost(wh, 8.00);
  delay(1500);
}

void controlRelay() {
  if (current >= 120) {
    digitalWrite(relayPin, LOW);
    Serial.println("Relay OFF - Current exceeded limit");
  } else {
    if (digitalRead(buttonPin) == HIGH && !isButtonPressed) {
      digitalWrite(relayPin, HIGH);
      Serial.println("Relay ON - Button pressed");
      isButtonPressed = true;
    } else if (isButtonPressed) {
      isButtonPressed = false;
    }
  }
}

void scrollText(const char* text) {
  int textLength = strlen(text);

  for (int i = 0; i < textLength - 16; ++i) {
    int startPos = i % textLength;
    lcd.clear();
    lcd.setCursor(0, 0);

    for (int j = 0; j < 16; ++j) {
      lcd.write(text[(startPos + j) % textLength]);
    }

    delay(400);
  }
}

void updateLCD(long volt, long current, long power, long wh) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("V: ");
  lcd.print(volt);

  lcd.setCursor(8, 0);
  lcd.print("A: ");
  lcd.print(current);

  lcd.setCursor(0, 1);
  lcd.print("W: ");
  lcd.print(power);

  lcd.setCursor(8, 1);
  lcd.print("Wh: ");
  lcd.print(wh);
}

void displayEnergyConsumption(long wh) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Energy Cons:");
  lcd.setCursor(0, 1);
  lcd.print(wh / 1000.0, 6);
  lcd.setCursor(9, 1);
  lcd.print("Units");
}

void displayEnergyCost(long wh, float costPerUnit) {
  float energyCost = (wh / 1000.0) * costPerUnit;
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Cost/Unit: ");
  lcd.setCursor(10, 0);
  lcd.print(costPerUnit);

  lcd.setCursor(0, 1);
  lcd.print("Cost: ");
  lcd.print(energyCost, 2);
  lcd.setCursor(11, 1);
  lcd.print("Rs");
}
$abcdeabcde151015202530354045505560fghijfghij
esp:0
esp:1
esp:2
esp:3
esp:4
esp:5
esp:6
esp:7
esp:8
esp:9
esp:10
esp:11
esp:12
esp:13
esp:14
esp:15
esp:16
esp:17
esp:18
esp:19
esp:20
esp:21
esp:26
esp:33
esp:34
esp:35
esp:36
esp:37
esp:38
esp:39
esp:40
esp:41
esp:42
esp:45
esp:46
esp:3V3
esp:5V
esp:GND.1
esp:TX
esp:RX
esp:RST
esp:GND.2
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL
NOCOMNCVCCGNDINLED1PWRRelay Module
relay1:VCC
relay1:GND
relay1:IN
relay1:NC
relay1:COM
relay1:NO
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
pot1:GND
pot1:SIG
pot1:VCC
r1:1
r1:2