#include <ESP32Servo.h> // library used to control the servo motor using angles
// Pin setup
const int PIR_PIN = 27;
const int BUTTON_PIN = 26;
const int SERVO_PIN = 18;
// Servo positions
const int CLOSED_POS = 90;
const int OPEN_POS = 0;
// Timing
const unsigned long OPEN_DURATION = 10000;
const unsigned long DEBOUNCE_TIME = 200;
Servo gateServo;
// Button interrupt flag
volatile bool buttonTriggered = false;
volatile unsigned long lastButtonInterruptTime = 0;
// State
bool gateOpen = false;
unsigned long gateStartTime = 0;
// PIR edge detection
bool lastPirState = LOW;
// Button interrupt with debounce
void IRAM_ATTR handleButtonInterrupt() {
unsigned long now = millis();
if (now - lastButtonInterruptTime > DEBOUNCE_TIME) {
buttonTriggered = true;
lastButtonInterruptTime = now;
}
}
void openGate(const char* source) {
if (!gateOpen) {
gateServo.write(OPEN_POS);
gateOpen = true;
Serial.print("Gate Opened by: ");
Serial.println(source);
} else {
Serial.print("Timer Reset by: ");
Serial.println(source);
}
gateStartTime = millis();
}
void closeGate() {
gateServo.write(CLOSED_POS);
gateOpen = false;
Serial.println("Gate Closed Automatically.");
}
void setup() {
Serial.begin(115200);
pinMode(PIR_PIN, INPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
gateServo.attach(SERVO_PIN);
gateServo.write(CLOSED_POS);
// interrupt only for button
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), handleButtonInterrupt, FALLING);
Serial.println("System Active - Gate Closed.");
}
void loop() {
//PIR handled in loop
bool pirState = digitalRead(PIR_PIN);
// trigger only when PIR changes from LOW to HIGH
if (pirState == HIGH && lastPirState == LOW) {
openGate("PIR Sensor");
}
// update last PIR state
lastPirState = pirState;
//button handled by interrupt
if (buttonTriggered) {
buttonTriggered = false;
openGate("Pushbutton");
}
//auto close
if (gateOpen && (millis() - gateStartTime >= OPEN_DURATION)) {
closeGate();
}
}