diff --git a/ecomonitoring.ino b/ecomonitoring.ino new file mode 100644 index 0000000..c8f7e9c --- /dev/null +++ b/ecomonitoring.ino @@ -0,0 +1,260 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// === KREDENSIAL FIREBASE === +#define API_KEY "AIzaSyDiYpuUPQUvK-1fOztrblPKKn3cMTDrlXU" +#define DATABASE_URL "https://ecomoni-dc5fd-default-rtdb.firebaseio.com/" +#define LEGACY_TOKEN "Sd9aMsdVYzEV7QkvaJh79j4kd3vaCClvBAC78yjn" + +// === PIN SENSOR DAN KOMPONEN === +#define DHTPIN 4 +#define DHTTYPE DHT22 +#define RAIN_SENSOR_PIN 5 +#define LDR_PIN 34 +#define LED_STATUS 26 +#define BUTTON_PIN 27 + +// === OBJEK & VARIABEL GLOBAL === +FirebaseData fbdo; +FirebaseAuth auth; +FirebaseConfig config; +DHT dht(DHTPIN, DHTTYPE); +LiquidCrystal_I2C lcd(0x27, 16, 2); + +unsigned long lastUpdate = 0; +unsigned long interval = 5000; +unsigned long lastHistorySend = 0; +unsigned long intervalHistory = 300000; +int displayPage = 0; +bool isOfflineMode = false; + +void setupNTP() { + configTime(7 * 3600, 0, "pool.ntp.org", "time.nist.gov"); + struct tm timeinfo; + Serial.print("Sinkronisasi waktu NTP..."); + while (!getLocalTime(&timeinfo)) { + Serial.print("."); + delay(500); + } + Serial.println(" [BERHASIL]"); + Serial.print("Waktu sekarang: "); + Serial.println(&timeinfo, "%Y-%m-%d %H:%M:%S"); +} + +void updateIntervalHistoryFromFirebase() { + if (Firebase.RTDB.getInt(&fbdo, "/threshold/interval_history")) { + if (fbdo.dataType() == "int") { + int interval_minutes = fbdo.intData(); + intervalHistory = interval_minutes * 60000UL; + Serial.print("Interval diperbarui: "); + Serial.println(intervalHistory); + } + } else { + Serial.print("Gagal mengambil interval_history: "); + Serial.println(fbdo.errorReason()); + } +} + +void setup() { + Serial.begin(115200); + dht.begin(); + Wire.begin(22, 21); + lcd.init(); + lcd.backlight(); + + pinMode(RAIN_SENSOR_PIN, INPUT); + pinMode(LED_STATUS, OUTPUT); + pinMode(BUTTON_PIN, INPUT_PULLUP); + digitalWrite(LED_STATUS, LOW); + + lcd.setCursor(0, 0); + lcd.print("Menghubungkan..."); + + WiFiManager wm; + wm.setTimeout(60); // 1 menit + + if (!wm.autoConnect("EcoMonitor-Setup")) { + Serial.println("Gagal konek WiFi. Mode offline."); + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("Mode Offline"); + isOfflineMode = true; + delay(2000); + } else { + Serial.println("WiFi Terhubung!"); + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("WiFi Terhubung"); + digitalWrite(LED_STATUS, HIGH); + delay(2000); + + setupNTP(); + + config.api_key = API_KEY; + config.database_url = DATABASE_URL; + config.signer.tokens.legacy_token = LEGACY_TOKEN; + Firebase.begin(&config, &auth); + Firebase.reconnectWiFi(true); + updateIntervalHistoryFromFirebase(); + + lcd.clear(); + } +} + +void loop() { + // === Tombol untuk masuk mode konfigurasi WiFi (bisa online/offline) === + if (digitalRead(BUTTON_PIN) == LOW) { + Serial.println("Tombol ditekan. Masuk konfigurasi WiFi..."); + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("Config WiFi..."); + delay(1000); + + WiFiManager wm; + wm.resetSettings(); // Reset kredensial WiFi + wm.setTimeout(120); // Timeout 2 menit + wm.startConfigPortal("EcoMonitor-Setup"); + ESP.restart(); // Restart setelah config + } + + // === Mode Offline === + if (isOfflineMode) { + float suhu = dht.readTemperature(); + float kelembaban = dht.readHumidity(); + int hujan_status = digitalRead(RAIN_SENSOR_PIN); + int ldr_raw = analogRead(LDR_PIN); + int lux = map(ldr_raw, 0, 4095, 1000, 1); + lux = constrain(lux, 1, 1000); + String kondisi_hujan = (hujan_status == 1) ? "Cerah" : "Hujan"; + + lcd.clear(); + switch (displayPage) { + case 0: + lcd.setCursor(0, 0); + lcd.print(" Ecomonitor"); + break; + case 1: + lcd.setCursor(0, 0); + lcd.print("Suhu:"); + lcd.print(suhu, 0); + lcd.print((char)223); + lcd.print("C"); + lcd.setCursor(0, 1); + lcd.print("Kelembaban:"); + lcd.print(kelembaban, 0); + lcd.print("%"); + break; + case 2: + lcd.setCursor(0, 0); + lcd.print("Cahaya:"); + lcd.print(lux); + lcd.print(" Lux"); + lcd.setCursor(0, 1); + lcd.print("Cuaca:"); + lcd.print(kondisi_hujan); + break; + } + displayPage = (displayPage + 1) % 3; + delay(3000); + return; + } + + // === Mode Online === + if (millis() - lastUpdate >= interval && Firebase.ready()) { + lastUpdate = millis(); + + float suhu = dht.readTemperature(); + float kelembabanMentah = dht.readHumidity(); + float kelembaban = kelembabanMentah * 0.51; + kelembaban = constrain(kelembaban, 0, 100); + int hujan_status = digitalRead(RAIN_SENSOR_PIN); + int ldr_raw = analogRead(LDR_PIN); + int lux = map(ldr_raw, 0, 4095, 1000, 1); + lux = constrain(lux, 1, 1000); + String kondisi_hujan = (hujan_status == 1) ? "Cerah" : "Hujan"; + + Serial.printf("Suhu: %.2f °C\n", suhu); + Serial.printf("Kelembaban: %.2f %%\n", kelembaban); + Serial.printf("Cuaca: %s\n", kondisi_hujan.c_str()); + Serial.printf("Cahaya: %d lux\n", lux); + + lcd.clear(); + switch (displayPage) { + case 0: + lcd.setCursor(0, 0); + lcd.print(" Ecomonitor"); + break; + case 1: + lcd.setCursor(0, 0); + lcd.print("Suhu:"); + lcd.print(suhu, 0); + lcd.print((char)223); + lcd.print("C"); + lcd.setCursor(0, 1); + lcd.print("Kelembaban:"); + lcd.print(kelembaban, 0); + lcd.print("%"); + break; + case 2: + lcd.setCursor(0, 0); + lcd.print("Cahaya:"); + lcd.print(lux); + lcd.print(" Lux"); + lcd.setCursor(0, 1); + lcd.print("Cuaca:"); + lcd.print(kondisi_hujan); + break; + } + displayPage = (displayPage + 1) % 3; + delay(3000); + + Firebase.RTDB.setFloat(&fbdo, "/sensor/suhu", suhu); + Firebase.RTDB.setFloat(&fbdo, "/sensor/kelembaban", kelembaban); + Firebase.RTDB.setString(&fbdo, "/sensor/sensor_hujan", kondisi_hujan); + Firebase.RTDB.setInt(&fbdo, "/sensor/intensitas_cahaya", lux); + + if (millis() - lastHistorySend >= intervalHistory) { + lastHistorySend = millis(); + updateIntervalHistoryFromFirebase(); + + time_t now; + struct tm timeinfo; + if (!getLocalTime(&timeinfo)) { + Serial.println("Gagal mendapatkan waktu!"); + return; + } + + char isoTime[30]; + strftime(isoTime, sizeof(isoTime), "%Y-%m-%dT%H:%M:%S+07:00", &timeinfo); + + String jsonPayload = "{"; + jsonPayload += "\"intensitas_cahaya\":" + String(lux) + ","; + jsonPayload += "\"kelembaban\":" + String(kelembaban) + ","; + jsonPayload += "\"sensor_hujan\":" + String((hujan_status == 0) ? "true" : "false") + ","; + jsonPayload += "\"suhu\":" + String(suhu) + ","; + jsonPayload += "\"timestamp\":\"" + String(isoTime) + "\"}"; + + WiFiClientSecure client; + client.setInsecure(); + + HTTPClient http; + http.begin(client, "https://ecomonitor-api.vercel.app/api/kirimdata"); + http.addHeader("Content-Type", "application/json"); + int httpResponseCode = http.POST(jsonPayload); + + if (httpResponseCode > 0) { + Serial.printf("Data history terkirim (%d): %s\n", httpResponseCode, http.getString().c_str()); + } else { + Serial.printf("Gagal kirim data history: %s\n", http.errorToString(httpResponseCode).c_str()); + } + http.end(); + } + } +} \ No newline at end of file