#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>
hd44780_I2Cexp lcd;
const int ldrPin = 32;
const int pirPin = 4;
const int buzzerPin = 12;
const int trigPin = 14;
const int echoPin = 27;
int LDR_DARK_THRESHOLD = 800;
int LDR_BRIGHT_THRESHOLD = 2500;
const float SOUND_SPEED = 0.034;
const int CLOSE_DISTANCE = 50;
const int MEDIUM_DISTANCE = 100;
const int MAX_DISTANCE = 200;
const int ULTRASONIC_SAMPLES = 3;
const int SAMPLE_COUNT = 5;
const int PIR_STABILIZE_TIME = 10000;
const int LOOP_DELAY = 1000;
unsigned long lastPirTrigger = 0;
const unsigned long PIR_RESET_TIME = 1000;
unsigned long lastBuzzerToggle = 0;
bool buzzerState = false;
const int FAST_BUZZER_INTERVAL = 300;
const int SLOW_BUZZER_INTERVAL = 1000;
int loopCounter = 0;
enum SystemStatus { AMAN, WASPADA, BAHAYA };
SystemStatus currentStatus = AMAN;
int readLDRAverage() {
long sum = 0;
for(int i = 0; i < SAMPLE_COUNT; i++) {
sum += analogRead(ldrPin);
delay(10);
}
return sum / SAMPLE_COUNT;
}
bool readPIRStable() {
bool currentState = digitalRead(pirPin);
Serial.print(" PIR Raw Reading: ");
Serial.println(currentState ? "HIGH" : "LOW");
if (currentState) {
delay(300);
if (digitalRead(pirPin)) {
lastPirTrigger = millis();
return true;
} else {
Serial.println(" PIR False Trigger - Tidak stabil");
return false;
}
}
if (millis() - lastPirTrigger < PIR_RESET_TIME) {
Serial.print(" PIR in reset period: ");
Serial.print(millis() - lastPirTrigger);
Serial.println(" ms");
return true;
}
return false;
}
float fuzzyGelap(int ldr) {
if (ldr <= LDR_DARK_THRESHOLD) return 1.0;
if (ldr >= LDR_BRIGHT_THRESHOLD) return 0.0;
return (float)(LDR_BRIGHT_THRESHOLD - ldr) / (LDR_BRIGHT_THRESHOLD - LDR_DARK_THRESHOLD);
}
float fuzzyTerang(int ldr) {
if (ldr <= LDR_DARK_THRESHOLD) return 0.0;
if (ldr >= LDR_BRIGHT_THRESHOLD) return 1.0;
return (float)(ldr - LDR_DARK_THRESHOLD) / (LDR_BRIGHT_THRESHOLD - LDR_DARK_THRESHOLD);
}
float fuzzyGerak(bool pir) {
return pir ? 1.0 : 0.0;
}
float readUltrasonicDistance() {
float totalDistance = 0;
int validReadings = 0;
for(int i = 0; i < ULTRASONIC_SAMPLES; i++) {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH, 30000);
if (duration > 0) {
float distance = (duration * SOUND_SPEED) / 2;
if (distance > 0 && distance <= MAX_DISTANCE) {
totalDistance += distance;
validReadings++;
}
}
delay(50);
}
return validReadings > 0 ? totalDistance / validReadings : -1;
}
float fuzzyDekat(float distance) {
if (distance <= 0) return 0.0;
if (distance <= CLOSE_DISTANCE) return 1.0;
if (distance >= MEDIUM_DISTANCE) return 0.0;
return (float)(MEDIUM_DISTANCE - distance) / (MEDIUM_DISTANCE - CLOSE_DISTANCE);
}
float fuzzySedang(float distance) {
if (distance <= 0) return 0.0;
if (distance <= CLOSE_DISTANCE) return 0.0;
if (distance >= MEDIUM_DISTANCE && distance <= MAX_DISTANCE) return 1.0;
if (distance > MAX_DISTANCE) return 0.0;
return (float)(distance - CLOSE_DISTANCE) / (MEDIUM_DISTANCE - CLOSE_DISTANCE);
}
float fuzzyJauh(float distance) {
if (distance <= 0) return 0.0;
if (distance <= MEDIUM_DISTANCE) return 0.0;
if (distance >= MAX_DISTANCE) return 1.0;
return (float)(distance - MEDIUM_DISTANCE) / (MAX_DISTANCE - MEDIUM_DISTANCE);
}
SystemStatus evaluateFuzzyLogic(int ldrValue, bool motion, float distance) {
float gelap = fuzzyGelap(ldrValue);
float terang = fuzzyTerang(ldrValue);
float gerak = fuzzyGerak(motion);
float dekat = fuzzyDekat(distance);
float sedang = fuzzySedang(distance);
float jauh = fuzzyJauh(distance);
float bahayaTinggi = gelap * gerak * dekat;
float bahaya = gelap * gerak * sedang;
float waspadaTinggi = terang * gerak * dekat;
float waspada = terang * gerak * sedang;
float waspadaRendah = gerak * jauh;
float aman = (1.0 - gerak);
if (!motion) return AMAN;
if (distance <= 0) return gelap >= 0.5 ? BAHAYA : WASPADA;
if (bahayaTinggi >= 0.4 || bahaya >= 0.4) return BAHAYA;
if (waspadaTinggi >= 0.4 || waspada >= 0.3) return WASPADA;
if (waspadaRendah >= 0.3) return WASPADA;
return WASPADA;
}
void controlBuzzer(SystemStatus status) {
unsigned long currentTime = millis();
switch(status) {
case BAHAYA:
if (currentTime - lastBuzzerToggle >= FAST_BUZZER_INTERVAL) {
buzzerState = !buzzerState;
digitalWrite(buzzerPin, buzzerState ? HIGH : LOW);
lastBuzzerToggle = currentTime;
}
break;
case WASPADA:
if (currentTime - lastBuzzerToggle >= SLOW_BUZZER_INTERVAL) {
buzzerState = !buzzerState;
digitalWrite(buzzerPin, buzzerState ? HIGH : LOW);
lastBuzzerToggle = currentTime;
}
break;
case AMAN:
digitalWrite(buzzerPin, LOW);
buzzerState = false;
break;
}
}
void updateLCD(SystemStatus status, int ldrValue, bool motion, float distance) {
lcd.clear();
switch(status) {
case BAHAYA:
lcd.setCursor(0, 0);
lcd.print("STATUS: BAHAYA!");
lcd.setCursor(0, 1);
if (distance > 0) {
lcd.print("Jarak: "); lcd.print((int)distance); lcd.print("cm");
} else lcd.print("Alarm Aktif");
break;
case WASPADA:
lcd.setCursor(0, 0);
lcd.print("STATUS: WASPADA");
lcd.setCursor(0, 1);
if (distance > 0) {
lcd.print("Jarak: "); lcd.print((int)distance); lcd.print("cm");
} else lcd.print("Ada Gerakan");
break;
case AMAN:
lcd.setCursor(0, 0);
lcd.print("STATUS: AMAN");
lcd.setCursor(0, 1);
lcd.print(ldrValue <= LDR_DARK_THRESHOLD ? "Malam Hari" : "Siang Hari");
break;
}
}
void setup() {
Serial.begin(115200);
delay(1000);
pinMode(pirPin, INPUT);
pinMode(buzzerPin, OUTPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
digitalWrite(buzzerPin, LOW);
digitalWrite(trigPin, LOW);
int status = lcd.begin(16, 2);
if (status == 0) {
lcd.clear(); lcd.print("Smart Monitor"); lcd.setCursor(0, 1); lcd.print("Starting...");
}
for(int i = PIR_STABILIZE_TIME/1000; i > 0; i--) {
if (status == 0) {
lcd.clear(); lcd.print("PIR Stabilizing"); lcd.setCursor(0, 1); lcd.print("Wait: "); lcd.print(i); lcd.print(" sec");
}
delay(1000);
}
if (status == 0) {
lcd.clear(); lcd.print("System Ready!"); lcd.setCursor(0, 1); lcd.print("Monitoring..."); delay(2000);
}
}
void loop() {
loopCounter++;
int ldrValue = readLDRAverage();
bool motion = readPIRStable();
float distance = readUltrasonicDistance();
SystemStatus newStatus = evaluateFuzzyLogic(ldrValue, motion, distance);
currentStatus = newStatus;
controlBuzzer(currentStatus);
updateLCD(currentStatus, ldrValue, motion, distance);
delay(LOOP_DELAY);
}