#define BLYNK_TEMPLATE_ID "TMPL66b-buG9w" #define BLYNK_TEMPLATE_NAME "Monitoring Listrik" #define BLYNK_AUTH_TOKEN "f3xiBla2UmCX2klP4VuzaYjXZlvyulJZ" #include #include #include #include #include #include #include #include #include #include #include // Define constants #define BLYNK_TEMPLATE_ID_LEN 20 #define BLYNK_TEMPLATE_NAME_LEN 40 #define BLYNK_AUTH_TOKEN_LEN 40 #define MAX_LEN 40 char ssid[50]; char pass[50]; char lokasi_id[MAX_LEN]; char blynk_template_id[BLYNK_TEMPLATE_ID_LEN]; char blynk_template_name[BLYNK_TEMPLATE_NAME_LEN]; char blynk_auth_token[BLYNK_AUTH_TOKEN_LEN]; char created_at[50]; const char* ntpServer = "pool.ntp.org"; const long gmtOffset_sec = 25200; const int daylightOffset_sec = 0; LiquidCrystal_I2C lcd(0x27, 16, 2); PZEM004Tv30 pzem(Serial2, 16, 17); float tarifPerKWh = 1352; const int relayPin = 5; const int buzzerPin = 15; int relayState = LOW; WiFiClient client; IPAddress serverAddr; unsigned long lastUploadTime = 0; // Variabel untuk menyimpan waktu upload terakhir const unsigned long uploadInterval = 60000; // Interval 1 menit (60000 ms) unsigned long lastBlynkUpdateTime = 0; // Variabel untuk menyimpan waktu update Blynk terakhir const unsigned long blynkUpdateInterval = 1000; // Interval 1 detik (1000 ms) unsigned long previousMillis = 0; // Waktu sebelumnya const long buzzerDuration = 60000; // Durasi buzzer dalam milidetik (1 menit = 60 detik = 60000 milidetik) void setup() { WiFi.mode(WIFI_STA); Serial.begin(115200); EEPROM.begin(512); pinMode(relayPin, OUTPUT); pinMode(buzzerPin, OUTPUT); // Membaca data dari EEPROM String read_lokasi_id = EEPROM.readString(0); String read_blynk_template_id = EEPROM.readString(20); String read_blynk_template_name = EEPROM.readString(60); String read_blynk_auth_token = EEPROM.readString(100); // Menampilkan data yang dibaca di Serial Monitor Serial.println("Reading from EEPROM:"); Serial.println("lokasi_id: " + read_lokasi_id); Serial.println("blynk_template_id: " + read_blynk_template_id); Serial.println("blynk_template_name: " + read_blynk_template_name); Serial.println("blynk_auth_token: " + read_blynk_auth_token); // Inisialisasi WiFiManager WiFiManager wifiManager; bool needConfiguration = false; // Memeriksa apakah data EEPROM valid if (read_lokasi_id.length() > 0 && read_blynk_template_id.length() > 0 && read_blynk_template_name.length() > 0 && read_blynk_auth_token.length() > 0) { // Data valid, gunakan untuk konfigurasi Blynk strncpy(lokasi_id, read_lokasi_id.c_str(), sizeof(lokasi_id)); strncpy(blynk_template_id, read_blynk_template_id.c_str(), sizeof(blynk_template_id)); strncpy(blynk_template_name, read_blynk_template_name.c_str(), sizeof(blynk_template_name)); strncpy(blynk_auth_token, read_blynk_auth_token.c_str(), sizeof(blynk_auth_token)); Serial.println("Using saved data from EEPROM:"); Serial.println("lokasi_id: " + String(lokasi_id)); Serial.println("blynk_template_id: " + String(blynk_template_id)); Serial.println("blynk_template_name: " + String(blynk_template_name)); Serial.println("blynk_auth_token: " + String(blynk_auth_token)); // Coba hubungkan ke WiFi dengan SSID yang disimpan lcd.clear(); lcd.setCursor(0, 0); lcd.print("Connecting to"); lcd.setCursor(0, 1); lcd.print("WiFi........."); delay(5000); WiFi.begin(ssid, pass); if (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("Failed to connect to WiFi with saved credentials. Opening configuration portal..."); needConfiguration = true; } else { Serial.println("Connected to WiFi with saved credentials"); // Periksa apakah SSID telah berubah if (String(WiFi.SSID()) != String(ssid)) { Serial.println("SSID has changed, opening configuration portal..."); needConfiguration = true; } } } else { // Data tidak valid atau kosong, buka portal konfigurasi Serial.println("No saved data in EEPROM or data invalid. Opening configuration portal..."); needConfiguration = true; } if (needConfiguration) { WiFiManagerParameter custom_lokasi_id("lokasi_id", "lokasi ID", lokasi_id, MAX_LEN); WiFiManagerParameter custom_blynk_template_id("blynk_template_id", "Blynk Template ID", blynk_template_id, BLYNK_TEMPLATE_ID_LEN); WiFiManagerParameter custom_blynk_template_name("blynk_template_name", "Blynk Template Name", blynk_template_name, BLYNK_TEMPLATE_NAME_LEN); WiFiManagerParameter custom_blynk_auth_token("blynk_auth_token", "Blynk Auth Token", blynk_auth_token, BLYNK_AUTH_TOKEN_LEN); wifiManager.addParameter(&custom_lokasi_id); wifiManager.addParameter(&custom_blynk_template_id); wifiManager.addParameter(&custom_blynk_template_name); wifiManager.addParameter(&custom_blynk_auth_token); if (!wifiManager.autoConnect("VoltTech", "password")) { Serial.println("Failed to connect to WiFi and hit timeout"); ESP.restart(); delay(1000); } // Simpan parameter kustom ke variabel strncpy(ssid, WiFi.SSID().c_str(), sizeof(ssid)); strncpy(pass, WiFi.psk().c_str(), sizeof(pass)); strncpy(lokasi_id, custom_lokasi_id.getValue(), sizeof(lokasi_id)); strncpy(blynk_template_id, custom_blynk_template_id.getValue(), sizeof(blynk_template_id)); strncpy(blynk_template_name, custom_blynk_template_name.getValue(), sizeof(blynk_template_name)); strncpy(blynk_auth_token, custom_blynk_auth_token.getValue(), sizeof(blynk_auth_token)); // Simpan parameter kustom ke EEPROM EEPROM.writeString(0, lokasi_id); EEPROM.writeString(20, blynk_template_id); EEPROM.writeString(60, blynk_template_name); EEPROM.writeString(100, blynk_auth_token); EEPROM.commit(); // Tampilkan data yang ditulis ke EEPROM di Serial Monitor Serial.println("Saved new data to EEPROM:"); Serial.println("lokasi_id: " + String(lokasi_id)); Serial.println("blynk_template_id: " + String(blynk_template_id)); Serial.println("blynk_template_name: " + String(blynk_template_name)); Serial.println("blynk_auth_token: " + String(blynk_auth_token)); } // Initialize Blynk with obtained credentials Blynk.begin(blynk_auth_token, ssid, pass); // Menampilkan data yang digunakan ke Serial Monitor Serial.println("Final data used:"); Serial.println("lokasi_id: " + String(lokasi_id)); Serial.println("blynk_template_id: " + String(blynk_template_id)); Serial.println("blynk_template_name: " + String(blynk_template_name)); Serial.println("blynk_auth_token: " + String(blynk_auth_token)); // Inisialisasi OTA ArduinoOTA.begin(); buzzTwice(); uploadWireless(); lcd.init(); lcd.backlight(); lcd.print(" kWh-Meter "); delay(2000); lcd.clear(); configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); // Ensure time is properly set up // Wait for time to be set struct tm timeinfo; if (!getLocalTime(&timeinfo)) { Serial.println("Failed to obtain time"); } else { Serial.println("Time obtained successfully"); Serial.print("Current time: "); Serial.printf("%02d-%02d-%04d %02d:%02d:%02d\n", timeinfo.tm_mday, timeinfo.tm_mon + 1, timeinfo.tm_year + 1900, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); } } void loop() { ArduinoOTA.handle(); Blynk.run(); getDateTime(); unsigned long currentMillis = millis(); // Pernyataan debugging untuk memeriksa status relayState saat ini Serial.print("relayState: "); Serial.println(relayState); if (relayState == HIGH) { // Mode Otomatis Aktif controlRelayBasedOnSensor(); // Gunakan logika kontrol otomatis jika mode Otomatis } else { // Mode Otomatis Nonaktif digitalWrite(relayPin, LOW); // Matikan relay } float voltage = pzem.voltage(); float current = pzem.current(); float powerFactor = pzem.pf(); float power = voltage * powerFactor * current; float hours = 1; float energy = power * (hours / 1000); if (power >= 450) { // Aktifkan buzzer jika daya lebih besar dari atau sama dengan 5 W digitalWrite(buzzerPin, HIGH); if (currentMillis - previousMillis >= buzzerDuration) { digitalWrite(buzzerPin, LOW); // Matikan buzzer setelah 1 menit previousMillis = currentMillis; // Perbarui waktu sebelumnya } } else { digitalWrite(buzzerPin, LOW); } Serial.println("Pembacaan Sensor:"); Serial.print("Voltage: "); Serial.print(voltage); Serial.println(" V"); Serial.print("Current: "); Serial.print(current); Serial.println(" A"); Serial.print("Power Factor: "); Serial.println(powerFactor); Serial.print("Power: "); Serial.print(power); Serial.println(" W"); Serial.print("Energy: "); Serial.print(energy); Serial.println(" kWh"); Serial.println(); if (isnan(voltage) || isnan(current) || isnan(powerFactor)) { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Error membaca"); lcd.setCursor(0, 1); lcd.print("sensor"); } else { float biaya = (energy * tarifPerKWh); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Voltage: "); lcd.print(voltage); lcd.print("V"); lcd.setCursor(0, 1); lcd.print("Power: "); lcd.print(power); lcd.print("W"); delay(2000); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Pf: "); lcd.print(powerFactor); lcd.setCursor(0, 1); lcd.print("Energy: "); lcd.print(energy); lcd.print("kWh"); delay(2000); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Current: "); lcd.print(current); lcd.print("A"); lcd.setCursor(0, 1); lcd.print("Biaya: Rp. "); lcd.print(biaya, 2); delay(2000); unsigned long currentTime = millis(); if (currentTime - lastBlynkUpdateTime >= blynkUpdateInterval) { // Upload data ke Blynk Blynk.virtualWrite(V2, voltage); Blynk.virtualWrite(V3, current); Blynk.virtualWrite(V4, powerFactor); Blynk.virtualWrite(V5, power); Blynk.virtualWrite(V6, energy); Blynk.virtualWrite(V7, biaya); lastBlynkUpdateTime = currentTime; } if (currentTime - lastUploadTime >= uploadInterval) { int lokasi_id_int = atoi(lokasi_id); // Upload data ke server sendHttpPost(lokasi_id_int, voltage, power, powerFactor, energy, current, biaya, created_at); lastUploadTime = currentTime; } } } void controlRelayBasedOnSensor() { float power = pzem.power(); if (power >= 500) { digitalWrite(relayPin, LOW); // Matikan relay jika daya lebih dari atau sama dengan 20 W relayState = LOW; // Simpan status relay } else { digitalWrite(relayPin, HIGH); // Hidupkan relay jika daya kurang dari 20 W relayState = HIGH; // Simpan status relay } } void sendHttpPost(int lokasi_id, float voltage, float power, float powerFactor, float energy, float current, float biaya, const char* created_at) { if (WiFi.status() == WL_CONNECTED) { // Pastikan WiFi terhubung HTTPClient http; Serial.println("Memulai HTTP POST..."); http.begin("https://kantorku.cloud/voltech/upload/sensor_data.php"); http.addHeader("Content-Type", "application/json"); StaticJsonDocument<200> jsonDoc; jsonDoc["lokasi_id"] = lokasi_id; jsonDoc["voltage"] = voltage; jsonDoc["power"] = power; jsonDoc["power_factor"] = powerFactor; jsonDoc["energy"] = energy; jsonDoc["current"] = current; jsonDoc["biaya"] = biaya; jsonDoc["created_at"] = created_at; String jsonString; serializeJson(jsonDoc, jsonString); // Debugging: Cetak payload JSON Serial.print("Payload JSON: "); Serial.println(jsonString); // Kirim permintaan POST dengan payload JSON int httpResponseCode = http.POST(jsonString); if (httpResponseCode > 0) { Serial.print("Kode Respons HTTP: "); Serial.println(httpResponseCode); String response = http.getString(); Serial.println("Respons dari server: " + response); } else { Serial.print("Kode Kesalahan: "); Serial.println(httpResponseCode); } http.end(); } else { Serial.println("WiFi tidak terhubung"); } } void uploadWireless() { ArduinoOTA .onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) type = "sketch"; else // U_SPIFFS type = "filesystem"; Serial.println("Start updating " + type); }) .onEnd([]() { Serial.println("\nEnd"); }) .onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }) .onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); }); ArduinoOTA.begin(); Serial.println("Ready"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } void getDateTime() { struct tm timeinfo; if (!getLocalTime(&timeinfo)) { Serial.println("Failed to obtain time"); snprintf(created_at, sizeof(created_at), "0000-00-00 00:00:00"); } else { snprintf(created_at, sizeof(created_at), "%04d-%02d-%02d %02d:%02d:%02d", timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); } } BLYNK_WRITE(V1) { relayState = param.asInt(); // Mengubah status relay berdasarkan tombol Blynk V1 Serial.print("Relay state changed to: "); Serial.println(relayState); // Balikkan logika relay untuk modul relay aktif rendah if (relayState == 1) { digitalWrite(relayPin, LOW); // Hidupkan relay jika tombol Blynk diaktifkan } else { digitalWrite(relayPin, HIGH); // Matikan relay jika tombol Blynk dinonaktifkan } } void buzzTwice() { for (int i = 0; i < 2; i++) { digitalWrite(buzzerPin, HIGH); delay(200); digitalWrite(buzzerPin, LOW); delay(200); } }