#include // Library Thinger.io untuk ESP8266 #include // Library untuk sensor PZEM004Tv30 #include // Library WiFiManager untuk manajemen koneksi Wi-Fi #include // Library NTPClient untuk sinkronisasi waktu #include // Library WiFiUDP untuk komunikasi UDP #include // Library EEPROM untuk penyimpanan data #define USERNAME "wahyuee" // Username Thinger.io #define DEVICE_ID "NodeMCU_PZEM" // ID perangkat Thinger.io #define DEVICE_CREDENTIAL "abogoboga" // Kredensial perangkat Thinger.io ThingerESP8266 thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL); // Objek ThingerESP8266 untuk menghubungkan ke Thinger.io // Pin yang terhubung ke relay 4 channel const int relay1 = D0; const int relay2 = D1; const int relay3 = D3; const int relay4 = D4; const int buzzerPin = D2; // Pin buzzer PZEM004Tv30 pzem(14, 12); // GPIO14(D5) ke Tx PZEM004; GPIO12(D6) ke Rx PZEM004 // Variabel untuk menyimpan data sensor float Voltage, Current, Power, Energy, Frequency, PF, VA, VAR, totalCost; bool relay1State = LOW; // Relay1 awalnya dalam keadaan hidup unsigned long relayOffTime = 0; // Waktu saat relay1 dimatikan const float tariffPerKWh = 1352.0; // Tarif per kWh unsigned long startTime = 0; // Waktu awal WiFiUDP ntpUDP; // Objek WiFiUDP untuk komunikasi NTP NTPClient timeClient(ntpUDP, "pool.ntp.org", 0, 60000); // Klien NTP untuk sinkronisasi waktu, update setiap menit const int EEPROM_SIZE = 10; // Ukuran EEPROM const int EEPROM_ADDR = 0; // Alamat EEPROM untuk penyimpanan data void setup() { WiFi.mode(WIFI_STA); // Mengatur mode WiFi menjadi station Serial.begin(115200); // Memulai komunikasi serial dengan baud rate 115200 WiFiManager wm; // Objek WiFiManager untuk manajemen koneksi Wi-Fi wm.resetSettings(); // Mereset pengaturan WiFiManager startTime = millis(); // Mendapatkan waktu awal dalam milidetik // Mengatur pin relay dan buzzer sebagai output pinMode(relay1, OUTPUT); pinMode(relay2, OUTPUT); pinMode(relay3, OUTPUT); pinMode(relay4, OUTPUT); pinMode(buzzerPin, OUTPUT); bool res; // Menghubungkan ke Wi-Fi dengan WiFiManager res = wm.autoConnect("AutoConnectAP", "password"); if (!res) { Serial.println("Failed to connect"); } else { Serial.println("connected... :)"); } thing.add_wifi(WiFi.SSID().c_str(), WiFi.psk().c_str()); // Menambahkan koneksi Wi-Fi ke Thinger.io // Mendefinisikan endpoint untuk data sensor pada Thinger.io thing["PZEM"] >> [] (pson & out) { out["voltage"] = String(Voltage, 2); out["current"] = String(Current, 2); out["power"] = String(Power, 2); out["energy"] = String(Energy, 3); out["frequency"] = String(Frequency, 2); out["faktor daya"] = String(PF, 2); out["Apparent Power"] = String(VA, 2); out["Reactive Power"] = String(VAR, 2); out["Total Biaya"] = String(totalCost, 2); }; // Mendefinisikan endpoint untuk setiap relay pada Thinger.io thing["Perangkat 1"] << digitalPin(relay1); thing["Perangkat 2"] << digitalPin(relay2); thing["Perangkat 3"] << digitalPin(relay3); thing["Perangkat 4"] << digitalPin(relay4); timeClient.begin(); // Memulai klien NTP EEPROM.begin(EEPROM_SIZE); // Memulai EEPROM dengan ukuran yang telah ditentukan unsigned long lastResetTime = 0; // Waktu reset terakhir EEPROM.get(EEPROM_ADDR, lastResetTime); // Mendapatkan waktu reset terakhir dari EEPROM if (lastResetTime == 0) { // Jika waktu reset terakhir adalah 0 lastResetTime = timeClient.getEpochTime(); // Mengatur waktu reset terakhir dengan waktu saat ini EEPROM.put(EEPROM_ADDR, lastResetTime); // Menyimpan waktu reset terakhir ke EEPROM EEPROM.commit(); // Mengkomit perubahan ke EEPROM } } void loop() { thing.handle(); // Menghandle koneksi dan komunikasi dengan Thinger.io timeClient.update(); // Mengupdate waktu dari NTP // Membaca data dari sensor PZEM-004T Voltage = pzem.voltage(); Current = pzem.current(); Power = pzem.power(); Energy = pzem.energy(); Frequency = pzem.frequency(); PF = pzem.pf(); // Menghitung Apparent Power (VA) if (PF == 0) { VA = 0; } else { VA = Power / PF; } // Menghitung Reactive Power (VAR) if (PF == 0) { VAR = 0; } else { VAR = Power / PF * sqrt(1 - sq(PF)); } totalCost = Energy * tariffPerKWh; // Menghitung total biaya berdasarkan energi dan tarif // Memeriksa validitas data dan menampilkan nilai-nilai pada Serial console if (isnan(Voltage)) { Serial.println("Error membaca tegangan"); } else { Serial.print("Voltage : "); Serial.print(Voltage); Serial.println("V"); } if (isnan(Current)) { Serial.println("Error membaca arus"); } else { Serial.print("Current : "); Serial.print(Current); Serial.println("A"); } if (isnan(Power)) { Serial.println("Error membaca daya"); } else { Serial.print("Power : "); Serial.print(Power); Serial.println("W"); } if (isnan(Frequency)) { Serial.println("Error membaca frekuensi"); } else { Serial.print("Frequency : "); Serial.print(Frequency); Serial.println("Hz"); } if (isnan(PF)) { Serial.println("Error membaca faktor daya"); } else { Serial.print("Faktor Daya : "); Serial.print(PF); Serial.println("PF"); } if (isnan(VA)) { Serial.println("Error membaca apparent power"); } else { Serial.print("Apparent Power : "); Serial.print(VA); Serial.println("VA"); } if (isnan(VAR)) { Serial.println("Error membaca reactive power"); } else { Serial.print("Reactive Power : "); Serial.print(VAR); Serial.println("VAR"); } if (isnan(Energy)) { Serial.println("Error membaca energi"); } else { Serial.print("Energy : "); Serial.print(Energy, 3); Serial.println("kWh"); } if (isnan(totalCost)) { Serial.println("Error menghitung biaya"); } else { Serial.print("Total Biaya: "); Serial.println(totalCost); } // Mengaktifkan buzzer jika Apparent Power dalam rentang 90-100 VA if (VA >= 90 && VA <= 100) { digitalWrite(buzzerPin, HIGH); delay(1000); digitalWrite(buzzerPin, LOW); delay(1000); thing.call_endpoint("monitor_listrik"); // Memanggil endpoint yang telah dibuat } else { digitalWrite(buzzerPin, LOW); } // Jika Apparent Power lebih dari 100 VA, matikan relay1 if (VA > 100) { if (relay1State == LOW) { digitalWrite(relay1, HIGH); relay1State = HIGH; relayOffTime = millis(); // Mengatur waktu saat relay1 dimatikan thing.call_endpoint("monitor_listrik1"); // Memanggil endpoint yang telah dibuat } } else { if (relay1State == HIGH && millis() - relayOffTime >= 120000) { // Periksa apakah sudah 2 menit berlalu digitalWrite(relay1, LOW); relay1State = LOW; } } // Mengecek apakah sudah 30 hari berlalu dan mereset energi jika ya unsigned long currentTime = timeClient.getEpochTime(); unsigned long lastResetTime; EEPROM.get(EEPROM_ADDR, lastResetTime); if (currentTime - lastResetTime >= 2592000) { // 30 hari = 2592000 detik pzem.resetEnergy(); // Mereset energi pada sensor PZEM EEPROM.put(EEPROM_ADDR, currentTime); // Menyimpan waktu reset terakhir ke EEPROM EEPROM.commit(); // Mengkomit perubahan ke EEPROM } Serial.println(); delay(1000); }