#include <WiFi.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <Adafruit_INA219.h>
#include <Adafruit_Thermal.h>
#include <SoftwareSerial.h>
#include <RTClib.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
Adafruit_INA219 ina219;
RTC_DS3231 rtc;
#define TX_PIN 17
#define RX_PIN 16
SoftwareSerial mySerial(TX_PIN, RX_PIN);
Adafruit_Thermal printer(&mySerial);
const char* ssid = "Redmi Note 7";
const char* password = "yongkiputeri";
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] = {32, 33, 25, 26};
byte colPins[COLS] = {27, 14, 12, 13};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
const int RELAY_Pin = 23;
const int VOLTAGE_Pin = 34;
const float MAX_VOLTAGE = 12.0;
const int MAX_PERCENTAGE = 100;
bool isPurchaseMode = false;
bool isCharging = false;
String purchaseAmount = "";
unsigned long startTime = 0;
void setup() {
Serial.begin(115200);
mySerial.begin(9600);
ina219.begin();
ina219.setCalibration_32V_2A();
rtc.begin();
//rtc.adjust(DateTime(2023, 12, 14, 21, 12, 0));// kalibrasi waktu
lcd.init();
lcd.backlight();
// Connecting to WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
lcd.setCursor(1, 1);
lcd.print("Connecting to WiFi");
delay(3000);
lcd.clear();
}
Serial.println("WiFi Connected");
lcd.setCursor(3, 1);
lcd.print("WiFi Connected");
delay(3000);
lcd.clear();
displayInitialScreen();
pinMode(VOLTAGE_Pin, INPUT);
pinMode(RELAY_Pin, OUTPUT);
digitalWrite(RELAY_Pin, HIGH);
}
void loop() {
char key = keypad.getKey();
if (key != NO_KEY) {
handleKeypad(key);
}
checkChargingStatus();
float batteryVoltage = readBatteryVoltage();
int batteryPercentage = mapBatteryPercentage(batteryVoltage);
automaticChargingControl(batteryVoltage, batteryPercentage); // Memanggil fungsi untuk memeriksa kondisi otomatis
}
void displayInitialScreen() {
// Tampilan layar awal
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("TRANSAKSI PRABAYAR");
lcd.setCursor(3, 1);
lcd.print("PENGISIAN DAYA");
lcd.setCursor(1, 2);
lcd.print("INTERNET OF THINGS");
}
void handleKeypad(char key) {
if (!isPurchaseMode && (key >= '0' && key <= '9')) {
return;
}
if (key == '*') {
isPurchaseMode = true;
purchaseAmount = "";
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("SILAHKAN TRANSAKSI");
lcd.setCursor(0, 1);
lcd.print("Beli: ");
lcd.setCursor(0, 3);
lcd.print("Back");
lcd.setCursor(16, 3);
lcd.print("Next");
} else if (key == '#') {
handlePurchase();
} else if (key == 'D') {
handleDelete();
} else if (isPurchaseMode && isDigit(key)) {
handleInput(key);
} else if (key == 'A') {
resetSystem();
} else if (isCharging && key == 'B') {
stopCharging();
}
}
void handleInput(char key) {
purchaseAmount += key;
lcd.setCursor(6, 1);
lcd.print(purchaseAmount);
lcd.setCursor(0, 1);
lcd.print("Beli: ");
lcd.setCursor(0, 3);
lcd.print("Back");
lcd.setCursor(16, 3);
lcd.print("Next");
}
void handleDelete() {
if (isPurchaseMode && purchaseAmount.length() < 7) {
purchaseAmount.remove(purchaseAmount.length() - 1);
lcd.setCursor(6, 1);
lcd.print(" ");
lcd.setCursor(6, 1);
lcd.print(purchaseAmount);
lcd.setCursor(0, 3);
lcd.print("Back");
lcd.setCursor(16, 3);
lcd.print("Next");
} else {
lcd.clear();
lcd.setCursor(1, 1);
lcd.print("MASUKKAN TRANSAKSI");
delay(1000);
lcd.clear();
displayInitialScreen();
}
}
void handlePurchase() {
if (isPurchaseMode && purchaseAmount != "") {
int amount = purchaseAmount.toInt();
if (amount == 5000) {
} else if (amount == 10000) {
} else if (amount == 15000) {
} else if (amount == 20000) {
} else if (amount == 25000) {
} else {
// Handling for invalid transaction
lcd.clear();
lcd.setCursor(1, 1);
lcd.print("MASUKKAN TRANSAKSI");
delay(1000);
lcd.clear();
displayInitialScreen();
return;
}
DateTime transactionTime = rtc.now();
lcd.clear();
lcd.setCursor(2, 1);
lcd.print("Charging Active!");
delay(2000);
lcd.clear();
digitalWrite(RELAY_Pin, LOW);
isCharging = true;
float batteryVoltage = 0.0;
int batteryPercentage = 0;
unsigned long startTime = millis();
unsigned long chargingDuration = 0;
unsigned long lastCalculationTime = millis();
float totalEnergy_kWh = 0.0; // Inisialisasi energi total yang dikonsumsi selama pengisian
float initialEnergy_kWh = 0.0; // Energi awal sebelum pengisian dimulai
//GANTI KWH SESUAI PERHITUNGAN
unsigned long lastEnergyAdditionTime = millis(); // Waktu terakhir energi ditambahkan
float intervalEnergyToAdd = 0.001; // Ganti Energi tambahan yang ditambahkan setiap 10 detik
//GANTI BIAYA SESUAI PERHITUNGAN
unsigned long chargingStart = millis(); // Simpan waktu saat pengisian dimulai
float chargingCost = 0.0; // Biaya pengisian
const float COST_PER_SECOND = 0.200; // Ganti Biaya per milidetik (Rp. 200)
while (isCharging) {
batteryVoltage = readBatteryVoltage();
batteryPercentage = mapBatteryPercentage(batteryVoltage);
float busVoltage_V = ina219.getBusVoltage_V();
float current_mA = ina219.getCurrent_mA();
float power_mW = ina219.getPower_mW();
// Hitung durasi pengisian
int hours = chargingDuration / 3600000;
int minutes = (chargingDuration % 3600000) / 60000;
int seconds = ((chargingDuration % 3600000) % 60000) / 1000;
// Hitung energi
float chargingPower_kW = (ina219.getPower_mW() / 1000.0) / (60.0 * 60.0);
float energy_kWh = chargingPower_kW * (chargingDuration / 1000.0 / 60.0 / 60.0);
displayBatteryInfo(batteryVoltage, batteryPercentage);
lcd.setCursor(0, 2);
lcd.print("Energy: ");
lcd.print(totalEnergy_kWh, 3);
lcd.print(" kWh");
// Tampilkan informasi biaya tambahan
lcd.setCursor(0, 3);
lcd.print("Biaya: Rp. ");
lcd.print(chargingCost, 3); // Menampilkan total biaya
if (millis() - lastCalculationTime >= 10000) {
unsigned long currentTime = millis();
float timeDiffSeconds = (currentTime - lastCalculationTime) / 1000.0;
lastCalculationTime = currentTime;
float chargingPower_kW = (ina219.getPower_mW() / 1000.0) / (60.0 * 60.0);
float intervalEnergy_kWh = chargingPower_kW * (timeDiffSeconds / 3600.0);
totalEnergy_kWh += intervalEnergy_kWh;
// Menghitung energi tambahan setiap 10 detik
if (millis() - lastEnergyAdditionTime >= 10000) {
totalEnergy_kWh += intervalEnergyToAdd;
lastEnergyAdditionTime = millis();
}
if (millis() - chargingStart >= 1000) {
chargingCost += COST_PER_SECOND; // Tambahkan biaya per detik
// Reset waktu pengisian
chargingStart = millis();
}
}
if (keypad.getKey() == 'B') {
digitalWrite(RELAY_Pin, HIGH);
isCharging = false;
chargingDuration = millis() - startTime;
purchaseAmount = "";
isPurchaseMode = false;
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("SILAHKAN AMBIL");
lcd.setCursor(2, 1);
lcd.print("BUKTI TRANSAKSI!");
printTransaction(batteryVoltage, batteryPercentage, current_mA, power_mW, totalEnergy_kWh, chargingCost, amount, transactionTime, chargingDuration);
delay(2000);
lcd.clear();
displayInitialScreen(); // Kembali ke tampilan awal setelah pengisian selesai
break;
}
// Pemantauan chargingCost untuk mematikan relay saat mencapai batas tertentu
if (amount == 5000 && chargingCost >= 7.000) {
digitalWrite(RELAY_Pin, HIGH);
isCharging = false;
chargingDuration = millis() - startTime;
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("SILAHKAN AMBIL");
lcd.setCursor(2, 1);
lcd.print("BUKTI TRANSAKSI!");
printTransaction(batteryVoltage, batteryPercentage, current_mA, power_mW, totalEnergy_kWh, chargingCost, amount, transactionTime, chargingDuration);
delay(2000);
lcd.clear();
displayInitialScreen(); // Kembali ke tampilan awal setelah pengisian selesai
break;
} else if (amount == 10000 && chargingCost >= 12.000) {
digitalWrite(RELAY_Pin, HIGH);
isCharging = false;
chargingDuration = millis() - startTime;
purchaseAmount = "";
isPurchaseMode = false;
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("SILAHKAN AMBIL");
lcd.setCursor(2, 1);
lcd.print("BUKTI TRANSAKSI!");
printTransaction(batteryVoltage, batteryPercentage, current_mA, power_mW, totalEnergy_kWh, chargingCost, amount, transactionTime, chargingDuration);
delay(2000);
lcd.clear();
displayInitialScreen(); // Kembali ke tampilan awal setelah pengisian selesai
break;
} else if (amount == 15000 && chargingCost >= 17.000) {
digitalWrite(RELAY_Pin, HIGH);
isCharging = false;
chargingDuration = millis() - startTime;
purchaseAmount = "";
isPurchaseMode = false;
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("SILAHKAN AMBIL");
lcd.setCursor(2, 1);
lcd.print("BUKTI TRANSAKSI!");
printTransaction(batteryVoltage, batteryPercentage, current_mA, power_mW, totalEnergy_kWh, chargingCost, amount, transactionTime, chargingDuration);
delay(2000);
lcd.clear();
displayInitialScreen(); // Kembali ke tampilan awal setelah pengisian selesai
break;
} else if (amount == 20000 && chargingCost >= 22.000) {
digitalWrite(RELAY_Pin, HIGH);
isCharging = false;
chargingDuration = millis() - startTime;
purchaseAmount = "";
isPurchaseMode = false;
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("SILAHKAN AMBIL");
lcd.setCursor(2, 1);
lcd.print("BUKTI TRANSAKSI!");
printTransaction(batteryVoltage, batteryPercentage, current_mA, power_mW, totalEnergy_kWh, chargingCost, amount, transactionTime, chargingDuration);
delay(2000);
lcd.clear();
displayInitialScreen(); // Kembali ke tampilan awal setelah pengisian selesai
break;
} else if (amount == 25000 && chargingCost >= 27.000) {
digitalWrite(RELAY_Pin, HIGH);
isCharging = false;
chargingDuration = millis() - startTime;
purchaseAmount = "";
isPurchaseMode = false;
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("SILAHKAN AMBIL");
lcd.setCursor(2, 1);
lcd.print("BUKTI TRANSAKSI!");
printTransaction(batteryVoltage, batteryPercentage, current_mA, power_mW, totalEnergy_kWh, chargingCost, amount, transactionTime, chargingDuration);
delay(2000);
lcd.clear();
displayInitialScreen(); // Kembali ke tampilan awal setelah pengisian selesai
break;
}
}
} else {
lcd.clear();
lcd.setCursor(0, 1);
lcd.print("TRANSAKSI INVALID");
delay(2000);
lcd.clear();
displayInitialScreen();
}
}
float readBatteryVoltage() {
int sensorValue = analogRead(VOLTAGE_Pin); // Membaca nilai tegangan dari pin analog
float voltage = (sensorValue * 5.0) / 4095; // Mengkonversi nilai analog ke tegangan (range 0-5V)
float actualVoltage = voltage * 2; // Mengkalibrasi tegangan (contoh faktor 2)
return actualVoltage;
}
int mapBatteryPercentage(float voltage) {
// Melakukan pemetaan (mapping) dari tegangan ke persentase baterai
int percentage = map(voltage, 0, MAX_VOLTAGE, 0, MAX_PERCENTAGE); // Mengonversi tegangan ke persentase
return constrain(percentage, 0, 100); // Memastikan nilai persentase berada di antara 0 hingga 100
}
void displayBatteryInfo(float voltage, int percentage) {
lcd.setCursor(0, 0);
lcd.print("Voltage: ");
lcd.print(voltage);
lcd.print(" V");
lcd.setCursor(0, 1);
lcd.print("Battery: ");
lcd.print(percentage);
lcd.print(" %");
}
void stopCharging() {
digitalWrite(RELAY_Pin, HIGH); // Mematikan relay untuk menghentikan pengisian
isCharging = false; // Menyetel status pengisian menjadi tidak aktif
lcd.clear(); // Membersihkan tampilan LCD
lcd.setCursor(3, 1);
lcd.print("CHARGER FINISH"); // Menampilkan pesan bahwa pengisian telah selesai
delay(2000);
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("SILAHKAN AMBIL");
lcd.setCursor(2, 1);
lcd.print("BUKTI TRANSAKSI!");
delay(2000);
lcd.clear();
displayInitialScreen(); // Kembali ke tampilan awal setelah pengisian selesai
}
void automaticChargingControl(float voltage, int percentage) {
if (voltage >= MAX_VOLTAGE && percentage >= MAX_PERCENTAGE) {
stopCharging();
}
}
void checkChargingStatus() {
if (isCharging) {
float batteryVoltage = readBatteryVoltage();
int batteryPercentage = mapBatteryPercentage(batteryVoltage);
displayBatteryInfo(batteryVoltage, batteryPercentage);
float busVoltage_V = ina219.getBusVoltage_V();
float current_mA = ina219.getCurrent_mA();
float power_mW = ina219.getPower_mW();
automaticChargingControl(batteryVoltage, batteryPercentage);
}
}
void printTransaction(float batteryVoltage, int batteryPercentage, float current_mA, float power_mW, float totalEnergy_kWh, float chargingCost, int amount, DateTime transactionTime, unsigned long chargingDuration) {
printer.begin();
printer.feed(1);
printer.justify('C');
printer.setSize('M');
printer.boldOn();
printer.println("STARIK");
printer.setSize('S');
printer.println("STASIUN PENGISIAN LISTRIK");
printer.boldOff();
printer.println("");
printer.justify('L');
printer.setSize('S');
printer.boldOn();
printer.println("Tanggal: " + String(transactionTime.day()) + "/" + String(transactionTime.month()) + "/" + String(transactionTime.year()));
printer.println("Waktu : " + String(transactionTime.hour()) + ":" + String(transactionTime.minute()) + ":" + String(transactionTime.second()));
printer.println("Durasi Charger: " + String(chargingDuration / 1000 / 60 / 60) + " : " + String((chargingDuration / 1000 / 60) % 60) + " : " + String((chargingDuration / 1000) % 60));
printer.println("Voltage: " + String(batteryVoltage) + " V");
printer.println("Batterai: " + String(batteryPercentage) + " %");
printer.println("Current: " + String(current_mA) + " mA");
printer.println("Power: " + String(power_mW) + " mW");
printer.println("Energy: " + String(totalEnergy_kWh, 3) + " kWh");
printer.println("Transaksi: Rp " + String(amount));
printer.println("Harga Charger: Rp. " + String(chargingCost, 3));
printer.boldOff();
printer.println("");
printer.justify('C');
printer.setSize('S');
printer.boldOn();
printer.println("TRANSAKSI SUKSES");
printer.println("TERIMA KASIH");
printer.boldOff();
printer.feed(3);
delay(1000);
printer.sleep();
// Mengirimkan ke alamat host dengan port 80 -----------------------------------
WiFiClient client;
const char *host = "https://starikpolmanbabel.000webhostapp.com";
const int httpPort = 443;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
// Isi Konten yang dikirim adalah alamat ip si esp -----------------------------
String url = "/getdata?voltage=1¤t=1&power=1&nominal=1&charging_time=1";
// Mengirimkan Request ke Server -----------------------------------------------
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 1000) {
Serial.println(">>> Client Timeout !");
client.stop();
return;
}
}
}
void resetSystem() {
digitalWrite(RELAY_Pin, HIGH); // Menghentikan pengisian jika sedang berlangsung
isCharging = false; // Menyetel status pengisian menjadi tidak aktif
lcd.clear(); // Membersihkan layar LCD
lcd.setCursor(4, 1);
lcd.print("RESET ESP32!"); // Menampilkan pesan reset
delay(1000);
ESP.restart(); // Melakukan restart pada ESP32
lcd.clear(); // Membersihkan layar setelah restart
displayInitialScreen(); // Menampilkan layar awal setelah restart
}