diff --git a/smarthome.ino b/smarthome.ino new file mode 100644 index 0000000..b791981 --- /dev/null +++ b/smarthome.ino @@ -0,0 +1,378 @@ +#include +#include +#include +#include +#include + +// --- Pin & Sensor --- +#define DHTPIN 32 +#define DHTTYPE DHT11 +#define MQ2_PIN 34 +#define LDR_PIN 35 +#define RELAY_SENSOR_PIN 25 +#define RELAY_FINGERPRINT_PIN 13 +#define LDR_CONTROL_PIN 23 +#define BUZZER_PIN 4 +#define BUTTON_PIN 15 + +DHT dht(DHTPIN, DHTTYPE); +HardwareSerial mySerial(2); // RX = 16, TX = 17 +Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial); + +// --- WiFi & Firebase --- +const char* ssid = "Bellaa"; +const char* password = "bella0916"; +const String FIREBASE_HOST = "https://rumahoto-c7c9b-default-rtdb.firebaseio.com/"; +const String FIREBASE_AUTH = "AAIzaSyDhXwFT0yCV4lAXPyKIMcfRzbNIxVVudl8"; + +// --- Mode Tombol --- +enum ButtonMode { MODE_NONE, MODE_UNLOCK, MODE_ENROLL, MODE_RESET }; +ButtonMode currentMode = MODE_NONE; + +// --- Variabel --- +unsigned long buttonPressTime = 0; +bool buttonPressed = false; +bool fiveSecondBuzzed = false; +bool tenSecondBuzzed = false; +unsigned long lastSensorSend = 0; +const unsigned long SENSOR_INTERVAL = 1000; + +int threshold_ldr = 100; +int threshold_mq2 = 100; +int threshold_suhu = 30; + +int mq2Baseline = 300; +bool kalibrasiSelesai = false; +int statusPintu = 0; + +// --- Deklarasi Fungsi --- +void handleButton(); +void modeEnrollFingerprint(); +void modeResetFingerprint(); +void cekFingerprint(); +void bacaSensor(); +void kirimStatusPintuFirebase(int status); +void bacaThresholdFirebase(); +void kalibrasiMQ2(); +void buzzerOnce(); +uint8_t getNextAvailableID(); +uint8_t getFingerprintEnroll(uint8_t id); +int bacaLDRRataRata(int jumlah = 10); + +void setup() { + Serial.begin(9600); + dht.begin(); + + pinMode(RELAY_SENSOR_PIN, OUTPUT); + pinMode(RELAY_FINGERPRINT_PIN, OUTPUT); + pinMode(LDR_CONTROL_PIN, OUTPUT); + pinMode(BUZZER_PIN, OUTPUT); + pinMode(BUTTON_PIN, INPUT_PULLUP); + + digitalWrite(RELAY_SENSOR_PIN, LOW); + digitalWrite(RELAY_FINGERPRINT_PIN, LOW); + digitalWrite(LDR_CONTROL_PIN, LOW); + digitalWrite(BUZZER_PIN, LOW); + + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("\nWiFi Terhubung"); + + mySerial.begin(57600, SERIAL_8N1, 16, 17); + finger.begin(57600); + if (finger.verifyPassword()) { + Serial.println("Sensor Fingerprint terdeteksi."); + } else { + Serial.println("Sensor Fingerprint TIDAK terdeteksi."); + } + + kalibrasiMQ2(); +} + +void loop() { + handleButton(); + cekFingerprint(); + + if (millis() - lastSensorSend >= SENSOR_INTERVAL) { + lastSensorSend = millis(); + bacaThresholdFirebase(); + bacaSensor(); + } +} + +void handleButton() { + int state = digitalRead(BUTTON_PIN); + unsigned long now = millis(); + + if (state == LOW && !buttonPressed) { + buttonPressed = true; + buttonPressTime = now; + fiveSecondBuzzed = false; + tenSecondBuzzed = false; + } + + if (buttonPressed) { + unsigned long duration = now - buttonPressTime; + + if (duration >= 5000 && !fiveSecondBuzzed && duration < 10000) { + buzzerOnce(); + fiveSecondBuzzed = true; + } + + if (duration >= 10000 && !tenSecondBuzzed) { + buzzerOnce(); + tenSecondBuzzed = true; + } + } + + if (state == HIGH && buttonPressed) { + unsigned long duration = now - buttonPressTime; + buttonPressed = false; + + if (duration >= 10000) { + currentMode = MODE_RESET; + modeResetFingerprint(); + } else if (duration >= 5000) { + currentMode = MODE_ENROLL; + modeEnrollFingerprint(); + } else if (duration >= 50) { + currentMode = MODE_UNLOCK; + statusPintu = 1; + kirimStatusPintuFirebase(statusPintu); + digitalWrite(RELAY_FINGERPRINT_PIN, HIGH); + delay(5000); + digitalWrite(RELAY_FINGERPRINT_PIN, LOW); + statusPintu = 0; + kirimStatusPintuFirebase(statusPintu); + } + currentMode = MODE_NONE; + } +} + +void modeEnrollFingerprint() { + uint8_t id = getNextAvailableID(); + if (id == 0) { + Serial.println("Semua ID fingerprint sudah terpakai!"); + return; + } + + Serial.print("ID yang akan didaftarkan: "); + Serial.println(id); + + unsigned long enrollStart = millis(); + const unsigned long TIMEOUT = 30000; + bool success = false; + + while (millis() - enrollStart < TIMEOUT) { + Serial.println("Menunggu jari..."); + if (getFingerprintEnroll(id)) { + success = true; + break; + } else { + Serial.println("Gagal, coba lagi..."); + buzzerOnce(); + } + delay(1000); + } + + if (success) { + Serial.println("Pendaftaran berhasil."); + buzzerOnce(); + } else { + Serial.println("Pendaftaran dibatalkan (timeout)."); + for (int i = 0; i < 5; i++) { + buzzerOnce(); + delay(100); + } + } +} + +void modeResetFingerprint() { + Serial.println("Menghapus semua fingerprint..."); + for (int i = 0; i < 5; i++) { + buzzerOnce(); + delay(100); + } + + for (uint8_t i = 1; i <= 127; i++) { + finger.deleteModel(i); + } + Serial.println("Reset selesai."); +} + +void cekFingerprint() { + if (currentMode != MODE_NONE) return; + + if (finger.getImage() != FINGERPRINT_OK) return; + if (finger.image2Tz() != FINGERPRINT_OK || finger.fingerSearch() != FINGERPRINT_OK) { + buzzerOnce(); + return; + } + + Serial.print("Fingerprint cocok, ID: "); + Serial.println(finger.fingerID); + statusPintu = 1; + kirimStatusPintuFirebase(statusPintu); + digitalWrite(RELAY_FINGERPRINT_PIN, HIGH); + delay(5000); + digitalWrite(RELAY_FINGERPRINT_PIN, LOW); + statusPintu = 0; + kirimStatusPintuFirebase(statusPintu); +} + +void bacaSensor() { + if (!kalibrasiSelesai) { + Serial.println("Kalibrasi MQ2 belum selesai."); + return; + } + + float temp = dht.readTemperature(); + float hum = dht.readHumidity(); + int gasRaw = analogRead(MQ2_PIN); + float gasPercent = mq2Baseline != 0 ? ((float)gasRaw / mq2Baseline) * 100.0 : 0.0; + int ldrRaw = bacaLDRRataRata(); + + if (isnan(temp) || isnan(hum)) { + Serial.println("Sensor DHT11 error"); + return; + } + + Serial.printf("Suhu: %.2f °C, Hum: %.2f%%, MQ2: %.2f, LDR (avg): %d\n", temp, hum, gasPercent, ldrRaw); + + digitalWrite(RELAY_SENSOR_PIN, temp >= threshold_suhu ? HIGH : LOW); + digitalWrite(BUZZER_PIN, gasPercent > threshold_mq2 ? HIGH : LOW); + digitalWrite(LDR_CONTROL_PIN, ldrRaw >= threshold_ldr ? HIGH : LOW); + + if (WiFi.status() == WL_CONNECTED) { + HTTPClient http; + + String url = FIREBASE_HOST + "sensor.json?auth=" + FIREBASE_AUTH; + String payload = "{\"suhu\":" + String(temp) + ",\"kelembaban\":" + String(hum) + ",\"mq2\":" + String(gasPercent) + ",\"ldr\":" + String(ldrRaw) + "}"; + http.begin(url); + http.addHeader("Content-Type", "application/json"); + int res = http.PATCH(payload); + Serial.println(res > 0 ? "Data sensor terkirim!" : "Gagal kirim data sensor"); + http.end(); + + int statusLampu = digitalRead(LDR_CONTROL_PIN); + int statusBuzzer = digitalRead(BUZZER_PIN); + String statusPayload = "{\"lampu\":" + String(statusLampu) + ",\"pintu\":" + String(statusPintu) + ",\"buzzer\":" + String(statusBuzzer) + "}"; + String statusUrl = FIREBASE_HOST + "status.json?auth=" + FIREBASE_AUTH; + + http.begin(statusUrl); + http.addHeader("Content-Type", "application/json"); + int statusRes = http.PATCH(statusPayload); + Serial.println(statusRes > 0 ? "Status terkirim!" : "Gagal kirim status"); + http.end(); + } +} + +void kirimStatusPintuFirebase(int status) { + if (WiFi.status() == WL_CONNECTED) { + HTTPClient http; + String url = FIREBASE_HOST + "status.json?auth=" + FIREBASE_AUTH; + String payload = "{\"pintu\":" + String(status) + "}"; + http.begin(url); + http.addHeader("Content-Type", "application/json"); + int code = http.PATCH(payload); + Serial.println(code > 0 ? "Status pintu dikirim!" : "Gagal kirim status pintu"); + http.end(); + } +} + +void bacaThresholdFirebase() { + if (WiFi.status() == WL_CONNECTED) { + HTTPClient http; + String url = FIREBASE_HOST + "threshold.json?auth=" + FIREBASE_AUTH; + http.begin(url); + int res = http.GET(); + if (res == 200) { + String response = http.getString(); + DynamicJsonDocument doc(256); + deserializeJson(doc, response); + threshold_ldr = doc["ldr"] | threshold_ldr; + threshold_mq2 = doc["mq2"] | threshold_mq2; + threshold_suhu = doc["suhu"] | threshold_suhu; + } + http.end(); + } +} + +void kalibrasiMQ2() { + long total = 0; + const int sampleCount = 100; + Serial.println("Kalibrasi MQ2 sedang dilakukan..."); + + for (int i = 0; i < sampleCount; i++) { + total += analogRead(MQ2_PIN); + delay(50); + } + + mq2Baseline = total / sampleCount; + kalibrasiSelesai = true; + Serial.print("Kalibrasi selesai. Nilai baseline MQ2: "); + Serial.println(mq2Baseline); +} + +void buzzerOnce() { + digitalWrite(BUZZER_PIN, HIGH); + delay(100); + digitalWrite(BUZZER_PIN, LOW); +} + +uint8_t getNextAvailableID() { + for (uint8_t id = 1; id <= 127; id++) { + if (finger.loadModel(id) != FINGERPRINT_OK) return id; + } + return 0; +} + +uint8_t getFingerprintEnroll(uint8_t id) { + int p = -1; + Serial.println("Letakkan jari..."); + + unsigned long timeoutStart = millis(); + while (p != FINGERPRINT_OK) { + if (millis() - timeoutStart > 30000) { + Serial.println("Timeout jari pertama."); + return false; + } + p = finger.getImage(); + if (p == FINGERPRINT_NOFINGER) delay(100); + } + if (finger.image2Tz(1) != FINGERPRINT_OK) return false; + + Serial.println("Angkat jari..."); + delay(1000); + while (finger.getImage() != FINGERPRINT_NOFINGER) delay(100); + + Serial.println("Letakkan lagi..."); + timeoutStart = millis(); + while (finger.getImage() != FINGERPRINT_OK) { + if (millis() - timeoutStart > 30000) { + Serial.println("Timeout jari kedua."); + return false; + } + delay(100); + } + if (finger.image2Tz(2) != FINGERPRINT_OK) return false; + + if (finger.createModel() != FINGERPRINT_OK) return false; + if (finger.storeModel(id) != FINGERPRINT_OK) return false; + + return true; +} + +int bacaLDRRataRata(int jumlah) { + long total = 0; + for (int i = 0; i < jumlah; i++) { + total += analogRead(LDR_PIN); + delay(5); + } + return total / jumlah; +} + +