Loading...

Monitoring MPPT dengan Firebase Realtime Database

2025-02-26 13:06:14 by Administrator Web

Monitoring MPPT dengan Firebase Realtime Database

Haloo IMERCY-ers. Artikel ini akan menunjukan dan menjelaskan cara memonitoring Photovoltaic (PV) menggunakan EPEVER MPPT (Maximum Power Point Tracking) menggunakan Firebase Realtime Database. Sistem monitoring ini bisa memantau beberapa parameter lhoo, beberapa diantaranya tegangan PV, arus PV, daya PV, tegangan baterai, dan suhu baterai secara real-time melalui platform Firebase, jadi kita bisa monitoring photovoltaic kita kapanpun dan dimanapun Lhoo asalkan ada wifi atau internet. Keren gak tuh? tapi sebelum itu kita siapkan dulu alat dan bahannya yaa.

  1.  EPEVER MPPT Solar Charge Controller, EPEVER MPPT ini digunakan untuk mengatur dan mempengisian daya dari panel surya ke baterai.
  2. ESP32, Micro Controllerr yang digunakan untuk mengolah data dari MPPT dan mengirimkannya ke Firebase.
  3. Modul TTL to RS485, Modul ini digunakan untuk mengubah sinyal RS485 dari MPPT menjadi sinyal TTL yang dapat diproses oleh ESP32.
  4. Photovoltaics (PV) / Panel Surya, Panel surya ini akan menjadi sumber energi baterai nantinya.
  5. Baterai, Penyimpanan energi yang dihasilkan oleh panel surya, tapii kali ini kami pakai baterai 18Ah, kalian bisa kok pakai baterai yang lain, asalkan ngga rusak hehehe….
  6. Kabel Jumper dan Kabel LAN RJ45, Kabel-kabel ini wajib yaa Untuk menghubungkan komponen-komponen terutama kabel untuk menghubungkan EPEVER MPPT dengan modul RS485.

Oke next kalian bisa ikutin rangkaian skematik ini yaa. 


Oke sesudah merangkai mari kita mendownload beberapa library dan boardnya yaitu ESP32, firebase ESP client, modbus master, NTP Client. setelah mendownload library-library tersebut mari kita coding! 

#include  
#include  
#include  
#include "addons/TokenHelper.h" 
#include "addons/RTDBHelper.h" 
// Konfigurasi WiFi 
#define WIFI_SSID "WIFI SSID kalian" 
#define WIFI_PASSWORD "Password wifi kalian" 
#include  
#include  
WiFiUDP ntpUDP; 
const long utc = 25200; 
NTPClient timeClient(ntpUDP, "pool.ntp.org", utc); 
String CurrentTime, CurrentDate, CurrentDate1; 
// Konfigurasi Firebase 
#define API_KEY "API Key kalian" 
#define DATABASE_URL "Database URL kalian/" 
#include  
// #include  
#include  
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) 
// SoftwareSerial mySerial(2, 3); // RX, TX 
HardwareSerial mySerial(2);  // RX, TX 
const int defaultBaudRate = 9600; 
int timerTask1, timerTask2, timerTask3; 
float battChargeCurrent, battDischargeCurrent, battOverallCurrent, battChargePower; 
float bvoltage, btemp, bremaining, lpower, lcurrent, pvvoltage, pvcurrent, pvpower; 
float stats_today_pv_volt_min, stats_today_pv_volt_max; 
uint8_t result; 
bool rs485DataReceived = true; 
bool loadPoweredOn = true; 
ModbusMaster node; 
// Firebase 
FirebaseData fbdo; 
FirebaseAuth auth; 
FirebaseConfig config; 
unsigned long sendDataPrevMillis = 0; 
bool signupOK = false; 
void setup() { 
Serial.begin(115200); 
// mySerial.begin(115200); 
mySerial.begin(115200, SERIAL_8N1, 16, 17); 
pinMode(2, OUTPUT);  // DE/RE control pin 
digitalWrite(2, LOW); 
node.begin(1, mySerial); 
node.preTransmission(preTransmission); 
node.postTransmission(postTransmission); 
Serial.println("Setup OK!"); 
WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 
Serial.print("Connecting to Wi-Fi"); 
while (WiFi.status() != WL_CONNECTED) { 
Serial.print("."); 
delay(300); 
} 
Serial.println("\nConnected to Wi-Fi"); 
Serial.println(WiFi.localIP()); 
timeClient.begin(); 
config.api_key = API_KEY; 
config.database_url = DATABASE_URL; 
config.token_status_callback = tokenStatusCallback; 
if (Firebase.signUp(&config, &auth, "", "")) { 
Serial.println("Firebase connected"); 
signupOK = true; 
} else { 
Serial.printf("Firebase signup error: %s\n", config.signer.signupError.message.c_str()); 
} 
Firebase.begin(&config, &auth); 
Firebase.reconnectWiFi(true); 
} 
void preTransmission() { 
digitalWrite(2, HIGH);  // Control DE/RE pin 
} 
void postTransmission() { 
digitalWrite(2, LOW); 
} 
typedef void (*RegistryList[])(); 
RegistryList Registries = { 
AddressRegistry_3100, 
AddressRegistry_3106, 
AddressRegistry_310D, 
AddressRegistry_311A, 
AddressRegistry_331B, 
}; 
uint8_t currentRegistryNumber = 0; 
void nextRegistryNumber() { 
currentRegistryNumber++; 
if (currentRegistryNumber >= ARRAY_SIZE(Registries)) { 
currentRegistryNumber = 0; 
} 
} 
void executeCurrentRegistryFunction() { 
Registries[currentRegistryNumber](); 
} 
uint8_t setOutputLoadPower(uint8_t state) { 
Serial.print("Writing coil 0x0006 value to: "); 
Serial.println(state); 
delay(10); 
result = node.writeSingleCoil(0x0006, state); 
if (result == node.ku8MBSuccess) { 
node.getResponseBuffer(0x00); 
Serial.println("Success."); 
} 
return result; 
} 
uint8_t readOutputLoadState() { 
delay(10); 
result = node.readHoldingRegisters(0x903D, 1); 
if (result == node.ku8MBSuccess) { 
loadPoweredOn = (node.getResponseBuffer(0x00) & 0x02) > 0; 
Serial.print("Set success. Load: "); 
Serial.println(loadPoweredOn); 
} else { 
Serial.println("Failed to read register 0x903D!"); 
} 
return result; 
} 
void AddressRegistry_3100() { 
result = node.readInputRegisters(0x3100, 6); 
if (result == node.ku8MBSuccess) { 
pvvoltage = node.getResponseBuffer(0x00) / 100.0f; 
Serial.print("PV Voltage: "); 
Serial.println(pvvoltage); 
pvcurrent = node.getResponseBuffer(0x01) / 100.0f; 
Serial.print("PV Current: "); 
Serial.println(pvcurrent); 
pvpower = (node.getResponseBuffer(0x02) | node.getResponseBuffer(0x03) << 16) / 
100.0f; 
Serial.print("PV Power: "); 
Serial.println(pvpower); 
bvoltage = node.getResponseBuffer(0x04) / 100.0f; 
Serial.print("Battery Voltage: "); 
Serial.println(bvoltage); 
battChargeCurrent = node.getResponseBuffer(0x05) / 100.0f; 
Serial.print("Battery Charge Current: "); 
Serial.println(battChargeCurrent); 
} 
} 
void AddressRegistry_3106() { 
result = node.readInputRegisters(0x3106, 2); 
if (result == node.ku8MBSuccess) { 
battChargePower = (node.getResponseBuffer(0x00) | node.getResponseBuffer(0x01) << 
16) / 100.0f; 
Serial.print("Battery Charge Power: "); 
Serial.println(battChargePower); 
} 
} 
void AddressRegistry_310D() { 
result = node.readInputRegisters(0x310D, 3); 
if (result == node.ku8MBSuccess) { 
lcurrent = node.getResponseBuffer(0x00) / 100.0f; 
Serial.print("Load Current: "); 
Serial.println(lcurrent); 
lpower = (node.getResponseBuffer(0x01) | node.getResponseBuffer(0x02) << 16) / 100.0f; 
Serial.print("Load Power: "); 
Serial.println(lpower); 
} else { 
rs485DataReceived = false; 
Serial.println("Read register 0x310D failed!"); 
} 
} 
void AddressRegistry_311A() { 
result = node.readInputRegisters(0x311A, 2); 
if (result == node.ku8MBSuccess) { 
bremaining = node.getResponseBuffer(0x00) / 1.0f; 
Serial.print("Battery Remaining %: "); 
Serial.println(bremaining); 
btemp = node.getResponseBuffer(0x01) / 100.0f; 
Serial.print("Battery Temperature: "); 
Serial.println(btemp); 
} else { 
rs485DataReceived = false; 
Serial.println("Read register 0x311A failed!"); 
} 
} 
void AddressRegistry_331B() { 
result = node.readInputRegisters(0x331B, 2); 
if (result == node.ku8MBSuccess) { 
battOverallCurrent = (node.getResponseBuffer(0x00) | node.getResponseBuffer(0x01) << 
16) / 100.0f; 
Serial.print("Battery Discharge Current: "); 
Serial.println(battOverallCurrent); 
} else { 
rs485DataReceived = false; 
Serial.println("Read register 0x331B failed!"); 
} 
} 
void UploadFirebase() { 
if (Firebase.ready() && signupOK && (millis() - sendDataPrevMillis > 15000 || 
sendDataPrevMillis == 0)) { 
sendDataPrevMillis = millis(); 
Firebase.RTDB.setFloat(&fbdo, "MPPT/BattChargeCurrent", battChargeCurrent); 
Firebase.RTDB.setFloat(&fbdo, "MPPT/BattDischargeCurrent", battDischargeCurrent); 
Firebase.RTDB.setFloat(&fbdo, "MPPT/BattOverallCurrent", battOverallCurrent); 
Firebase.RTDB.setFloat(&fbdo, "MPPT/BattChargePower", battChargePower); 
Firebase.RTDB.setFloat(&fbdo, "MPPT/Bvoltage", bvoltage); 
Firebase.RTDB.setFloat(&fbdo, "MPPT/Btemp", btemp); 
Firebase.RTDB.setFloat(&fbdo, "MPPT/Lpower", lpower); 
Firebase.RTDB.setFloat(&fbdo, "MPPT/Lcurrent", lcurrent); 
Firebase.RTDB.setFloat(&fbdo, "MPPT/Pvvoltage", pvvoltage); 
Firebase.RTDB.setFloat(&fbdo, "MPPT/Pvcurrent", pvcurrent); 
Firebase.RTDB.setFloat(&fbdo, "MPPT/Pvpower", pvpower); 
Firebase.RTDB.setString(&fbdo, "MPPT/TimeStamp", CurrentTime + " - " + 
CurrentDate1); 
} 
Serial.println("Uploading data to Firebase is successfully."); 
} 
void UpdateTime() { 
timeClient.update(); 
int Hours = timeClient.getHours(); 
int Minutes = timeClient.getMinutes(); 
CurrentTime = (Hours < 10 ? "0" : "") + String(Hours) + ":" + (Minutes < 10 ? "0" : "") + 
String(Minutes); 
// Konversi epoch time ke struktur waktu 
time_t epochTime = timeClient.getEpochTime(); 
struct tm timeInfo; 
gmtime_r(&epochTime, &timeInfo); 
int monthDay = timeInfo.tm_mday; 
int currentMonth = timeInfo.tm_mon + 1; 
int currentYear = timeInfo.tm_year + 1900; 
// Format tanggal dengan dua digit (DD/MM) 
char dateBuffer[6]; 
sprintf(dateBuffer, "%02d/%02d", monthDay, currentMonth); 
CurrentDate = String(dateBuffer); 
// Format tanggal dengan tiga digit (DD/MM/YY) 
CurrentDate1 = CurrentDate + "/" + String(currentYear); 
Serial.print("Current time: "); 
Serial.println(CurrentTime); 
Serial.print("Current date: "); 
Serial.println(CurrentDate1); 
} 
void loop() { 
executeCurrentRegistryFunction(); 
nextRegistryNumber(); 
UpdateTime(); 
UploadFirebase(); 
delay(500);

Api key dan database URL bisa kalian dapatkan di website firebase berikut linknya. Login terlebih dahulu, bisa dengan akun anonymus. Setelah membuat akun selanjutkan kalian harus membuat project realtime database pada firebase untuk mendapatkan API key dan database URL.

HOREEE kalian bisa memonitoring photovoltaickalian lewat firebase dimanapun dan kapanpun.