From 6211061a56b67cc6381fb189c50761d0c39cd4a4 Mon Sep 17 00:00:00 2001 From: Fajar Date: Fri, 4 Jul 2025 08:54:23 +0700 Subject: [PATCH] Menambahkan kode ARDUINO IDE --- Alat.ino | 512 ++++++++++++++++++++++++++++++++++++++++++++++++ Aplikasi Mobile | 1 + Koneksi Service | 1 + 3 files changed, 514 insertions(+) create mode 100644 Alat.ino create mode 160000 Aplikasi Mobile create mode 160000 Koneksi Service diff --git a/Alat.ino b/Alat.ino new file mode 100644 index 0000000..1ea2885 --- /dev/null +++ b/Alat.ino @@ -0,0 +1,512 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +// āœ… Firebase +#include "addons/TokenHelper.h" +#include "addons/RTDBHelper.h" +// Firebase +#define API_KEY "AIzaSyCaLvOB31bMXPwFfIz5Gy5ecGZhDs6kW34" +#define DATABASE_URL "https://sistemparkir-cc7d8-default-rtdb.firebaseio.com/" +#define LEGACY_TOKEN "1uQ1lRWJqVoxeuGaSbJvzjEGX9MpRdaqXCFAxrP0" + +// RFID Pins +#define SS_MASUK 19 +#define RST_MASUK 23 +#define SS_KELUAR 2 +#define RST_KELUAR 15 + +// SPI Shared Bus +#define SCK 17 +#define MISO 22 +#define MOSI 21 + +// Servo +#define SERVO_MASUK_PIN 33 +#define SERVO_KELUAR_PIN 25 + +// Buzzer +#define BUZZER_PIN 13 + +// IR Sensor +#define IR_MASUK_PIN 34 +#define IR_KELUAR_PIN 35 + +// LED Status +#define LED_PIN 12 + +// Tombol Reset +#define RESET_BUTTON_PIN 14 + + +const char* ssid = "Fajar"; +const char* password = "fajar123"; + +// Firebase objects +FirebaseData fbdo; +FirebaseAuth auth; +FirebaseConfig config; +String apiKey; +String databaseUrl; +const char* ntpServer = "time.nist.gov"; +const long gmtOffset_sec = 7 * 3600; // GMT+7 +const int daylightOffset_sec = 0; + + +// RFID & Servo +MFRC522 rfidMasuk(SS_MASUK, RST_MASUK); +MFRC522 rfidKeluar(SS_KELUAR, RST_KELUAR); +Servo servoMasuk; +Servo servoKeluar; + +// LCD +LiquidCrystal_I2C lcd(0x27, 16, 2); + +// Variabel +int totalSlot = 10; +int jumlahMasuk = 0; +int jumlahKeluar = 0; +int slotTerpakai = 0; +unsigned long previousMillis = 0; +bool ledState = false; + +unsigned long buttonPressStart = 0; +bool buttonPressed = false; +const unsigned long resetHoldTime = 10000; // 10 detik +bool emergencyActive = false; + + +void tampilkanDefaultLCD() { + int slotKosong = 0; + + // Mengambil data slot kosong langsung dari Firebase + if (Firebase.RTDB.getInt(&fbdo, "info_parkir/slot")) { + slotKosong = fbdo.intData(); // Mengambil nilai slot kosong dari Firebase + } + + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print(" SIPARKIR SLOT:"); + lcd.setCursor(0, 1); + lcd.print(" " + String(slotKosong)); // Menampilkan jumlah slot kosong dari Firebase +} + + +void tampilkanPesanLCD(String pesan) { + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print(pesan); + delay(3000); + tampilkanDefaultLCD(); +} + +void tampilkanPesanLCDDuaBaris(String baris1, String baris2) { + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print(baris1); + lcd.setCursor(0, 1); + lcd.print(baris2); + delay(3000); + tampilkanDefaultLCD(); +} + +bool bukaPintu(Servo& servo, int irPin, bool isMasuk) { + // Buka pintu + if (isMasuk) { + servo.write(90); // buka arah masuk + } else { + servo.write(90); // buka arah keluar (ubah dari 0 ke 90) + } + + Serial.println("šŸš— Pintu terbuka, menunggu kendaraan melewati sensor IR..."); + + unsigned long waktuMulai = millis(); + const unsigned long batasWaktu = 10000; // timeout jika kendaraan tidak muncul + bool terdeteksi = false; + + // Tunggu kendaraan muncul + while (!terdeteksi && (millis() - waktuMulai < batasWaktu)) { + if (digitalRead(irPin) == LOW) { + terdeteksi = true; + Serial.println("āœ… Kendaraan terdeteksi IR..."); + } + delay(100); + } + + if (!terdeteksi) { + Serial.println("āš ļø Tidak ada kendaraan yang muncul, timeout."); + + // Tutup pintu + if (isMasuk) { + servo.write(0); + } else { + servo.write(0); // tutup keluar (ubah dari 90 ke 0) + } + + return false; + } + + // Tunggu kendaraan lewat + while (digitalRead(irPin) == LOW) { + delay(100); + } + + Serial.println("āœ… Kendaraan sudah melewati sensor IR."); + + // Tutup pintu + if (isMasuk) { + servo.write(0); + } else { + servo.write(0); // ubah dari 90 ke 0 + } + + return true; +} + + + + + + +void updateFirebase() { + int slotKosong = totalSlot - slotTerpakai; + Firebase.RTDB.setInt(&fbdo, "info_parkir/masuk", jumlahMasuk); + Firebase.RTDB.setInt(&fbdo, "info_parkir/keluar", jumlahKeluar); + Firebase.RTDB.setInt(&fbdo, "info_parkir/slot", slotKosong); +} + +void kirimDataKeServer(String uid, String activity) { + HTTPClient http; + http.begin("https://esp32-firebase-service.vercel.app/api/kirim-data"); + + time_t now; + struct tm timeinfo; + if (!getLocalTime(&timeinfo)) { + Serial.println("āŒ Gagal mendapatkan waktu lokal"); + return; + } + + char timeString[30]; + strftime(timeString, sizeof(timeString), "%Y-%m-%dT%H:%M:%S.000Z", &timeinfo); + + String payload = "{\"uid\":\"" + uid + "\",\"activity\":\"" + activity + "\",\"time\":\"" + String(timeString) + "\"}"; + Serial.println("šŸ“¤ Kirim Payload: " + payload); + + http.begin("https://esp32-firebase-service.vercel.app/api/kirim-data"); // āœ… langsung tulis URL-nya + http.addHeader("Content-Type", "application/json"); + + int httpResponseCode = http.POST(payload); + + if (httpResponseCode > 0) { + Serial.printf("āœ… Kirim berhasil: %d\n", httpResponseCode); + String response = http.getString(); + Serial.println("Response: " + response); + } else { + Serial.printf("āŒ Kirim gagal: %s\n", http.errorToString(httpResponseCode).c_str()); + } + + http.end(); +} + + +void loadDataFromFirebase() { + if (Firebase.RTDB.getInt(&fbdo, "info_parkir/masuk")) { + jumlahMasuk = fbdo.intData(); + } + + if (Firebase.RTDB.getInt(&fbdo, "info_parkir/keluar")) { + jumlahKeluar = fbdo.intData(); + } + + int slotKosong = 10; + if (Firebase.RTDB.getInt(&fbdo, "info_parkir/slot")) { + slotKosong = fbdo.intData(); + } + + slotTerpakai = totalSlot - slotKosong; + + Serial.println("āœ… Data berhasil dimuat dari Firebase"); +} + + + +String getUID(MFRC522& rfid) { + String uid = ""; + for (byte i = 0; i < rfid.uid.size; i++) { + uid += String(rfid.uid.uidByte[i], HEX); + } + uid.toUpperCase(); + return uid; +} + +void bunyiBuzzerTerdaftar() { + digitalWrite(BUZZER_PIN, HIGH); + delay(100); + digitalWrite(BUZZER_PIN, LOW); +} + +void bunyiBuzzerTidakTerdaftar() { + for (int i = 0; i < 5; i++) { + digitalWrite(BUZZER_PIN, HIGH); + delay(100); + digitalWrite(BUZZER_PIN, LOW); + delay(400); + } +} +void prosesKartu(MFRC522& rfid, bool isMasuk) { + String rfidUID = getUID(rfid); + Serial.println((isMasuk ? "Masuk" : "Keluar") + String(" UID: ") + rfidUID); + String path = "daftar_kartu/" + rfidUID; + + if (Firebase.RTDB.getBool(&fbdo, path + "/value") && fbdo.boolData()) { + if (Firebase.RTDB.getBool(&fbdo, path + "/status")) { + bool status = fbdo.boolData(); + + if (isMasuk) { + if (!status) { // Belum masuk + if (slotTerpakai < totalSlot) { + tampilkanPesanLCD("Silahkan Masuk"); + + bool kendaraanLewat = bukaPintu(servoMasuk, IR_MASUK_PIN, true); + if (kendaraanLewat) { + jumlahMasuk++; // āœ… hanya tambah kalau IR mendeteksi kendaraan + slotTerpakai++; // āœ… + Firebase.RTDB.setBool(&fbdo, path + "/status", true); + updateFirebase(); + bunyiBuzzerTerdaftar(); + tampilkanDefaultLCD(); + kirimDataKeServer(rfidUID, "masuk"); + } else { + tampilkanPesanLCD("Gagal Masuk!"); + bunyiBuzzerTidakTerdaftar(); + } + } else { + tampilkanPesanLCD("Parkiran Penuh!"); + } + } else { + tampilkanPesanLCD("Sudah Masuk!"); + } + + } else { // Keluar + if (status) { // Sudah masuk + tampilkanPesanLCD("Terima Kasih"); + + bool kendaraanLewat = bukaPintu(servoKeluar, IR_KELUAR_PIN, false); + if (kendaraanLewat) { + jumlahKeluar++; // āœ… hanya kurang kalau IR mendeteksi kendaraan + slotTerpakai--; // āœ… + Firebase.RTDB.setBool(&fbdo, path + "/status", false); + updateFirebase(); + bunyiBuzzerTerdaftar(); + tampilkanDefaultLCD(); + kirimDataKeServer(rfidUID, "keluar"); + } else { + tampilkanPesanLCD("Gagal Keluar!"); + bunyiBuzzerTidakTerdaftar(); + } + } else { + tampilkanPesanLCD("Belum Masuk!"); + } + } + + } else { + tampilkanPesanLCD("Status Tidak Ada"); + bunyiBuzzerTidakTerdaftar(); + } + + } else { + tampilkanPesanLCDDuaBaris("Kartu Tidak", "Terdaftar"); + bunyiBuzzerTidakTerdaftar(); + } + + rfid.PICC_HaltA(); + rfid.PCD_StopCrypto1(); +} + + + +void resetDataFirebase() { + Serial.println("āš ļø Reset data Firebase..."); + + Firebase.RTDB.setInt(&fbdo, "info_parkir/masuk", 0); + Firebase.RTDB.setInt(&fbdo, "info_parkir/keluar", 0); + Firebase.RTDB.setInt(&fbdo, "info_parkir/slot", totalSlot); + + jumlahMasuk = 0; + jumlahKeluar = 0; + slotTerpakai = 0; + + // Ambil isi JSON + if (Firebase.RTDB.getJSON(&fbdo, "daftar_kartu")) { + FirebaseJson json = fbdo.to(); // Ambil JSON penuh + + String raw; + json.toString(raw, true); + Serial.println("šŸ“¦ Data JSON:"); + Serial.println(raw); + + size_t len = json.iteratorBegin(); + Serial.printf("šŸ” Total Key: %d\n", len); + + String uidKey, dummyVal; + int type; + + for (size_t i = 0; i < len; i++) { + json.iteratorGet(i, type, uidKey, dummyVal); + + if (uidKey.length() > 0) { + String statusPath = "daftar_kartu/" + uidKey + "/status"; + bool success = Firebase.RTDB.setBool(&fbdo, statusPath, false); + Serial.print("Set status false untuk UID "); + Serial.print(uidKey); + Serial.println(success ? " āœ… BERHASIL" : " āŒ GAGAL"); + } else { + Serial.println("āŒ UID kosong, dilewati"); + } + + delay(200); // Hindari limit koneksi + } + + json.iteratorEnd(); + } else { + Serial.println("āŒ Gagal ambil data daftar_kartu"); + } + + tampilkanPesanLCD("Data Direset"); +} + + +void setup() { + Serial.begin(115200); + + Wire.begin(27, 26); + lcd.init(); + lcd.backlight(); + tampilkanDefaultLCD(); + + + servoMasuk.attach(SERVO_MASUK_PIN); + servoKeluar.attach(SERVO_KELUAR_PIN); + + pinMode(BUZZER_PIN, OUTPUT); + pinMode(IR_MASUK_PIN, INPUT_PULLUP); + pinMode(IR_KELUAR_PIN, INPUT_PULLUP); + pinMode(LED_PIN, OUTPUT); + pinMode(RESET_BUTTON_PIN, INPUT_PULLUP); + + SPI.begin(SCK, MISO, MOSI, SS_MASUK); + rfidMasuk.PCD_Init(); + rfidKeluar.PCD_Init(); + + WiFi.mode(WIFI_STA); + + // Inisialisasi WiFi + WiFi.begin(ssid, password); + Serial.print("Menghubungkan ke WiFi..."); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("\nāœ… Terhubung ke WiFi"); + Serial.print("IP Address: "); + Serial.println(WiFi.localIP()); + + configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); + + Serial.println("Menunggu waktu NTP..."); + + struct tm timeinfo; + while (!getLocalTime(&timeinfo)) { + Serial.print("."); + delay(500); + } + Serial.println("\nWaktu NTP berhasil didapatkan:"); + Serial.println(&timeinfo, "%Y-%m-%d %H:%M:%S"); + + + // === Firebase config === + config.api_key = API_KEY; + config.database_url = DATABASE_URL; + config.signer.tokens.legacy_token = LEGACY_TOKEN; + + Firebase.begin(&config, &auth); + Firebase.reconnectWiFi(true); + + + // Load data awal dari Firebase + loadDataFromFirebase(); + + tampilkanDefaultLCD(); + + Serial.println("šŸš€ Setup selesai."); +} + + +void loop() { + if (WiFi.status() != WL_CONNECTED) { + unsigned long currentMillis = millis(); + if (currentMillis - previousMillis >= 500) { + previousMillis = currentMillis; + ledState = !ledState; + digitalWrite(LED_PIN, ledState); + } + return; + } else { + digitalWrite(LED_PIN, HIGH); + } + + int buttonState = digitalRead(RESET_BUTTON_PIN); + +if (buttonState == LOW && !buttonPressed) { + buttonPressed = true; + buttonPressStart = millis(); + emergencyActive = true; + + // Bunyikan buzzer darurat + digitalWrite(BUZZER_PIN, HIGH); + Serial.println("🚨 Tombol emergency ditekan - buzzer aktif"); +} + +if (buttonState == LOW && buttonPressed) { + if (millis() - buttonPressStart >= resetHoldTime) { + Serial.println("ā™»ļø Tombol ditekan lama - reset sistem"); + + // Matikan buzzer + digitalWrite(BUZZER_PIN, LOW); + resetDataFirebase(); + // Lakukan reset (misal: reset data parkir, atau restart ESP + + tampilkanPesanLCDDuaBaris("Sistem di-reset", "oleh petugas"); + + buttonPressed = false; + emergencyActive = false; + } +} + +if (buttonState == HIGH && buttonPressed) { + // Tombol dilepas sebelum 10 detik + digitalWrite(BUZZER_PIN, LOW); + buttonPressed = false; + emergencyActive = false; + Serial.println("šŸ”• Tombol emergency dilepas"); +} + + + if (rfidMasuk.PICC_IsNewCardPresent() && rfidMasuk.PICC_ReadCardSerial()) { + prosesKartu(rfidMasuk, true); + } + + if (rfidKeluar.PICC_IsNewCardPresent() && rfidKeluar.PICC_ReadCardSerial()) { + prosesKartu(rfidKeluar, false); + } +} diff --git a/Aplikasi Mobile b/Aplikasi Mobile new file mode 160000 index 0000000..9c33fe2 --- /dev/null +++ b/Aplikasi Mobile @@ -0,0 +1 @@ +Subproject commit 9c33fe273876c6cf926e2947ecd463a933406690 diff --git a/Koneksi Service b/Koneksi Service new file mode 160000 index 0000000..0615434 --- /dev/null +++ b/Koneksi Service @@ -0,0 +1 @@ +Subproject commit 06154348014f2c2f78be25991d39c3cceb1480aa