import sounddevice as sd import numpy as np import librosa import joblib import firebase_admin import time from firebase_admin import credentials, db # ===================================================== # FIREBASE SETUP # ===================================================== cred = credentials.Certificate("serviceAccountKey.json") firebase_admin.initialize_app(cred, { 'databaseURL': 'https://tugas-akhir-9947b-default-rtdb.asia-southeast1.firebasedatabase.app/' }) ref = db.reference("/Kebun") # ===================================================== # LOAD MODEL & LABEL # ===================================================== model = joblib.load("model_burung.pkl") label_map = { 10: "manusia", 20: "burung" } # ===================================================== # PARAMETER # ===================================================== duration = 2.0 fs = 22050 MIN_VOLUME = 0.06 MIN_CONFIDENCE = 0.75 MAX_DISTANCE = 300 # ===================================================== # HOLD DETEKSI & TIMER # ===================================================== DETECTION_HOLD = 5 last_detection_time = 0 last_result = "tidak dikenal" last_firebase_update = 0 firebase_interval = 2 print("===================================") print("AI KNN BURUNG AKTIF") print("Listening...") print("===================================") # ===================================================== # LOOP # ===================================================== while True: try: # ============================================= # AMBIL SENSOR FIREBASE # ============================================= jarak = 0 suara_sensor = 0 try: sensor_data = ref.child("Sensor").get() if sensor_data: if "Jarak" in sensor_data: jarak = int(sensor_data["Jarak"]) if "Suara_dB" in sensor_data: suara_sensor = float(sensor_data["Suara_dB"]) except Exception as e: print("Gagal baca sensor:", e) # ============================================= # RECORD AUDIO # ============================================= audio = sd.rec( int(duration * fs), samplerate=fs, channels=1, device=1, dtype='float32' ) sd.wait() audio = audio.flatten() # ============================================= # HITUNG VOLUME & KONVERSI dB # ============================================= volume = np.max(np.abs(audio)) db_value = int(volume * 85) if db_value < 30: db_value = 30 if db_value > 85: db_value = 85 print("Volume:", round(volume, 4)) print("dB:", db_value) # ============================================= # DEFAULT # ============================================= hasil = "tidak dikenal" confidence = 0.0 # ============================================= # DEBUG FILTER # ============================================= print("========== FILTER ==========") print("Volume :", round(volume, 4)) print("Min Volume :", MIN_VOLUME) print("Jarak :", jarak) print("Max Jarak :", MAX_DISTANCE) if volume < MIN_VOLUME: print("SKIP -> Volume terlalu kecil") if suara_sensor < 60: print("SKIP -> Suara sensor ESP32 kurang dari 60 dB") if jarak <= 2: print("SKIP -> Jarak terlalu dekat") if jarak > MAX_DISTANCE: print("SKIP -> Jarak terlalu jauh") # ============================================= # FILTER NOISE & PREDIKSI # ============================================= if (volume >= MIN_VOLUME and suara_sensor >= 60 and jarak > 2 and jarak <= MAX_DISTANCE): # NORMALISASI & MFCC audio = librosa.util.normalize(audio) mfcc = librosa.feature.mfcc(y=audio, sr=fs, n_mfcc=13) mfcc_scaled = np.mean(mfcc.T, axis=0).reshape(1, -1) # PREDIKSI proba = model.predict_proba(mfcc_scaled)[0] prediksi = model.predict(mfcc_scaled)[0] print("Probabilitas :", proba) confidence = float(np.max(proba)) predicted_label = label_map.get(prediksi, "tidak dikenal") print("Raw Prediksi :", prediksi) print("Label :", predicted_label) print("Confidence :", round(confidence, 2)) # ========================================= # VALIDASI HASIL AI (Sudah di dalam posisi Indentasi yang Benar) # ========================================= sorted_proba = np.sort(proba) highest = sorted_proba[-1] second = sorted_proba[-2] selisih = highest - second print("Selisih Proba :", round(selisih, 2)) if (confidence >= 0.75 and selisih >= 0.20 and predicted_label in ["manusia", "burung"]): hasil = predicted_label else: hasil = "tidak dikenal" # ============================================= # HOLD HASIL DETEKSI # ============================================= current_time = time.time() if hasil in ["manusia", "burung"]: last_result = hasil last_detection_time = current_time # TAHAN HASIL if (current_time - last_detection_time) < DETECTION_HOLD: hasil_tampil = last_result else: hasil_tampil = "tidak dikenal" # ============================================= # DEBUG TAMPILAN # ============================================= print("Confidence:", round(confidence, 2)) print("Hasil AI:", hasil) print("Tampil:", hasil_tampil) print("Jarak Firebase:", jarak) print("Suara Sensor:", suara_sensor) print("----------------") # ============================================= # UPDATE FIREBASE # ============================================= if (current_time - last_firebase_update) >= firebase_interval: last_firebase_update = current_time ref.update({ "AI": { "Klasifikasi": hasil_tampil, "Confidence": round(confidence, 2), "Volume": round(float(volume), 4) } }) # ============================================= # DELAY # ============================================= time.sleep(0.3) except Exception as e: print("ERROR:", e) try: ref.update({ "AI": { "Klasifikasi": "error", "Confidence": 0, "Volume": 0 } }) except: pass time.sleep(1)