2025-02-26 13:06:14 by Administrator Web
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.
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);
2025-03-16 06:24:06
2025-02-21 02:04:31