Differences

This shows you the differences between two versions of the page.

Link to this comparison view

iothings:proiecte:2025sric:security-system-to_detect-movement-and-capture-image [2025/05/29 09:43]
felicia.saghin [Software]
iothings:proiecte:2025sric:security-system-to_detect-movement-and-capture-image [2025/05/29 11:19] (current)
felicia.saghin [Introduction]
Line 7: Line 7:
  
 ====== Introduction ====== ====== Introduction ======
-In today’s connected world, real-time security monitoring at home or in small offices ​has become ​both practical and affordable. This project delivers a lightweight IoT door-security solution by combining an ESP32-CAM module with a Hall-effect sensor. Whenever the door opens, the sensor immediately signals the ESP32-CAM to capture a high-resolution ​image. That image is then uploaded to Firebase Storage, ​and its publicly accessible URL is written to Firebase Realtime Database. Simultaneously,​ Twilio’s API is invoked to send an SMS to your smartphone. Finally, a web gallery hosted on Firebase ​displays ​the latest ​snapshot instantly, giving you secure ​and remote visibility of every entry event.+In today’s connected world, real-time security monitoring at home or in small offices ​is both practical and affordable. This project delivers a lightweight IoT door-security solution by combining an ESP32-CAM module with a Hall-effect sensor. Whenever the door opens, the sensor immediately signals the ESP32-CAM to capture a high-resolution ​JPEG, which is then Base64-encoded ​and stored directly in Firebase Realtime Database. Simultaneously,​ Twilio’s API sends an SMS alert with a link to your live web gallery. A responsive dashboard ​hosted on Firebase ​Hosting listens for new entries in the database and displays each snapshot instantly, giving you secureremote visibility of every entry event.
 ====== Context ====== ====== Context ======
 __**Diagram**__ __**Diagram**__
Line 62: Line 62:
 ====== Software Design ====== ====== Software Design ======
  
-<note tip>I used **VS Code** with the **PlatformIO IDE** extension. +I used **VS Code** with the **PlatformIO IDE** extension.
-I’ve built the core logic so that each door-open triggers exactly one clean sequence:+
  
-  * A debounce routine on the Hall sensor waits for the input to remain stable (no rapid bouncing) for ~50 ms before recognizing a genuine open event.+====== Key Project Features ======
  
-  ​I track the previous sensor state to detect a rising edge (closed→open) ​and ignore all other transitions.+**Firebase Realtime Database** ​  
 +  Instant data synchronization between ​the ESP32-CAM device ​and the web dashboard.
  
-  * On that single edge, the ESP32-CAM captures a JPEG, then immediately:​+**Image Processing** ​  
 +  Automated ​JPEG capture, Base64 encodingand seamless cloud upload.
  
-  ​  ​Uploads it to Firebase Storage over HTTPS.+**SMS Notifications (Twilio)** ​  
 +  Instant SMS alerts via Twilio API with direct gallery links.
  
-  ​  ​Parses the JSON response to extract the download URL.+**Responsive Web Dashboard** ​  
 +  Mobile-friendly interface for real-time image monitoring and history review.
  
-  ​  ​Writes that into Firebase Realtime Database.+**Hall Sensor Integration** ​  
 +  Magnetic door-open detection with software debouncing to ensure one capture per event.
  
-  ​  ​Calls Twilio’s REST API (over secure TLS) to send an SMS with the gallery link.+**PSRAM Optimization** ​  
 +  Advanced PSRAM configuration on ESP32-CAM for reliable image buffering and processing.
  
-After each step I check for errors and retry once if something fails (network hiccupJSON parse erroretc.).+- **Modern Web Technologies** ​  
 +  Built with HTML5CSS3JavaScript ES6+, Firebase Hosting, and fetch API for a smooth user experience 
  
-Finally, I release the camera buffer and reset state, so the loop stays non-blocking (using millis() for timing) and immediately resumes listening for the next door-open. 
  
-All of this makes the system rock-solid: one photo, one upload, one DB update, one SMS—every single time. 
  
 +=== Code Snippets ===
 +<​code>​
 +bool uploadImageToFirebase(camera_fb_t* fb, const char* source) {
 +    if (!fb || !fb->buf || fb->len == 0) {
 +        return false;
 +    }
 +    ​
 +    // Convert to base64 encoding
 +    size_t required_len = ((fb->​len + 2) / 3) * 4 + 1;
 +    char* base64_buffer = (char*)malloc(required_len);​
 +    ​
 +    size_t olen = 0;
 +    int ret = mbedtls_base64_encode((unsigned char*)base64_buffer, ​
 +                                   ​required_len,​ &olen, fb->buf, fb->​len);​
 +    ​
 +    // Create JSON payload and upload to Firebase
 +    FirebaseJson imageData;
 +    imageData.set("​timestamp",​ millis());
 +    imageData.set("​source",​ source);
 +    imageData.set("​size",​ (int)fb->​len);​
 +    imageData.set("​base64",​ String(base64_buffer));​
 +    ​
 +    String path = String("/​images/"​) + String(millis());​
 +    ​
 +    if (Firebase.RTDB.setJSON(&​fbdo,​ path.c_str(),​ &​imageData)) {
 +        // Send SMS notification via Twilio
 +        String smsMessage = "📸 Intruder detected! Check: https://​proiect-iot-feli.web.app/";​
 +        sendTwilioSMS(smsMessage.c_str());​
 +        return true;
 +    }
 +    ​
 +    free(base64_buffer);​
 +    return false;
 +}
 +</​code>​
  
 +<​code>​
 +#define HALL_SENSOR_PIN 12
 +const unsigned long DEBOUNCE_DELAY = 500; // 500ms debounce
  
 +void checkHallSensor() {
 +    static int lastState = HIGH;
 +    static unsigned long lastTriggerTime = 0;
 +    static bool initialized = false;
 +    ​
 +    // Initialize sensor state on first run
 +    if (!initialized) {
 +        lastState = digitalRead(HALL_SENSOR_PIN);​
 +        initialized = true;
 +        return;
 +    }
 +    ​
 +    int currentState = digitalRead(HALL_SENSOR_PIN);​
 +    unsigned long currentTime = millis();
 +    ​
 +    // Check for state change with debouncing
 +    if (currentState != lastState && ​
 +        (currentTime - lastTriggerTime) > DEBOUNCE_DELAY) {
 +        ​
 +        if (currentState == LOW) {
 +            Serial.println("​🧲 Magnet detected - capturing photo"​);​
 +        } else {
 +            Serial.println("​🧲 Magnet removed - capturing photo"​);​
 +        }
 +        ​
 +        capturePhotoFromSensor();​
 +        lastTriggerTime = currentTime;​
 +        lastState = currentState;​
 +    }
 +}
 +</​code>​
  
 +<​code>​
 +const firebaseConfig = {
 +  apiKey: "​AIzaSyB_GqKEayiItvWUcP9b0PLF8xKqtqJBjXM",​
 +  authDomain: "​proiect-iot-feli.firebaseapp.com",​
 +  databaseURL:​ "​https://​proiect-iot-feli-default-rtdb.europe-west1.firebasedatabase.app",​
 +  projectId: "​proiect-iot-feli"​
 +};
  
 +function initializeFirebase() {
 +  firebase.initializeApp(firebaseConfig);​
 +  database = firebase.database();​
 +  imagesRef = database.ref('​images'​);​
 +  ​
 +  // Set up real-time listener for new images
 +  setupRealtimeListener();​
 +  loadImages();​
 +}
  
 +function setupRealtimeListener() {
 +  imagesRef.on('​child_added',​ function(snapshot) {
 +    const imageData = snapshot.val();​
 +    displayImage(snapshot.key,​ imageData);
 +    updateStatus(`📸 New image detected at ${new Date().toLocaleTimeString()}`,​ '​new-image'​);​
 +  });
 +}
 +</​code>​
  
 +<​code>​
 +bool sendTwilioSMS(const char* message) {
 +    if (!twilio) {
 +        Serial.println("​❌ Twilio client not initialized"​);​
 +        return false;
 +    }
 +    ​
 +    Serial.println("​📱 Sending SMS notification..."​);​
 +    String response;
 +    bool result = twilio->​send_message(TO_PHONE_NUMBER,​ TWILIO_PHONE_NUMBER,​ message, response);
 +    ​
 +    if (result) {
 +        Serial.println("​✅ SMS sent successfully"​);​
 +        Serial.println("​SMS Response:"​);​
 +        Serial.println(response);​
 +    } else {
 +        Serial.println("​❌ SMS failed to send"​);​
 +        Serial.printf("​Error:​ %s\n", response.c_str());​
 +    }
 +    ​
 +    return result;
 +}
 +</​code>​
  
 +==== Firebase ====
  
-=== Code Snippets ===+{{ :​iothings:​proiecte:​2025sric:​firebase_feli.jpeg?​600 }} 
 + 
 +The entire application is deployed on **Firebase Hosting** and uses **Firebase Realtime Database** to coordinate data between the ESP32-CAM and the web dashboard. The database contains: 
 + 
 +  * **images/​** ​  
 +    - A collection of timestamped entries, each holding the Base64-encoded JPEG and metadata (size, source). ​  
 +  * **latestImage** ​  
 +    - Stores the key of the most recent images/​{timestamp} entry for quick access (optional). ​  
 +  * **notificationsEnabled** ​  
 +    - A Boolean flag to enable or disable SMS alerts on the fly. 
 + 
 +All communication flows through the Realtime Database: 
 + 
 +  * **ESP32-CAM** writes a new child under /images on every door-open event. 
 +  * **Web dashboard** listens for child_added and updates the UI in real time. 
 +  * **Toggles** to /​notificationsEnabled can be flipped by the user to mute alerts without redeploy. 
 + 
 +{{ :​iothings:​proiecte:​2025sric:​firebase2_feli.jpg?​600 }}
  
  
 ====== Challenges ====== ====== Challenges ======
 +
 +One of the first hurdles I encountered was the ESP32-CAM’s limited onboard RAM. Capturing high-resolution JPEGs and then encoding them into Base64 demanded more memory than the 520 KB of SRAM could comfortably provide. To overcome this, I enabled the module’s external PSRAM and carefully managed my buffer allocations so that large image data would reside in PSRAM rather than exhausting the internal memory.
 +
 +Another issue came up when trying to upload these large images all at once: memory would sometimes fragment, or the HTTP requests would time out, leading to failed uploads. I solved this by breaking the Base64 encoding into smaller, manageable chunks, freeing each buffer immediately after use, and adding a simple retry mechanism for any failed network calls. This approach dramatically reduced memory spikes and improved upload reliability.
 +
 +Finally, my Hall-effect sensor occasionally produced multiple false “door open” triggers due to electrical noise or rapid swings near the magnet. Instead of acting on every glitch, I implemented a 500 ms software debounce in my sensor-reading routine. That way, once the sensor changes state, I wait half a second to ensure it’s stable before capturing a photo—guaranteeing exactly one image per genuine door-open event.  ​
  
 ====== References ====== ====== References ======
 +
 +https://​docs.espressif.com/​projects/​esp-idf/​en/​latest/​esp32/​hw-reference/​esp32/​get-started-wrover-kit.html
 +
 +https://​github.com/​mobizt/​Firebase-ESP-Client
 +
 +https://​github.com/​ademuri/​twilio-esp32-client
 +
 +https://​firebase.google.com/​docs/​database
 +
 +https://​docs.platformio.org/​en/​latest/​
 +
 +https://​github.com/​espressif/​esp32-camera
 +
 +https://​www.twilio.com/​docs/​sms/​api
 +
 +https://​firebase.google.com/​docs/​web/​setup
 +
 +https://​docs.espressif.com/​projects/​esp-idf/​en/​latest/​esp32/​api-guides/​external-ram.html
 +
 +https://​randomnerdtutorials.com/​esp32-cam-pinout-gpios/​
  
  
iothings/proiecte/2025sric/security-system-to_detect-movement-and-capture-image.1748501013.txt.gz · Last modified: 2025/05/29 09:43 by felicia.saghin
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0