#include <Arduino.h>
#include <Keypad.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ESP32Servo.h>
#include "driver/ledc.h"
// --- Shared variables ---
int pir1State, pir2State, peopleCount = 0;
const int PIRinput_1 = 13;
const int PIRinput_2 = 12;
const int ledPin = 27;
Servo servo;
const int servoPin = 4;
// Gas sensor
const int Buzzer = 25;
const int S_switch = 34;
float gasvalue;
float voltage;
// Keypad
#define row_num 4
#define col_num 4
char keys[row_num][col_num] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
byte row_pins[row_num] = {19, 18, 5, 17};
byte col_pins[col_num] = {16, 14, 2, 15};
LiquidCrystal_I2C lcd(0x27, 20, 4);
String password = "12345";
String input = "";
Keypad mykeypad = Keypad(makeKeymap(keys), row_pins, col_pins, row_num, col_num);
int attempts = 0;
bool locked = false;
unsigned long lockStart = 0;
const unsigned long lockTime = 60000; // 1 minute
// PWM parameters
const int pwmChannel = 0;
const int pwmFreq = 5000;
const int pwmResolution = 8;
const int maxPeople = 5; // full brightness threshold
// -------------------- SETUP --------------------
void setup() {
Serial.begin(115200);
pinMode(PIRinput_1, INPUT);
pinMode(PIRinput_2, INPUT);
pinMode(ledPin, OUTPUT);
pinMode(Buzzer, OUTPUT);
pinMode(S_switch, INPUT_PULLUP);
servo.attach(servoPin, 500, 2400);
lcd.init();
lcd.clear();
lcd.backlight();
lcd.setCursor(0,0);
lcd.print("Enter password:");
// --------- PWM LED Setup using native ESP32 driver ---------
// Configure timer
ledc_timer_config_t ledc_timer;
ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;
ledc_timer.duty_resolution = (ledc_timer_bit_t)pwmResolution;
ledc_timer.timer_num = LEDC_TIMER_0;
ledc_timer.freq_hz = pwmFreq;
ledc_timer.clk_cfg = LEDC_AUTO_CLK;
ledc_timer_config(&ledc_timer);
// Configure channel
ledc_channel_config_t ledc_channel;
ledc_channel.gpio_num = ledPin;
ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;
ledc_channel.channel = (ledc_channel_t)pwmChannel;
ledc_channel.intr_type = LEDC_INTR_DISABLE;
ledc_channel.timer_sel = LEDC_TIMER_0;
ledc_channel.duty = 0;
ledc_channel.hpoint = 0;
ledc_channel_config(&ledc_channel);
// --------- FreeRTOS tasks ---------
xTaskCreate(Lighting_control, "Lighting Task", 3000, NULL, 1, NULL);
xTaskCreate(door_function, "Door Task", 5000, NULL, 1, NULL);
xTaskCreate(gas_detection, "Gas Task", 5000, NULL, 1, NULL);
}
void loop() {
// Empty: all handled by FreeRTOS tasks
}
// -------------------- TASK 1: LIGHT CONTROL --------------------
void Lighting_control(void *pvParameters) {
int state = 0; // 0 = idle, 1 = PIR1 first, 2 = PIR2 first
bool waitingReset = false;
while (1) {
int pir1 = digitalRead(PIRinput_1);
int pir2 = digitalRead(PIRinput_2);
if (waitingReset) {
if (pir1 == LOW && pir2 == LOW) {
waitingReset = false;
state = 0;
}
} else {
switch (state) {
case 0:
if (pir1 == HIGH && pir2 == LOW) state = 1;
else if (pir2 == HIGH && pir1 == LOW) state = 2;
break;
case 1:
if (pir2 == HIGH) {
peopleCount++;
Serial.print("✅ Person Entered | Count = ");
Serial.println(peopleCount);
waitingReset = true;
}
break;
case 2:
if (pir1 == HIGH) {
if (peopleCount > 0) peopleCount--;
Serial.print("⬅️ Person Exited | Count = ");
Serial.println(peopleCount);
waitingReset = true;
}
break;
}
}
// PWM adaptive lighting
int brightness = map(peopleCount, 0, maxPeople, 0, 255);
brightness = constrain(brightness, 0, 255);
ledc_set_duty(LEDC_HIGH_SPEED_MODE, (ledc_channel_t)pwmChannel, brightness);
ledc_update_duty(LEDC_HIGH_SPEED_MODE, (ledc_channel_t)pwmChannel);
vTaskDelay(50 / portTICK_PERIOD_MS);
}
}
// -------------------- TASK 2: DOOR FUNCTION --------------------
void door_function(void *pvParameters) {
while (1) {
if (locked) {
unsigned long elapsed = millis() - lockStart;
unsigned long remaining = (lockTime - elapsed) / 1000;
lcd.setCursor(0, 0);
lcd.print("LOCKED! Wait... ");
lcd.setCursor(0, 1);
lcd.print("Time Left: ");
lcd.print(remaining);
lcd.print("s ");
Serial.print("Locked. Time left: ");
Serial.println(remaining);
if (elapsed >= lockTime) {
locked = false;
attempts = 0;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Enter password:");
Serial.println("Lock released. Try again.");
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
char key = mykeypad.getKey();
if (key) {
if (key == '#') { // Enter pressed
if (input.compareTo(password) == 0) {
lcd.setCursor(0, 2);
lcd.print("Password correct");
Serial.println("Password is correct");
vTaskDelay(1000 / portTICK_PERIOD_MS);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Enter password:");
attempts = 0;
// Servo open
for (int pos = 0; pos <= 180; pos += 10) {
servo.write(pos);
vTaskDelay(15 / portTICK_PERIOD_MS);
}
vTaskDelay(3000 / portTICK_PERIOD_MS);
// Servo close
for (int pos = 180; pos >= 0; pos -= 10) {
servo.write(pos);
vTaskDelay(15 / portTICK_PERIOD_MS);
}
} else {
attempts++;
Serial.println("Wrong password");
lcd.setCursor(0, 2);
lcd.print("Wrong password ");
vTaskDelay(1000 / portTICK_PERIOD_MS);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Re Enter password:");
lcd.setCursor(0,1);
lcd.print("No of attempts :");
lcd.print(attempts);
if (attempts >= 4) {
locked = true;
lockStart = millis();
lcd.clear();
lcd.setCursor(0,0);
lcd.print("LOCKED! Wait...");
Serial.println("LOCKED for 1 minute!");
}
}
input = ""; // reset
}
else if (key == '*') { // Clear input
input = "";
lcd.setCursor(0, 2);
lcd.print("Cleared ");
vTaskDelay(1000 / portTICK_PERIOD_MS);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Enter password:");
}
else {
input += key;
Serial.print(key);
int pos = input.length() - 1;
lcd.setCursor(pos, 2);
lcd.print(key);
vTaskDelay(500 / portTICK_PERIOD_MS);
lcd.setCursor(pos, 2);
lcd.print('*');
}
}
vTaskDelay(20 / portTICK_PERIOD_MS);
}
}
// -------------------- TASK 3: GAS + BUZZER --------------------
void gas_detection(void *pvParameters) {
bool buzzerActive = false;
while (1) {
gasvalue = analogRead(32);
voltage = (gasvalue / 4095.0) * 3.3;
Serial.print("Gas sensor Value: ");
Serial.println(gasvalue);
Serial.print("Voltage: ");
Serial.println(voltage);
int switchState = digitalRead(S_switch);
if (gasvalue > 3146) { // Gas detected
if (!buzzerActive) {
digitalWrite(Buzzer, HIGH);
buzzerActive = true;
Serial.println("🚨 Gas Detected! Buzzer ON");
}
if (switchState == LOW && buzzerActive) {
digitalWrite(Buzzer, LOW);
buzzerActive = false;
Serial.println("🔕 Buzzer manually stopped");
}
} else { // Safe
digitalWrite(Buzzer, LOW);
buzzerActive = false;
Serial.println("✅ Environment safe, buzzer OFF");
}
vTaskDelay(200 / portTICK_PERIOD_MS);
}
}