Skip to content

Instantly share code, notes, and snippets.

@fajarlabs
Last active February 6, 2024 04:33
Show Gist options
  • Select an option

  • Save fajarlabs/28aea467ee464b6e796917fa02b9908a to your computer and use it in GitHub Desktop.

Select an option

Save fajarlabs/28aea467ee464b6e796917fa02b9908a to your computer and use it in GitHub Desktop.

Revisions

  1. fajarlabs revised this gist Feb 6, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion listrik_koin_v_1_3.cpp
    Original file line number Diff line number Diff line change
    @@ -308,7 +308,7 @@ void callback1() {

    StoreData konversi_uang_ke_sisa_daya(long uang, float harga_per_kwh) {
    StoreData obj;
    obj.harga_1_watt = harga_per_kwh / uang;
    obj.harga_1_watt = harga_per_kwh / 1000;
    obj.dapatkan_kredit_watt = uang / obj.harga_1_watt;
    obj.sisa_kredit_daya_dalam_detik = obj.dapatkan_kredit_watt * 3600;
    obj.harga_perkwh = harga_per_kwh;
  2. fajarlabs revised this gist Feb 6, 2024. 1 changed file with 18 additions and 2 deletions.
    20 changes: 18 additions & 2 deletions listrik_koin_v_1_3.cpp
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@
    #include <TimeOut.h>

    #define EEADDR 166
    #define PERKWH 1444.70
    #define PERKWH 1820
    #define RELAY_PIN 6
    #define RELAY_PIN_SUPPORT 7
    #define RESET_PIN 4 // reset ZERO
    @@ -42,10 +42,18 @@ SoftwareSerial pzemSWSerial(PZEM_RX_PIN, PZEM_TX_PIN);
    PZEM004Tv30 pzem(pzemSWSerial);
    HistoryData hd;

    // timeout 0 (check coin)
    TimeOut timeout0;
    void callback0();
    int impulsCount = 0;

    // timeout 1 ( auto restart )
    TimeOut timeout1;
    void callback1();

    // reset program
    void(* resetFunc) (void) = 0; //declare reset function @ address 0

    LiquidCrystal_I2C lcd(0x27, 20, 4);

    // lock interrupt
    @@ -93,6 +101,10 @@ void setup() {
    // }

    isStarted = true;

    // restart setiap 24 jam sekali
    long longDelay = 86400 * 1000;
    timeout1.timeOut(longDelay, callback1); //delay, callback function
    }
    void loop() {
    TimeOut::handler();
    @@ -168,7 +180,7 @@ void loop() {
    float sisaKreditDayaDetikTemp = 0;
    eeSisaKreditDayaDetik >> sisaKreditDayaDetikTemp;

    if (sisaKreditDayaDetikTemp > 0) {
    if (sisaKreditDayaDetikTemp >= 1) {
    float estimasi_habis = 0;
    float beban_daya = 0;
    float powerA = hitung_beban_daya(voltage, current);
    @@ -290,6 +302,10 @@ void callback0() {
    impulsCount = 0;
    }

    void callback1() {
    resetFunc();
    }

    StoreData konversi_uang_ke_sisa_daya(long uang, float harga_per_kwh) {
    StoreData obj;
    obj.harga_1_watt = harga_per_kwh / uang;
  3. fajarlabs created this gist Jan 20, 2024.
    459 changes: 459 additions & 0 deletions listrik_koin_v_1_3.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,459 @@
    #include <EEPROM.h>
    #include <LiquidCrystal_I2C.h>
    #include <PZEM004Tv30.h>
    #include "EEvar.h"
    #include <TimeOut.h>

    #define EEADDR 166
    #define PERKWH 1444.70
    #define RELAY_PIN 6
    #define RELAY_PIN_SUPPORT 7
    #define RESET_PIN 4 // reset ZERO
    #define BUZZER_PIN A3
    #define INTERRUPT_COIN_PIN 2
    #define MAX_COUNTER 2
    #define LCD_TYPE_COLS 16 // jenis LCD 16x2
    #define LCD_TYPE_ROWS 2 // jenis LCD 16x2

    #if !defined(PZEM_RX_PIN) && !defined(PZEM_TX_PIN)
    #define PZEM_RX_PIN 9
    #define PZEM_TX_PIN 10
    #endif

    typedef struct {
    float harga_1_watt;
    float dapatkan_kredit_watt;
    float sisa_kredit_daya_dalam_detik;
    float harga_perkwh;
    long uang;
    } StoreData;

    typedef struct {
    float voltage;
    float current;
    float power;
    float energy;
    float frequency;
    float pf;
    } HistoryData;

    EEstore<float> eeSisaKreditDayaDetik(0.0);
    SoftwareSerial pzemSWSerial(PZEM_RX_PIN, PZEM_TX_PIN);
    PZEM004Tv30 pzem(pzemSWSerial);
    HistoryData hd;

    TimeOut timeout0;
    void callback0();
    int impulsCount = 0;

    LiquidCrystal_I2C lcd(0x27, 20, 4);

    // lock interrupt
    boolean insert = false;

    // Init Var Power Sensor
    float voltage = 0;
    float current = 0;
    float power = 0;
    float energy = 0;
    float frequency = 0;
    float pf = 0;

    int holdReset = MAX_COUNTER; // berapa lama BUTTON di tekan
    bool isBuzzer = false;
    bool isStarted = false;
    bool isReady = false;

    void setup() {
    // put your setup code here, to run once:
    Serial.begin(9600);
    initMyLCD();
    pinMode(INTERRUPT_COIN_PIN, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(2), incomingImpuls, RISING);
    writeLCD(LCD_TYPE_COLS, 0, 0, "EV-Charger Koin");
    writeLCD(LCD_TYPE_COLS, 0, 1, " ----##---- ");
    delay(1000);

    // relay pin relay
    pinMode(RELAY_PIN, OUTPUT);
    pinMode(RELAY_PIN_SUPPORT, OUTPUT);
    // buzzer pin
    pinMode(BUZZER_PIN, OUTPUT);
    // coin acceptor interrupt
    pinMode(RESET_PIN, INPUT_PULLUP);
    delay(500);

    // set relay to low
    digitalWrite(RELAY_PIN, LOW);
    digitalWrite(RELAY_PIN_SUPPORT, LOW);
    delay(500);

    // for (int i = 0; i < LCD_TYPE_ROWS; i++) {
    // writeLCD(LCD_TYPE_COLS, 0, i, "");
    // }

    isStarted = true;
    }
    void loop() {
    TimeOut::handler();

    if (digitalRead(RESET_PIN) == LOW) {
    if (wait(1000)) {
    holdReset -= 1;
    if (holdReset < 1) {
    float resetSisaKredit = 0;
    eeSisaKreditDayaDetik << resetSisaKredit;
    Serial.println(F("*MSG*RESET BERHASIL"));
    holdReset = MAX_COUNTER;

    for (int i = 0; i < 3; i++) {
    writeLCD(LCD_TYPE_COLS, 0, 0, "");
    writeLCD(LCD_TYPE_COLS, 0, 1, "");
    delay(500);
    writeLCD(LCD_TYPE_COLS, 0, 0, " RESET BERHASIL ");
    buzzerFlipFlop(true);
    delay(500);
    }
    buzzerFlipFlop(false);
    writeLCD(LCD_TYPE_COLS, 0, 0, "");
    writeLCD(LCD_TYPE_COLS, 0, 1, "");
    }
    }
    } else {
    holdReset = MAX_COUNTER;
    }

    if (wait(1000)) {

    if (isReady == false) {
    writeLCD(LCD_TYPE_COLS, 0, 0, "");
    writeLCD(LCD_TYPE_COLS, 0, 1, "");
    writeLCD(LCD_TYPE_COLS, 0, 0, "Memuat data...");
    delay(500);
    }

    // Check if the data is valid
    if (isnan(voltage)) {
    Serial.println(F("*ERR*Error reading voltage"));
    } else if (isnan(current)) {
    Serial.println(F("*ERR*Error reading current"));
    } else if (isnan(power)) {
    Serial.println(F("*ERR*Error reading power"));
    } else if (isnan(energy)) {
    Serial.println(F("*ERR*Error reading energy"));
    } else if (isnan(frequency)) {
    Serial.println(F("*ERR*Error reading frequency"));
    } else if (isnan(pf)) {
    Serial.println(F("*ERR*Error reading power factor"));
    } else {
    // Read the data from the sensor
    voltage = pzem.voltage(); Serial.println(voltage);
    current = pzem.current();
    power = pzem.power();
    energy = pzem.energy();
    frequency = pzem.frequency();
    pf = pzem.pf();


    if (isReady == false) {
    isReady = true;
    writeLCD(LCD_TYPE_COLS, 0, 0, "");
    writeLCD(LCD_TYPE_COLS, 0, 1, "");
    }

    if (voltage > 0) {
    // debug power vars
    // show_power_vars(voltage, current, power, energy, frequency, pf);

    float sisaKreditDayaDetikTemp = 0;
    eeSisaKreditDayaDetik >> sisaKreditDayaDetikTemp;

    if (sisaKreditDayaDetikTemp > 0) {
    float estimasi_habis = 0;
    float beban_daya = 0;
    float powerA = hitung_beban_daya(voltage, current);
    float powerB = power;
    // ambil daya yang paling sesuai
    // daya dari perhitungan P = V*I atau P = SENSOR jika tidak watt terlalu kecil
    if (powerA > powerB){
    beban_daya = powerA;
    } else {
    beban_daya = powerB;
    }

    // periksa jika sisa kredit daya kosong/null/error
    if (sisaKreditDayaDetikTemp < 1 || isnan(sisaKreditDayaDetikTemp)) {
    Serial.println("Credit is empty");
    } else {
    estimasi_habis = hitung_estimasi_habis(sisaKreditDayaDetikTemp, beban_daya);
    }

    if (beban_daya > sisaKreditDayaDetikTemp) {
    digitalWrite(RELAY_PIN, LOW);
    digitalWrite(RELAY_PIN_SUPPORT, LOW);
    Serial.println(F("*MSG*Switch status : OFF"));
    buzzerFlipFlop(true);
    } else {
    digitalWrite(RELAY_PIN, HIGH);
    digitalWrite(RELAY_PIN_SUPPORT, HIGH);

    sisaKreditDayaDetikTemp = sisaKreditDayaDetikTemp - beban_daya;
    Serial.println(F("*MSG*Switch status : ON"));
    buzzerFlipFlop(false);
    }

    /*
    Serial.print("Estimasi habis : ");
    Serial.println(estimasi_habis);
    Serial.print("Saldo daya dalam detik : ");
    Serial.print(sisaKreditDayaDetikTemp);
    Serial.println(" Watt/Second");
    Serial.print("Beban daya : ");
    Serial.print(beban_daya);
    Serial.println(" Watt");
    */


    float sisa_daya_aktual = sisa_daya_ke_watt(sisaKreditDayaDetikTemp);

    /*
    Serial.print("Sisa daya aktual : ");
    Serial.print(sisa_daya_aktual);
    Serial.println(" Watt");
    */
    writeLCD(4, 0, 0, String(int(voltage)) + String("V"));
    writeLCD(5, 5, 0, String(current) + String("A"));
    writeLCD(5, 11, 0, String(int(power)) + String("W"));
    writeLCD(6, 0, 1, "PULSA:");

    float convertToKWH = sisa_daya_aktual / 1000;
    writeLCD(11, 6, 1, String(convertToKWH) + String("KWH"));
    hd.voltage = voltage;
    hd.current = current;
    hd.power = power;
    hd.energy = energy;
    hd.frequency = frequency;
    hd.pf = pf;
    simpan_rekaman(hd, EEADDR);
    eeSisaKreditDayaDetik << sisaKreditDayaDetikTemp;
    } else {
    writeLCD(4, 0, 0, String(int(voltage)) + String("V"));
    writeLCD(5, 5, 0, String(current) + String("A"));
    writeLCD(5, 11, 0, String(int(power)) + String("W"));
    writeLCD(6, 0, 1, "PULSA:");
    writeLCD(11, 6, 1, String("0KWH"));

    digitalWrite(RELAY_PIN, LOW);
    digitalWrite(RELAY_PIN_SUPPORT, LOW);
    }
    } else {
    writeLCD(LCD_TYPE_COLS, 0, 0, "No voltage");
    }
    }
    }
    }

    void incomingImpuls() {
    impulsCount = impulsCount + 1;
    timeout0.cancel();
    timeout0.timeOut(300, callback0); //delay, callback function
    }

    void callback0() {
    int coinUang = 0;
    if(impulsCount == 1){
    Serial.println("Coin 1");
    }
    if(impulsCount == 5) {
    coinUang = 1000;
    Serial.println("Coin 2");
    }
    if(impulsCount == 10){
    coinUang = 500;
    Serial.println("Coin 3");
    }
    Serial.println(F("*MSG*Add Coin"));
    StoreData sd = konversi_uang_ke_sisa_daya(coinUang, PERKWH);
    float _sisaKreditDayaDetik = 0;
    eeSisaKreditDayaDetik >> _sisaKreditDayaDetik;
    float _NewWisaKreditDayaDetik = _sisaKreditDayaDetik + sd.sisa_kredit_daya_dalam_detik;
    eeSisaKreditDayaDetik << _NewWisaKreditDayaDetik;


    //float sisa_daya_aktual = sisa_daya_ke_watt(sisaKreditDayaDetikTemp);

    /*
    Serial.print("Sisa daya aktual : ");
    Serial.print(sisa_daya_aktual);
    Serial.println(" Watt");
    */
    impulsCount = 0;
    }

    StoreData konversi_uang_ke_sisa_daya(long uang, float harga_per_kwh) {
    StoreData obj;
    obj.harga_1_watt = harga_per_kwh / uang;
    obj.dapatkan_kredit_watt = uang / obj.harga_1_watt;
    obj.sisa_kredit_daya_dalam_detik = obj.dapatkan_kredit_watt * 3600;
    obj.harga_perkwh = harga_per_kwh;
    obj.uang = uang;
    return obj;
    }

    float sisa_daya_ke_watt(float sisa_daya) {
    return sisa_daya / 3600;
    }

    float hitung_beban_daya(float voltage, float current) {
    return voltage * current;
    }

    float hitung_estimasi_habis(float sisa_kredit_daya_dalam_detik, float beban_daya) {
    if (beban_daya < 1)
    return 0;
    else
    return (sisa_kredit_daya_dalam_detik / beban_daya) / 3600;
    }

    void show_vars(StoreData *p) {
    Serial.print("Uang dari koin acceptor : Rp.");
    Serial.println(p->uang);
    Serial.print("Harga per-Kwh : Rp.");
    Serial.println(p->harga_perkwh);
    Serial.print("Harga 1 watt per-Rupiah : Rp.");
    Serial.println(p->harga_1_watt);
    Serial.print("Mendapatkan Watt : ");
    Serial.print(p->dapatkan_kredit_watt);
    Serial.println(" watt/seconds");
    Serial.print("Total kredit daya dalam detik selama 1 jam : ");
    Serial.print(p->sisa_kredit_daya_dalam_detik);
    Serial.println(" watt/seconds");
    Serial.print("Sisa dalam watt : ");
    Serial.print(sisa_daya_ke_watt(p->sisa_kredit_daya_dalam_detik));
    Serial.println(" watt");
    }

    bool wait(unsigned long duration) {
    static unsigned long startTime;
    static bool isStarted = false;

    if (isStarted == false) {
    startTime = millis();
    isStarted = true;
    return false;
    }

    if (millis() - startTime >= duration) {
    isStarted = false;
    return true;
    }
    return false;
    }

    void writeLCDLine(int col, int row, String text) {
    lcd.setCursor(col, row);
    lcd.print(text);
    }

    void clearLCDLine(int row, int total_cols) {
    for (int n = 0; n < total_cols; n++) {
    lcd.setCursor(n, row);
    lcd.print(" ");
    }
    lcd.setCursor(0, row); // set cursor in the beginning of deleted line
    }

    void reverse(char *x, int begin, int end) {
    char c;
    if (begin >= end)
    return;
    c = *(x + begin);
    *(x + begin) = *(x + end);
    *(x + end) = c;

    reverse(x, ++begin, --end);
    }

    String rupiah(long a) {
    String ans;
    String n = String(a);
    int count = 0;
    char buff[12];

    for (int i = n.length() - 1; i >= 0; i--) {
    ans += n[i];
    count++;
    if (count == 3) {
    ans += ('.');
    count = 0;
    }
    }
    if (ans.length() % 4 == 0) {
    ans.remove(ans.length() - 1, 1);
    }
    ans.toCharArray(buff, 12);
    reverse(buff, 0, ans.length() - 1);

    return String(buff);
    }

    void simpan_rekaman(HistoryData hd, int eeaddr) {
    EEPROM.put(eeaddr, hd);
    }

    HistoryData dapatkan_rekaman(int eeaddr) {
    HistoryData hd;
    EEPROM.get(eeaddr, hd);
    return hd;
    }

    void show_power_vars(float voltage, float current, float power, float energy, float frequency, float pf) {
    /*
    Serial.print("Voltage: "); Serial.print(voltage); Serial.println("V");
    Serial.print("Current: "); Serial.print(current); Serial.println("A");
    Serial.print("Power: "); Serial.print(power); Serial.println("W");
    Serial.print("Energy: "); Serial.print(energy,3); Serial.println("kWh");
    Serial.print("Frequency: "); Serial.print(frequency, 1); Serial.println("Hz");
    Serial.print("PF: "); Serial.println(pf);
    */
    }

    void initMyLCD() {
    lcd.init();
    lcd.backlight();
    lcd.clear();
    }

    void writeLCD(int max_char, int cols, int rows, String message) {
    lcd.setCursor(cols, rows);
    if (message.length() > max_char) {
    for (int i = 0; i < max_char; i++) {
    message.concat(" ");
    }
    lcd.print("ERR");
    } else {
    int total_space = max_char - message.length();
    if (total_space > 0) {
    for (int i = 0; i < total_space; i++) {
    message.concat(" ");
    }
    lcd.print(message);
    } else {
    lcd.print(message);
    }
    }
    }

    void buzzerFlipFlop(bool set_on) {
    if (set_on == true) {
    if (isBuzzer == false) {
    digitalWrite(BUZZER_PIN, HIGH);
    isBuzzer = true;
    } else {
    digitalWrite(BUZZER_PIN, LOW);
    isBuzzer = false;
    }
    } else {
    digitalWrite(BUZZER_PIN, LOW);
    }
    }