// ====================================================== // LIBRARY // ====================================================== #include #include #include #include "time.h" // ====================================================== // WIFI // ====================================================== #define WIFI_SSID "siip" #define WIFI_PASSWORD "mbayardulu" // ====================================================== // FIREBASE // ====================================================== #define API_KEY "AIzaSyDwXyctX6eQSoUNBsMbD2CzbeVekdOuBdI" #define DATABASE_URL "https://tugas-akhir-9947b-default-rtdb.asia-southeast1.firebasedatabase.app/" #define USER_EMAIL "chika@gmail.com" #define USER_PASSWORD "chika123" FirebaseData fbdo; FirebaseAuth auth; FirebaseConfig config; // ====================================================== // PIN // ====================================================== const int pirPin1 = 32; const int pirPin2 = 21; const int trigPin = 4; const int echoPin = 18; const int buzzerPin = 14; const int servoPin1 = 25; const int servoPin2 = 26; const int servoPin3 = 27; const int soundPin = 33; // ====================================================== // SERVO // ====================================================== Servo servo1; Servo servo2; Servo servo3; // ====================================================== // VARIABLE // ====================================================== unsigned long lastTrigger = 0; unsigned long lastFirebase = 0; unsigned long lastMotionTime = 0; unsigned long lastAIRead = 0; unsigned long lastHistoryTime = 0; const unsigned long cooldown = 8000; const unsigned long pirHoldTime = 700; const unsigned long historyCooldown = 12000; String hasilAI = "tidak dikenal"; String lastStatus = "Aman"; int validCounter = 0; long lastDistance = 0; float lastSoundDB = 35; String lastDeteksi = "tidak dikenal"; long savedDistance = 0; float savedSoundDB = 0; String savedDeteksi = "tidak dikenal"; // ====================================================== // UPDATE STATUS // ====================================================== void updateStatus(String statusBaru) { if (!Firebase.ready()) return; if (statusBaru != lastStatus) { Firebase.RTDB.setString( &fbdo, "/Kebun/Status", statusBaru ); lastStatus = statusBaru; } } // ====================================================== // FORMAT WAKTU // ====================================================== String getFormattedTime() { struct tm timeinfo; if (!getLocalTime(&timeinfo)) { return "Waktu Error"; } char buffer[30]; strftime( buffer, sizeof(buffer), "%d-%m-%Y %H:%M:%S", &timeinfo ); return String(buffer); } // ====================================================== // SIMPAN HISTORY // ====================================================== void simpanRiwayatDeteksi() { if ( lastSoundDB <= 0 || lastDistance <= 2 || lastDistance > 60 ) { return; } FirebaseJson json; // ========================== // SENSOR PEMICU // ========================== String sensorPemicu = "-"; if (digitalRead(pirPin1) == HIGH && digitalRead(pirPin2) == HIGH) { sensorPemicu = "PIR 1 & PIR 2"; } else if (digitalRead(pirPin1) == HIGH) { sensorPemicu = "PIR 1"; } else if (digitalRead(pirPin2) == HIGH) { sensorPemicu = "PIR 2"; } json.set("sensor_pemicu", sensorPemicu); // ========================== // DATA RIWAYAT // ========================== json.set("jarak", lastDistance); json.set("db", lastSoundDB); json.set("deteksi", "burung"); json.set("pir1", digitalRead(pirPin1)); json.set("pir2", digitalRead(pirPin2)); json.set("waktu", getFormattedTime()); Firebase.RTDB.pushJSON( &fbdo, "/Kebun/Riwayat", &json ); } // ====================================================== // SETUP // ====================================================== void setup() { Serial.begin(115200); delay(2000); // WARMUP PIR delay(5000); analogReadResolution(12); analogSetPinAttenuation( soundPin, ADC_11db ); // ==================================================== // PINMODE // ==================================================== pinMode(pirPin1, INPUT_PULLDOWN); // Mengaktifkan pull-down internal pinMode(pirPin2, INPUT_PULLDOWN); // Mengaktifkan pull-down internal pinMode(soundPin, INPUT); pinMode(buzzerPin, OUTPUT); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); digitalWrite(buzzerPin, LOW); // ==================================================== // SERVO DETACH // ==================================================== servo1.detach(); servo2.detach(); servo3.detach(); // ==================================================== // WIFI // ==================================================== WiFi.begin(WIFI_SSID, WIFI_PASSWORD); WiFi.setSleep(false); Serial.print("Menghubungkan WiFi"); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(300); } Serial.println(); Serial.println("WiFi Connected"); // ==================================================== // INTERNET TIME // ==================================================== configTime( 7 * 3600, 0, "pool.ntp.org" ); // ==================================================== // FIREBASE // ==================================================== config.api_key = API_KEY; config.database_url = DATABASE_URL; auth.user.email = USER_EMAIL; auth.user.password = USER_PASSWORD; Firebase.begin(&config, &auth); Firebase.reconnectWiFi(true); Serial.println("Firebase Connected"); updateStatus("Aman"); } // ====================================================== // LOOP // ====================================================== void loop() { // ==================================================== // WIFI CHECK // ==================================================== if (WiFi.status() != WL_CONNECTED) { WiFi.disconnect(); WiFi.reconnect(); delay(1000); return; } // ==================================================== // FIREBASE READY // ==================================================== if (!Firebase.ready()) { return; } // ==================================================== // PIR // ==================================================== int pir1 = digitalRead(pirPin1); int pir2 = digitalRead(pirPin2); bool gerakan = false; if ( pir1 == HIGH || pir2 == HIGH ) { delay(80); if ( digitalRead(pirPin1) == HIGH || digitalRead(pirPin2) == HIGH ) { gerakan = true; lastMotionTime = millis(); } } // ==================================================== // HOLD PIR // ==================================================== if ( millis() - lastMotionTime < pirHoldTime ) { gerakan = true; } // ==================================================== // SENSOR // ==================================================== long distance = getDistanceAverage(); float soundDB = getSoundDB(); lastDistance = distance; lastSoundDB = soundDB; // ==================================================== // VALIDASI // ==================================================== bool jarakValid = false; bool aiValid = false; if ( distance > 2 && distance <= 60 // Batas maksimal sekarang 60 cm ) { jarakValid = true; } // ==================================================== // AI // ==================================================== if (millis() - lastAIRead > 1000) { lastAIRead = millis(); if ( Firebase.RTDB.getString( &fbdo, "/Kebun/AI/Klasifikasi" ) ) { hasilAI = fbdo.stringData(); hasilAI.trim(); hasilAI.toLowerCase(); if (gerakan) { lastDeteksi = hasilAI; } else { lastDeteksi = "tidak dikenal"; } } } if (hasilAI == "burung") { aiValid = true; } if (hasilAI == "burung" || hasilAI == "manusia") { savedDeteksi = hasilAI; savedDistance = distance; savedSoundDB = soundDB; } // ==================================================== // VALID COUNTER // ==================================================== if ( gerakan && jarakValid && aiValid ) { validCounter++; } else { validCounter = 0; } // ==================================================== // FIREBASE // ==================================================== if (millis() - lastFirebase > 3000) { lastFirebase = millis(); Firebase.RTDB.setInt( &fbdo, "/Kebun/Sensor/Jarak", lastDistance ); Firebase.RTDB.setFloat( &fbdo, "/Kebun/Sensor/Suara_dB", lastSoundDB ); // SIMPAN DETEKSI TERAKHIR YANG VALID if (gerakan && hasilAI == "burung") { savedDeteksi = "burung"; } else if (gerakan && hasilAI == "manusia") { savedDeteksi = "manusia"; } String deteksiFirebase = savedDeteksi; Serial.println("===== DEBUG FIREBASE ====="); Serial.print("Gerakan = "); Serial.println(gerakan); Serial.print("AI = "); Serial.println(hasilAI); Serial.print("deteksiFirebase = "); Serial.println(deteksiFirebase); Serial.println("=========================="); Firebase.RTDB.setString( &fbdo, "/Kebun/Sensor/Deteksi", deteksiFirebase ); // ========================== // PIR 1 // ========================== Firebase.RTDB.setInt( &fbdo, "/Kebun/Sensor/PIR1", pir1 ); // ========================== // PIR 2 // ========================== Firebase.RTDB.setInt( &fbdo, "/Kebun/Sensor/PIR2", pir2 ); Firebase.RTDB.setString( &fbdo, "/Kebun/Sensor/UpdateTerakhir", getFormattedTime() ); } // ==================================================== // MODE // ==================================================== int mode = 0; if ( Firebase.RTDB.getInt( &fbdo, "/kontrol/mode" ) ) { mode = fbdo.intData(); } // ==================================================== // MODE OTOMATIS // ==================================================== if (mode == 0) { updateStatus("Otomatis"); if ( validCounter >= 1 && millis() - lastTrigger > cooldown && millis() - lastHistoryTime > historyCooldown ) { lastTrigger = millis(); lastHistoryTime = millis(); updateStatus("Bahaya"); simpanRiwayatDeteksi(); aksiPengusiran(); validCounter = 0; } } // ==================================================== // MODE MANUAL // ==================================================== else { updateStatus("Manual"); int buzzerManual = 0; int servoManual = 0; Firebase.RTDB.getInt( &fbdo, "/kontrol/buzzer" ); buzzerManual = fbdo.intData(); Firebase.RTDB.getInt( &fbdo, "/kontrol/servo" ); servoManual = fbdo.intData(); // ================================================== // BUZZER MANUAL // ================================================== if (buzzerManual == 1) { digitalWrite(buzzerPin, HIGH); delay(5000); digitalWrite(buzzerPin, LOW); Firebase.RTDB.setInt( &fbdo, "/kontrol/buzzer", 0 ); } // ================================================== // SERVO MANUAL // ================================================== if (servoManual == 1) { aksiServoOnly(); Firebase.RTDB.setInt( &fbdo, "/kontrol/servo", 0 ); } } // ==================================================== // SERIAL MONITOR // ==================================================== Serial.println("========================"); Serial.print("PIR1: "); Serial.println(pir1); Serial.print("PIR2: "); Serial.println(pir2); Serial.print("Gerakan: "); Serial.println(gerakan); Serial.print("Jarak: "); Serial.print(distance); Serial.println(" cm"); Serial.print("dB: "); Serial.println(soundDB); Serial.print("AI: "); Serial.println(hasilAI); Serial.println("========================"); delay(100); } // ====================================================== // ULTRASONIK // ====================================================== long getDistanceRaw() { digitalWrite(trigPin, LOW); delayMicroseconds(5); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); long duration = pulseIn(echoPin, HIGH, 20000); if (duration == 0) { return -1; } long distance = duration * 0.0343 / 2; if ( distance < 2 || distance > 400 ) { return -1; } return distance; } // ====================================================== // ULTRASONIK FILTER // ====================================================== long getDistanceAverage() { long d1 = getDistanceRaw(); if ( d1 == -1 && lastDistance > 0 ) { d1 = lastDistance; } delay(3); long d2 = getDistanceRaw(); if ( d2 == -1 && lastDistance > 0 ) { d2 = lastDistance; } delay(3); long d3 = getDistanceRaw(); if ( d3 == -1 && lastDistance > 0 ) { d3 = lastDistance; } long values[3] = {d1, d2, d3}; for (int i = 0; i < 2; i++) { for (int j = i + 1; j < 3; j++) { if (values[j] < values[i]) { long temp = values[i]; values[i] = values[j]; values[j] = temp; } } } return values[1]; } // ====================================================== // SOUND SENSOR // ====================================================== float getSoundDB() { long total = 0; const int samples = 50; for (int i = 0; i < samples; i++) { total += analogRead(soundPin); delayMicroseconds(200); } float average = total / samples; float noise = abs(average - 2048); if (noise < 15) { noise = 0; } float db = 25 + (noise / 18.0); if (db > 75) db = 75; static float smoothDb = 35; smoothDb = (smoothDb * 0.75) + (db * 0.25); return smoothDb; } // ====================================================== // SERVO ONLY MANUAL // ====================================================== void aksiServoOnly() { servo1.attach(servoPin1); servo2.attach(servoPin2); servo3.attach(servoPin3); unsigned long startTime = millis(); while (millis() - startTime < 30000) { // ====================== // SERVO 1 // ====================== servo1.write(90); delay(700); servo1.write(0); delay(300); // ====================== // SERVO 2 // ====================== servo2.write(90); delay(700); servo2.write(0); delay(300); // ====================== // SERVO 3 // ====================== servo3.write(90); delay(700); servo3.write(0); delay(300); } servo1.detach(); servo2.detach(); servo3.detach(); } // ====================================================== // AKSI PENGUSIRAN OTOMATIS // ====================================================== void aksiPengusiran() { // ========================= // BUZZER DULU // ========================= digitalWrite(buzzerPin, HIGH); delay(3000); digitalWrite(buzzerPin, LOW); delay(300); // ========================= // SERVO // ========================= servo1.attach(servoPin1); servo2.attach(servoPin2); servo3.attach(servoPin3); unsigned long startTime = millis(); while (millis() - startTime < 30000) { // ====================== // SERVO 1 // ====================== servo1.write(90); delay(700); servo1.write(0); delay(300); // ====================== // SERVO 2 // ====================== servo2.write(90); delay(700); servo2.write(0); delay(300); // ====================== // SERVO 3 // ====================== servo3.write(90); delay(700); servo3.write(0); delay(300); } servo1.detach(); servo2.detach(); servo3.detach(); }