This shows you the differences between two versions of the page.
iothings:proiecte:2025sric:esp32-smart-access-monitor [2025/05/29 16:54] robert_george.pancu [Introduction] |
iothings:proiecte:2025sric:esp32-smart-access-monitor [2025/05/29 17:48] (current) robert_george.pancu [Challenges] |
||
---|---|---|---|
Line 10: | Line 10: | ||
The aim is to provide a low-cost, responsive, and real-time system suitable for securing rooms, monitoring occupancy, and enhancing access control in small-scale environments such as labs, classrooms, or offices. | The aim is to provide a low-cost, responsive, and real-time system suitable for securing rooms, monitoring occupancy, and enhancing access control in small-scale environments such as labs, classrooms, or offices. | ||
====== Context ====== | ====== Context ====== | ||
+ | In today's world, real-time monitoring and automation are becoming essential in both residential and commercial environments. Manual tracking of occupancy or relying solely on physical access cards or keys has limitations in terms of scalability, logging, and remote monitoring. | ||
+ | This project addresses several modern needs: | ||
+ | |||
+ | * Remote access control using Wi-Fi and a web browser. | ||
+ | |||
+ | * Automated door management with time-based locking. | ||
+ | |||
+ | * Accurate real-time people counting using IR sensors and directional logic. | ||
+ | |||
+ | * Visual feedback using dynamic graphs and status messages on a web interface. | ||
+ | |||
+ | By combining IoT (Internet of Things) principles with basic access control and data visualization, this system serves as a foundation for smarter building management solutions. | ||
====== Hardware ====== | ====== Hardware ====== | ||
+ | Components: | ||
+ | * ESP32 | ||
+ | * 2 x IR sensor | ||
+ | * Buzzer | ||
+ | * wires | ||
+ | * breadboard | ||
+ | |||
+ | {{iothings:proiecte:2025sric:poza_esp.jpg?400 | ESP32 Setup}} | ||
====== Software ====== | ====== Software ====== | ||
+ | |||
+ | Technologies Used | ||
+ | |||
+ | * Arduino Framework (ESP32 Core): Used to program the microcontroller. | ||
+ | |||
+ | * HTML/CSS/JavaScript: Used for building a responsive web interface. | ||
+ | |||
+ | * Chart.js: JavaScript library used for rendering the real-time people count chart. | ||
+ | |||
+ | * Embedded Web Server (ESP32): Hosts the HTML page and handles HTTP requests. | ||
+ | |||
=== Code Snippets === | === Code Snippets === | ||
+ | |||
+ | <code cpp> | ||
+ | #include <WiFi.h> | ||
+ | #include <WebServer.h> | ||
+ | |||
+ | #define BUZZER_PIN 4 | ||
+ | #define IR_SENSOR_A 25 | ||
+ | #define IR_SENSOR_B 26 | ||
+ | |||
+ | const char* ssid = ""; | ||
+ | const char* wifiPassword = ""; | ||
+ | const char* correctPassword = ""; | ||
+ | |||
+ | WebServer server(80); | ||
+ | |||
+ | int peopleCount = 0; | ||
+ | unsigned long doorOpenTime = 0; | ||
+ | const unsigned long doorOpenDuration = 10000; | ||
+ | bool doorOpen = false; | ||
+ | |||
+ | enum IRState { | ||
+ | IDLE, | ||
+ | ENTER_STAGE_1, | ||
+ | EXIT_STAGE_1 | ||
+ | }; | ||
+ | |||
+ | IRState state = IDLE; | ||
+ | unsigned long lastTriggerTime = 0; | ||
+ | |||
+ | void buzzerSuccess() { | ||
+ | for (int i = 0; i < 3; i++) { | ||
+ | tone(BUZZER_PIN, 1000); | ||
+ | delay(150); | ||
+ | noTone(BUZZER_PIN); | ||
+ | delay(150); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void buzzerError() { | ||
+ | tone(BUZZER_PIN, 500); | ||
+ | delay(1000); | ||
+ | noTone(BUZZER_PIN); | ||
+ | } | ||
+ | |||
+ | void handleSubmit() { | ||
+ | if (!server.hasArg("pass")) { | ||
+ | server.send(400, "text/plain", "Bad Request"); | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | String enteredPass = server.arg("pass"); | ||
+ | if (enteredPass == correctPassword) { | ||
+ | doorOpen = true; | ||
+ | doorOpenTime = millis(); | ||
+ | buzzerSuccess(); | ||
+ | Serial.println("Door opened for 10 seconds."); | ||
+ | server.send(200, "text/plain", "Access Granted: door open"); | ||
+ | } else { | ||
+ | buzzerError(); | ||
+ | server.send(200, "text/plain", "Access Denied"); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void handleCount() { | ||
+ | String json = "{\"count\": " + String(peopleCount) + "}"; | ||
+ | server.send(200, "application/json", json); | ||
+ | } | ||
+ | |||
+ | void handleDoorStatus() { | ||
+ | if (doorOpen) { | ||
+ | server.send(200, "text/plain", "opened"); | ||
+ | } else { | ||
+ | server.send(200, "text/plain", "closed"); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void setup() { | ||
+ | Serial.begin(115200); | ||
+ | pinMode(BUZZER_PIN, OUTPUT); | ||
+ | pinMode(IR_SENSOR_A, INPUT_PULLUP); | ||
+ | pinMode(IR_SENSOR_B, INPUT_PULLUP); | ||
+ | |||
+ | WiFi.begin(ssid, wifiPassword); | ||
+ | while (WiFi.status() != WL_CONNECTED) { | ||
+ | delay(500); | ||
+ | Serial.print("."); | ||
+ | } | ||
+ | Serial.println("\nConnected to WiFi"); | ||
+ | Serial.println(WiFi.localIP()); | ||
+ | |||
+ | server.on("/", handleRoot); | ||
+ | server.on("/submit", HTTP_POST, handleSubmit); | ||
+ | server.on("/count", handleCount); | ||
+ | server.on("/doorstatus", handleDoorStatus); | ||
+ | server.begin(); | ||
+ | } | ||
+ | |||
+ | void loop() { | ||
+ | server.handleClient(); | ||
+ | |||
+ | unsigned long now = millis(); | ||
+ | int sensorA = digitalRead(IR_SENSOR_A); | ||
+ | int sensorB = digitalRead(IR_SENSOR_B); | ||
+ | |||
+ | if (doorOpen && now - doorOpenTime >= doorOpenDuration) { | ||
+ | doorOpen = false; | ||
+ | Serial.println("Door closed"); | ||
+ | state = IDLE; | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | if (!doorOpen) { | ||
+ | state = IDLE; | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | switch (state) { | ||
+ | case IDLE: | ||
+ | if (sensorA == LOW && sensorB == HIGH) { | ||
+ | state = ENTER_STAGE_1; | ||
+ | lastTriggerTime = now; | ||
+ | } else if (sensorB == LOW && sensorA == HIGH) { | ||
+ | state = EXIT_STAGE_1; | ||
+ | lastTriggerTime = now; | ||
+ | } | ||
+ | break; | ||
+ | |||
+ | case ENTER_STAGE_1: | ||
+ | if (sensorB == LOW && now - lastTriggerTime < 2000) { | ||
+ | peopleCount++; | ||
+ | Serial.print("Entered → Total: "); | ||
+ | Serial.println(peopleCount); | ||
+ | state = IDLE; | ||
+ | delay(500); | ||
+ | } else if (now - lastTriggerTime >= 2000) { | ||
+ | state = IDLE; | ||
+ | } | ||
+ | break; | ||
+ | |||
+ | case EXIT_STAGE_1: | ||
+ | if (sensorA == LOW && now - lastTriggerTime < 2000) { | ||
+ | peopleCount = max(0, peopleCount - 1); | ||
+ | Serial.print("Exited → Total: "); | ||
+ | Serial.println(peopleCount); | ||
+ | state = IDLE; | ||
+ | delay(500); | ||
+ | } else if (now - lastTriggerTime >= 2000) { | ||
+ | state = IDLE; | ||
+ | } | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </code> | ||
+ | |||
+ | WEB | ||
+ | |||
+ | {{iothings:proiecte:2025sric:dashboard.png?600 | Web Dashboard}} | ||
+ | |||
====== Challenges ====== | ====== Challenges ====== | ||
+ | Sensor Accuracy and Timing | ||
+ | |||
+ | * Differentiating between entry and exit requires precise detection and timing. | ||
+ | * Simultaneous movement or people hesitating at the doorway can cause incorrect counts. | ||
+ | * Solution: Implemented a state machine with timeouts to improve reliability. | ||
+ | |||
+ | Resource Limitations on ESP32 | ||
+ | |||
+ | * Hosting a full HTML page, JavaScript logic, and handling concurrent client requests pushed the memory limits. | ||
+ | * Optimized the web page content and avoided large libraries to keep the firmware lean. | ||
+ | |||
+ | Security Considerations | ||
+ | * Password is sent in plain text and checked locally, making it vulnerable in open networks. | ||
+ | * Future improvements could include HTTPS support or token-based authentication. | ||
====== References ====== | ====== References ====== | ||
+ | * https://ocw.cs.pub.ro/courses/iothings/laboratoare/2022/lab3 | ||
+ | * https://randomnerdtutorials.com/esp32-web-server-arduino-ide/ | ||
+ | * https://www.w3schools.com/ |