#include #include #include #include #include "RTClib.h" #include "time.h" #include // ===================================== // OBJECT // ===================================== Preferences prefs; RTC_DS3231 rtc; WiFiClientSecure client; // ===================================== // WIFI // ===================================== const char* ssid = "Galaxy A16 2CF8"; const char* password = "bismillah"; // ===================================== // FIREBASE // ===================================== String baseURL = "https://smartcabai-default-rtdb.firebaseio.com/"; // ===================================== // PIN // ===================================== #define SENSOR_PIN 34 #define RELAY_AIR 26 #define RELAY_PESTISIDA 27 // ===================================== // KALIBRASI SENSOR // ===================================== int nilaiKering = 3000; int nilaiBasah = 2200; int batasKering = 60; // ===================================== // VARIABEL SISTEM // ===================================== String mode = "AUTO"; String airStatus = "OFF"; String pestStatus = "OFF"; bool pestisidaNyala = false; unsigned long waktuMulaiPestisida = 0; unsigned long lastSemprotUnix = 0; unsigned long lastFirebase = 0; unsigned long lastGetMode = 0; unsigned long lastManualGet = 0; unsigned long firebaseCooldown = 0; bool firebaseError = false; // ===================================== // CONNECT WIFI // ===================================== void connectWiFi() { WiFi.mode(WIFI_STA); WiFi.setSleep(false); WiFi.setAutoReconnect(true); WiFi.persistent(true); WiFi.config( INADDR_NONE, INADDR_NONE, INADDR_NONE, IPAddress(8,8,8,8), IPAddress(8,8,4,4) ); WiFi.begin(ssid, password); Serial.print("Connecting WiFi"); int timeout = 0; while (WiFi.status() != WL_CONNECTED && timeout < 20) { delay(500); Serial.print("."); timeout++; } if (WiFi.status() == WL_CONNECTED) { Serial.println("\nWiFi Connected"); Serial.print("IP : "); Serial.println(WiFi.localIP()); } else { Serial.println("\nOFFLINE MODE"); } } // ===================================== // FIREBASE GET // ===================================== String getFirebase(String path) { if (WiFi.status() != WL_CONNECTED) { return ""; } HTTPClient http; String url = baseURL + path + ".json"; http.begin(client, url); http.setTimeout(10000); int httpCode = http.GET(); String hasil = ""; if (httpCode > 0) { hasil = http.getString(); hasil.replace("\"", ""); hasil.trim(); } else { firebaseError = true; firebaseCooldown = millis(); } http.end(); delay(100); return hasil; } // ===================================== // FIREBASE PUT // ===================================== // ===================================== // FIREBASE PUT // ===================================== void putFirebase(String path, String value, bool isString = false) { if (WiFi.status() != WL_CONNECTED) { return; } HTTPClient http; String url = baseURL + path + ".json"; http.begin(client, url); http.setTimeout(5000); http.addHeader( "Content-Type", "application/json" ); String payload; if (isString) { payload = "\"" + value + "\""; } else { payload = value; } int httpCode = http.PUT(payload); if (httpCode <= 0) { firebaseError = true; firebaseCooldown = millis(); } http.end(); } // ===================================== // GET UNIX RTC // ===================================== unsigned long getUnixTimeRTC() { DateTime now = rtc.now(); Serial.print("Tanggal RTC : "); Serial.print(now.day()); Serial.print("/"); Serial.print(now.month()); Serial.print("/"); Serial.print(now.year()); Serial.print(" "); Serial.print(now.hour()); Serial.print(":"); Serial.print(now.minute()); Serial.print(":"); Serial.println(now.second()); Serial.print("NOW UNIX : "); Serial.println(now.unixtime()); Serial.print("LAST UNIX : "); Serial.println(lastSemprotUnix); return now.unixtime(); } // ===================================== // SETUP // ===================================== void setup() { Serial.begin(115200); prefs.begin("spray", false); client.setInsecure(); // ================================= // RELAY // ================================= pinMode(RELAY_AIR, OUTPUT); pinMode(RELAY_PESTISIDA, OUTPUT); digitalWrite(RELAY_AIR, HIGH); digitalWrite(RELAY_PESTISIDA, HIGH); // ================================= // RTC // ================================= Wire.begin(21, 22); if (!rtc.begin()) { Serial.println("RTC ERROR"); while (1); } // ================================= // WIFI // ================================= connectWiFi(); // ================================= // SYNC RTC DARI INTERNET // ================================= configTime(7 * 3600, 0, "pool.ntp.org"); if (rtc.lostPower()) { struct tm timeinfo; if (getLocalTime(&timeinfo)) { rtc.adjust(DateTime( timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec )); Serial.println("RTC SYNC BERHASIL"); } else { Serial.println("GAGAL SYNC RTC"); } } // ================================= // AMBIL DATA LAST SEMPROT // ================================= String lastData = getFirebase("last_semprot"); if (lastData != "" && lastData != "null" && lastData != "0") { // dari firebase unsigned long temp = strtoul( lastData.c_str(), NULL, 10 ); if(temp > 0) { lastSemprotUnix = temp; } // simpan lokal prefs.putULong( "lastUnix", lastSemprotUnix ); Serial.println( "DATA DARI FIREBASE" ); } else { // dari memori lokal lastSemprotUnix = prefs.getULong( "lastUnix", 0 ); Serial.println( "DATA DARI MEMORI LOKAL" ); // jika belum ada data if (lastSemprotUnix == 0) { lastSemprotUnix = rtc.now().unixtime(); Serial.print("LAST SEMPROT BARU: "); Serial.println(lastSemprotUnix); prefs.putULong( "lastUnix", lastSemprotUnix ); Serial.println( "DATA BARU DIBUAT" ); } } Serial.println("SYSTEM READY"); } // ===================================== // LOOP // ===================================== void loop() { if(WiFi.status()!=WL_CONNECTED) { WiFi.reconnect(); } // ================================= // FIREBASE COOLDOWN // ================================= if (firebaseError && millis() - firebaseCooldown < 10000) { delay(1000); return; } firebaseError = false; // ================================= // STATUS WIFI // ================================= bool wifiConnected = (WiFi.status() == WL_CONNECTED); if (!wifiConnected) { mode = "AUTO"; } // ================================= // AMBIL MODE DARI FIREBASE // ================================= if (wifiConnected && millis() - lastGetMode >= 10000) { String firebaseMode = getFirebase("mode"); if (firebaseMode != "") { mode = firebaseMode; mode.trim(); } lastGetMode = millis(); } // ================================= // BACA SENSOR // ================================= int adc = analogRead(SENSOR_PIN); float kelembapan = ((float)(nilaiKering - adc) / (nilaiKering - nilaiBasah)) * 100; kelembapan = constrain( kelembapan, 0, 100 ); // ================================= // RTC // ================================= DateTime now = rtc.now(); int jam = now.hour(); int menit = now.minute(); // ================================= // HITUNG COUNTDOWN // ================================= unsigned long nowUnix = now.unixtime(); unsigned long intervalDetik = 120UL * 3600UL; unsigned long elapsedDetik = nowUnix - lastSemprotUnix; long sisaDetik; if (elapsedDetik >= intervalDetik) { sisaDetik = 0; } else { sisaDetik = intervalDetik - elapsedDetik; } // ================================= // FORMAT COUNTDOWN // ================================= int hariSisa = sisaDetik / 86400; int jamSisa = (sisaDetik % 86400) / 3600; int menitSisa = (sisaDetik % 3600) / 60; int detikSisa = sisaDetik % 60; String countdown; if (sisaDetik > 0) { countdown = String(hariSisa) + " Hari " + String(jamSisa) + " Jam " + String(menitSisa) + " Menit " + String(detikSisa) + " Detik"; } else { countdown = "Siap Semprot"; } // ================================= // KIRIM FIREBASE // ================================= if (wifiConnected && millis() - lastFirebase >= 1000) { putFirebase( "kelembapan", String(kelembapan, 1) ); putFirebase( "jeda_penyemprotan", countdown, true ); lastFirebase = millis(); } // ================================= // SERIAL MONITOR // ================================= Serial.print("Mode : "); Serial.print(mode); Serial.print(" ADC: "); Serial.print(adc); Serial.print( " || Kelembapan : " ); Serial.print( kelembapan, 1 ); Serial.print("%"); Serial.print( " ||Jeda Penyemprotan : " ); Serial.print(countdown); Serial.print(" || "); if (wifiConnected) { Serial.println("ONLINE"); } else { Serial.println("OFFLINE"); } // ================================= // MODE AUTO // ================================= if (mode == "AUTO") { // ============================= // POMPA AIR // ============================= if (kelembapan < batasKering) { digitalWrite( RELAY_AIR, LOW ); } else { digitalWrite( RELAY_AIR, HIGH ); } // ============================= // PESTISIDA OTOMATIS // ============================= if (sisaDetik <= 0 && !pestisidaNyala && WiFi.status()==WL_CONNECTED) { Serial.println("PESTISIDA MULAI"); digitalWrite( RELAY_PESTISIDA, LOW ); pestisidaNyala = true; waktuMulaiPestisida = millis(); } // ============================= // MATIKAN PESTISIDA // ============================= if (pestisidaNyala && millis() - waktuMulaiPestisida >= 7000) { Serial.println("PESTISIDA SELESAI"); digitalWrite( RELAY_PESTISIDA, HIGH ); pestisidaNyala = false; lastSemprotUnix = rtc.now().unixtime(); // simpan firebase putFirebase( "last_semprot", String(lastSemprotUnix) ); // simpan lokal prefs.putULong( "lastUnix", lastSemprotUnix ); } } // ================================= // MODE MANUAL // ================================= else if (mode == "MANUAL" && wifiConnected) { // ============================= // AMBIL STATUS MANUAL // ============================= if (millis() - lastManualGet >= 5000) { airStatus = getFirebase("pompa_air"); pestStatus = getFirebase( "pompa_pestisida" ); lastManualGet = millis(); } // ============================= // POMPA AIR // ============================= if (airStatus == "ON") { digitalWrite( RELAY_AIR, LOW ); } else { digitalWrite( RELAY_AIR, HIGH ); } // ============================= // POMPA PESTISIDA // ============================= if (pestStatus == "ON") { digitalWrite( RELAY_PESTISIDA, LOW ); } else { digitalWrite( RELAY_PESTISIDA, HIGH ); } } delay(3000); }