#include <IRremote.h>
#include <Servo.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
const int TRIG_pin = 9;
const int ECHO_pin = 10;
const int IR_pin = 2;
const int SERVO_pin = 3;
const int BUZZER_pin = 4;
const int BUTTON_pin = 5;
const int LED_pin = 6;
const int LDR_pin = A0;
Servo garageDoor;
enum SystemState {
IDLE,
CAR_APPROACHING,
AWAITING_LIGHTS,
DOOR_OPEN,
EXIT_SEQUENCE,
WAITING_REMOTE_CLOSE
};
SystemState currentState = IDLE;
unsigned long passwordStartTime = 0;
const unsigned long PASSWORD_TIMEOUT = 20000;
int lastLdrState = LOW;
int lightFlashes = 0;
unsigned long previousBuzzerMillis = 0;
int buzzerState = LOW;
int lastButtonState = LOW;
int lastDisplayedSecond = -1;
bool isParkingInside = false;
String scrollMsg = " Click remote or button to close... ";
int scrollIndex = 0;
unsigned long lastScrollTime = 0;
void setup() {
Serial.begin(9600);
pinMode(TRIG_pin, OUTPUT);
pinMode(ECHO_pin, INPUT);
pinMode(BUZZER_pin, OUTPUT);
pinMode(BUTTON_pin, INPUT);
pinMode(LED_pin, OUTPUT);
garageDoor.attach(SERVO_pin);
garageDoor.write(0);
IrReceiver.begin(IR_pin, ENABLE_LED_FEEDBACK);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("System IDLE");
Serial.println("System Initialized: IDLE");
}
void loop() {
long distance = getDistance();
int currentButtonState = digitalRead(BUTTON_pin);
if (currentButtonState == HIGH && lastButtonState == LOW) {
if (currentState == DOOR_OPEN || currentState == EXIT_SEQUENCE
|| currentState == WAITING_REMOTE_CLOSE) {
garageDoor.write(0);
digitalWrite(LED_pin, LOW);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Door Closed.");
lcd.setCursor(0, 1);
lcd.print("System Secured.");
Serial.println("Door manually closed. System Secured.");
delay(1500);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("System IDLE");
currentState = IDLE;
isParkingInside = false;
digitalWrite(BUZZER_pin, LOW);
} else {
garageDoor.write(90);
digitalWrite(LED_pin, HIGH);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Override Open!");
lcd.setCursor(0, 1);
lcd.print("Door Opened.");
Serial.println("Inside button pressed. Door Opened.");
delay(1500);
if (distance < 150) {
isParkingInside = true;
} else {
isParkingInside = false;
}
currentState = DOOR_OPEN;
digitalWrite(BUZZER_pin, LOW);
}
}
lastButtonState = currentButtonState;
switch (currentState) {
case IDLE:
if (IrReceiver.decode()) {
IrReceiver.resume();
}
if (distance > 0 && distance < 100) {
currentState = CAR_APPROACHING;
Serial.println("Car detected. Proximity warning active");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Car Detected!");
lcd.setCursor(0, 1);
lcd.print("Warning Active");
}
break;
case CAR_APPROACHING:
handleBuzzerProximity(distance);
if (IrReceiver.decode()) {
Serial.println("IR Received! Awaiting headlight flashes...");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("IR Received!");
lcd.setCursor(0, 1);
lcd.print("Pass: 0");
IrReceiver.resume();
currentState = AWAITING_LIGHTS;
digitalWrite(BUZZER_pin, LOW);
lightFlashes = 0;
passwordStartTime = millis();
lastDisplayedSecond = 20;
}
if (distance > 150 ) {
currentState = IDLE;
digitalWrite(BUZZER_pin, LOW);
Serial.println("Car left. Returning to IDLE.");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("System IDLE");
}
break;
case AWAITING_LIGHTS:
{
int ldrValue = analogRead(LDR_pin);
int currentLdrState = (ldrValue < 500) ? HIGH : LOW;
if (currentLdrState == HIGH && lastLdrState == LOW) {
lightFlashes++;
Serial.print("Pass ");
Serial.println(lightFlashes);
lcd.setCursor(6, 1);
lcd.print(lightFlashes);
delay(50);
}
lastLdrState = currentLdrState;
int secondsLeft = (PASSWORD_TIMEOUT - (millis() - passwordStartTime)) / 1000;
if (secondsLeft < 0) secondsLeft = 0;
if (secondsLeft != lastDisplayedSecond) {
lcd.setCursor(13, 1);
if (secondsLeft < 10) {
lcd.print(" ");
}
lcd.print(secondsLeft);
lcd.print("s");
lastDisplayedSecond = secondsLeft;
}
if (lightFlashes >= 3) {
Serial.println("Password Accepted: Opening Door!");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Pass Accepted!");
lcd.setCursor(0, 1);
lcd.print("Opening Door...");
garageDoor.write(90);
digitalWrite(LED_pin, HIGH);
currentState = DOOR_OPEN;
isParkingInside = true;
passwordStartTime = 0;
}
else if (millis() - passwordStartTime > PASSWORD_TIMEOUT) {
Serial.println("Timeout: Incorrect Password. Returning to scan.");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Timeout! Failed");
lcd.setCursor(0, 1);
lcd.print("Warning Active");
currentState = CAR_APPROACHING;
passwordStartTime = 0;
}
}
break;
case DOOR_OPEN:
if (distance > 0 && distance < 100) {
currentState = EXIT_SEQUENCE;
if (isParkingInside) {
Serial.println("Vehicle entering.");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Vehicle Detected");
lcd.setCursor(0, 1);
lcd.print("Parking In...");
} else {
Serial.println("Vehicle exiting. Auto-close ready.");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Vehicle Detected");
lcd.setCursor(0, 1);
lcd.print("Auto-Close Ready");
}
}
break;
case EXIT_SEQUENCE:
if (distance > 150) {
if (isParkingInside) {
Serial.println("Car parked inside. Awaiting manual close.");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Parked Already?");
currentState = WAITING_REMOTE_CLOSE;
scrollIndex = 0;
lastScrollTime = millis();
} else {
garageDoor.write(0);
digitalWrite(LED_pin, LOW);
Serial.println("Car has cleared the door. System Secured.");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Area Clear.");
lcd.setCursor(0, 1);
lcd.print("System Secured.");
delay(1500);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("System IDLE");
currentState = IDLE;
}
}
break;
case WAITING_REMOTE_CLOSE:
if (millis() - lastScrollTime > 300) {
lastScrollTime = millis();
lcd.setCursor(0, 1);
String displayStr = scrollMsg.substring(scrollIndex, scrollIndex + 16);
lcd.print(displayStr);
scrollIndex++;
if (scrollIndex > scrollMsg.length() - 16) {
scrollIndex = 0;
}
}
if (IrReceiver.decode()) {
IrReceiver.resume();
garageDoor.write(0);
digitalWrite(LED_pin, LOW);
Serial.println("Remote clicked. Door closed. System Secured.");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Door Closed.");
lcd.setCursor(0, 1);
lcd.print("System Secured.");
delay(1500);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("System IDLE");
currentState = IDLE;
isParkingInside = false;
}
break;
}
delay(50);
}
long getDistance() {
digitalWrite(TRIG_pin, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_pin, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_pin, LOW);
long duration = pulseIn(ECHO_pin, HIGH, 30000);
if (duration == 0) return 999;
return (duration / 2) * 0.0343;
}
void handleBuzzerProximity (long dist) {
int beepInterval;
if (dist > 80) beepInterval = 1000;
else if (dist > 40) beepInterval = 500;
else if (dist > 15) beepInterval = 150;
else beepInterval = 0;
if (beepInterval == 0) {
digitalWrite(BUZZER_pin, HIGH);
} else {
if (millis() - previousBuzzerMillis >= beepInterval) {
previousBuzzerMillis = millis();
if (buzzerState == LOW) {
buzzerState = HIGH;
digitalWrite(BUZZER_pin, HIGH);
} else {
buzzerState = LOW;
digitalWrite(BUZZER_pin, LOW);
}
}
}
}
SMART SECURE GARAGE SYSTEM
Garage Door
For Outside Components
For Inside Components
The Microcontroller
Inputs: Distance Sensor, Push Button, IR Receiver, and Photoresistor
Outputs: Servo Motor, LED, Buzzer, and I2C LCD
In the real world, the Servo VCC and GND must be connected to a dedicated external battery (with grounds tied to the Arduino) to prevent current overload.
The light sensor needs a physical cover (like a tube) to block the sun, and the code must automatically adjust to normal daylight so the sensor isn't blinded.
External User-Input: IR Remote
By: Bastasa, D S.
The IR Receiver must be installed outside, as most solid garage door materials will block the remote's light signal.