/*
* Proyek UAS Praktikum IoT: Smart Parking System
* Deskripsi:
* - Mengontrol palang parkir otomatis menggunakan Servo.
* - Menghitung jumlah kendaraan masuk/keluar menggunakan 2 Sensor IR.
* - Mengukur jarak aman parkir dengan Sensor Ultrasonik.
* - Memberi peringatan suara dengan Buzzer.
* - Menampilkan semua status pada LCD 20x4 dan platform Blynk.
*/
// ================= 1. KONFIGURASI BLYNK =================
// Ganti dengan kredensial dari Template Blynk Anda
#define BLYNK_TEMPLATE_ID "TMPLxxxxxxxx"
#define BLYNK_TEMPLATE_NAME "Smart Parking"
#define BLYNK_AUTH_TOKEN "GANTI_DENGAN_TOKEN_ANDA"
// ================= 2. INCLUDE LIBRARIES =================
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include "esp32-hal-timer.h" // Diperlukan untuk Servo di ESP32 Wokwi
// ================= 3. DEFINISI PIN & KONSTANTA =================
// === Konstanta & Pin Setup ===
const int pinPIRMasuk = 25;
const int pinPIRKeluar = 26;
const int pinTrig = 18;
const int pinEcho = 19;
const int pinServo = 27;
const int pinBuzzer = 33;
const int TOTAL_SLOT_PARKIR = 5;
const int JARAK_AMAN_CM = 20;
const int POSISI_BUKA = 90;
const int POSISI_TUTUP = 0;
// === Variabel Global ===
int mobilTerparkir = 0;
int slotTersedia = TOTAL_SLOT_PARKIR;
bool deteksiMasuk = false;
bool deteksiKeluar = false;
String statusGerbang = "TUTUP";
LiquidCrystal_I2C lcd(0x27, 20, 4);
Servo gerbangServo;
BlynkTimer timer;
// === Fungsi Update Tampilan ===
void updateLCD() {
lcd.clear();
lcd.setCursor(0, 0); lcd.print("Slot: "); lcd.print(slotTersedia); lcd.print("/"); lcd.print(TOTAL_SLOT_PARKIR);
lcd.setCursor(0, 1); lcd.print("Terparkir: "); lcd.print(mobilTerparkir); lcd.print(" mbl");
lcd.setCursor(0, 2); lcd.print("Gerbang: "); lcd.print(statusGerbang);
lcd.setCursor(0, 3);
if (slotTersedia == 0) lcd.print("PARKIRAN PENUH!");
else lcd.print("Status: Aman");
}
// === Fungsi Kontrol Servo ===
void kontrolGerbang(bool buka) {
gerbangServo.write(buka ? POSISI_BUKA : POSISI_TUTUP);
statusGerbang = buka ? "BUKA" : "TUTUP";
}
// === Fungsi Penghitungan Mobil Masuk/Keluar ===
void handlePIR() {
if (digitalRead(pinPIRMasuk) == HIGH && !deteksiMasuk) {
deteksiMasuk = true;
if (slotTersedia > 0) {
kontrolGerbang(true);
delay(3000);
mobilTerparkir++;
slotTersedia = TOTAL_SLOT_PARKIR - mobilTerparkir;
kontrolGerbang(false);
}
} else if (digitalRead(pinPIRMasuk) == LOW) {
deteksiMasuk = false;
}
if (digitalRead(pinPIRKeluar) == HIGH && !deteksiKeluar) {
deteksiKeluar = true;
if (mobilTerparkir > 0) {
kontrolGerbang(true);
delay(3000);
mobilTerparkir--;
slotTersedia = TOTAL_SLOT_PARKIR - mobilTerparkir;
kontrolGerbang(false);
}
} else if (digitalRead(pinPIRKeluar) == LOW) {
deteksiKeluar = false;
}
}
// === Fungsi Keamanan: Cek Jarak & Buzzer ===
void checkDistance() {
digitalWrite(pinTrig, LOW); delayMicroseconds(2);
digitalWrite(pinTrig, HIGH); delayMicroseconds(10);
digitalWrite(pinTrig, LOW);
long durasi = pulseIn(pinEcho, HIGH);
int jarak = durasi * 0.034 / 2;
if (jarak > 0 && jarak < JARAK_AMAN_CM) {
tone(pinBuzzer, 1000);
lcd.setCursor(0, 3); lcd.print("AWAS, JARAK DEKAT!");
Blynk.logEvent("safety_alert", "Mobil terlalu dekat!");
} else {
noTone(pinBuzzer);
}
Blynk.virtualWrite(V3, jarak);
}
// === Loop Utama Sistem ===
void runSystem() {
handlePIR();
checkDistance();
updateLCD();
Blynk.virtualWrite(V0, slotTersedia);
Blynk.virtualWrite(V1, mobilTerparkir);
Blynk.virtualWrite(V2, statusGerbang);
}
// === Setup Awal ===
void setup() {
Serial.begin(115200);
pinMode(pinPIRMasuk, INPUT);
pinMode(pinPIRKeluar, INPUT);
pinMode(pinTrig, OUTPUT);
pinMode(pinEcho, INPUT);
pinMode(pinBuzzer, OUTPUT);
lcd.init(); lcd.backlight(); lcd.print("Smart Parking");
gerbangServo.attach(pinServo); gerbangServo.write(POSISI_TUTUP);
Blynk.begin(BLYNK_AUTH_TOKEN, "Wokwi-GUEST", "");
timer.setInterval(1000L, runSystem);
}
// === Loop Arduino ===
void loop() {
Blynk.run();
timer.run();
}