#include #include #include #include #include #include "addons/TokenHelper.h" #include "addons/RTDBHelper.h" #include // WiFi #define WIFI_SSID "redmii" #define WIFI_PASSWORD "87654321" // Firebase #define API_KEY "AIzaSyAEe82VtGAo4Q1zA1UPGWvLjJ0Bh_7ogdU" #define DATABASE_URL "https://amonia-a027f-default-rtdb.asia-southeast1.firebasedatabase.app/" #define USER_EMAIL "ardhaxiomi11@gmail.com" #define USER_PASSWORD "Ayam.1234" FirebaseData fbdo; FirebaseAuth auth; FirebaseConfig config; // DHT11 #define DHTPIN 14 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); // MQ135 #define MQ135_PIN 34 const float R0 = 9.50; const float RL = 10.0; // Aktuator #define RELAY1_PIN 4 #define RELAY2_PIN 12 #define BUZZER_PIN 13 // LCD LiquidCrystal_I2C lcd(0x27, 16, 2); // Interval pengiriman history (5 menit) unsigned long lastHistorySendTime = 0; const unsigned long historyInterval = 5 * 60 * 1000; // 5 menit // Tambahan: kendali manual buzzer int buzzerOverride = -1; // -1 = otomatis, 0 = buzzer mati manual void setup() { Serial.begin(115200); dht.begin(); lcd.init(); lcd.backlight(); pinMode(RELAY1_PIN, OUTPUT); pinMode(RELAY2_PIN, OUTPUT); pinMode(BUZZER_PIN, OUTPUT); digitalWrite(RELAY1_PIN, LOW); digitalWrite(RELAY2_PIN, LOW); digitalWrite(BUZZER_PIN, LOW); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nWiFi Connected"); // Sinkronisasi waktu NTP (GMT+7) configTime(25200, 0, "pool.ntp.org", "time.nist.gov"); struct tm timeinfo; while (!getLocalTime(&timeinfo)) { Serial.println("Gagal sinkronisasi waktu"); delay(1000); } // Firebase config.api_key = API_KEY; config.database_url = DATABASE_URL; auth.user.email = USER_EMAIL; auth.user.password = USER_PASSWORD; config.token_status_callback = tokenStatusCallback; Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); } void loop() { // Baca waktu struct tm timeinfo; if (!getLocalTime(&timeinfo)) { Serial.println("Gagal dapat waktu"); return; } time_t nowEpoch = mktime(&timeinfo); char datetimeStr[25]; // ✅ Ganti separator waktu ke titik: YYYY-MM-DD-HH.MM.SS strftime(datetimeStr, sizeof(datetimeStr), "%Y-%m-%d-%H.%M.%S", &timeinfo); // Baca sensor float temp = dht.readTemperature(); float hum = dht.readHumidity(); int analogValue = analogRead(MQ135_PIN); float voltage = analogValue * (3.3 / 4095.0); float Rs = ((3.3 * RL) / voltage) - RL; float ratio = Rs / R0; float ppm = 116.6020682 * pow(ratio, -2.769034857); float correctedPPM = ppm - 41.0; if (correctedPPM < 0) correctedPPM = 0; // 🔔 Ambil status buzzer manual dari Firebase if (Firebase.ready()) { if (Firebase.RTDB.getString(&fbdo, "/amonia_monitoring_realtime/buzzer")) { String sValue = fbdo.stringData(); int overrideValue = sValue.toInt(); buzzerOverride = overrideValue; Serial.print("Buzzer Override (from Firebase): "); Serial.println(buzzerOverride); } } // Aktuator if (correctedPPM > 25.0) { digitalWrite(RELAY1_PIN, HIGH); // Kipas selalu ON jika ppm tinggi if (buzzerOverride == 0) { digitalWrite(BUZZER_PIN, LOW); // Manual matikan buzzer } else { digitalWrite(BUZZER_PIN, HIGH); // Otomatis ON buzzer } } else { digitalWrite(RELAY1_PIN, LOW); // Kipas OFF jika ppm aman digitalWrite(BUZZER_PIN, LOW); // Buzzer OFF } // Relay2 otomatisasi lampu if (temp < 30.0) { digitalWrite(RELAY2_PIN, HIGH); // Lampu ON } else { digitalWrite(RELAY2_PIN, LOW); // Lampu OFF } // LCD realtime lcd.clear(); lcd.setCursor(0, 0); lcd.print("T:"); lcd.print(temp, 1); lcd.print((char)223); // derajat lcd.print("C H:"); lcd.print(hum, 0); lcd.print("%"); lcd.setCursor(0, 1); char buffer[9]; sprintf(buffer, "%02d:%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); lcd.print(buffer); lcd.print(" "); lcd.print((int)correctedPPM); // ✅ PPM ditampilkan sebagai bulat lcd.print("ppm"); // Kirim data realtime (SETIAP DETIK) if (Firebase.ready()) { String realtimePath = "/amonia_monitoring_realtime"; Firebase.RTDB.setFloat(&fbdo, realtimePath + "/temperature", temp); Firebase.RTDB.setFloat(&fbdo, realtimePath + "/humidity", hum); Firebase.RTDB.setFloat(&fbdo, realtimePath + "/ppm", (int)correctedPPM); // ✅ Bulatkan Firebase.RTDB.setString(&fbdo, realtimePath + "/waktu", String(datetimeStr)); } // Kirim data historis (TIAP 5 MENIT) unsigned long currentMillis = millis(); if (currentMillis - lastHistorySendTime >= historyInterval || lastHistorySendTime == 0) { lastHistorySendTime = currentMillis; String timestamp = String(nowEpoch); String historyPath = "/amonia_monitoring_history/" + timestamp; Firebase.RTDB.setFloat(&fbdo, historyPath + "/temperature", temp); Firebase.RTDB.setFloat(&fbdo, historyPath + "/humidity", hum); Firebase.RTDB.setFloat(&fbdo, historyPath + "/ppm", (int)correctedPPM); // ✅ Bulatkan Firebase.RTDB.setString(&fbdo, historyPath + "/waktu", String(datetimeStr)); } delay(1000); // Loop delay 1 detik }