ESP32 Cam to verify garage gates and light
Post ReplyESP32 Cam to verify garage gates and lightPosted: Wednesday, July 20, 2022 [02:00:21] - 1
IaoT remote garage door opener and remote light in a garage it helps to have a feedback on current state of the above. www.codemacs.com/iaot/app.. - garage door opener project ESP32 Cam looks very appealing and cheap as a solution when image quality is not a major factor. Enclosure STL file was taken and forked from Thingiverse. This is the code used for taking pictures: Rui Santos Complete project details at RandomNerdTutorials.com/e.. IMPORTANT!!! - Select Board "AI Thinker ESP32-CAM" - GPIO 0 must be connected to GND to upload a sketch - After connecting GPIO 0 to GND, press the ESP32-CAM on-board RESET button to put your board in flashing mode The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. *********/ #include "WiFi.h" #include "esp_camera.h" #include "esp_timer.h" #include "img_converters.h" #include "Arduino.h" #include "soc/soc.h" // Disable brownour problems #include "soc/rtc_cntl_reg.h" // Disable brownour problems #include "driver/rtc_io.h" #include <ESPAsyncWebServer.h> #include <StringArray.h> #include <SPIFFS.h> #include <FS.h> // Replace with your network credentials const char* ssid = "YOUR_SSID"; const char* password = "SSID_PASSWORD"; // Create AsyncWebServer object on port 80 AsyncWebServer server(80); boolean takeNewPhoto = false; // Photo File Name to save in SPIFFS #define FILE_PHOTO "/garage.jpg" // OV2640 camera module pins (CAMERA_MODEL_AI_THINKER) #define PWDN_GPIO_NUM 32 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 0 #define SIOD_GPIO_NUM 26 #define SIOC_GPIO_NUM 27 #define Y9_GPIO_NUM 35 #define Y8_GPIO_NUM 34 #define Y7_GPIO_NUM 39 #define Y6_GPIO_NUM 36 #define Y5_GPIO_NUM 21 #define Y4_GPIO_NUM 19 #define Y3_GPIO_NUM 18 #define Y2_GPIO_NUM 5 #define VSYNC_GPIO_NUM 25 #define HREF_GPIO_NUM 23 #define PCLK_GPIO_NUM 22 #define FLASH_GPIO_NUM 4 const char index_html[] PROGMEM = R"rawliteral( <!DOCTYPE HTML><html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> body { text-align:center; } .vert { margin-bottom: 10%; } .hori{ margin-bottom: 0%; } </style> </head> <body> <div id="container"> <h2>No Photo</h2> <!-- <p> <button onclick="rotatePhoto();">ROTATE</button> <button onclick="capturePhoto()">CAPTURE PHOTO</button> <button onclick="location.reload();">REFRESH PAGE</button> </p> --> </div> <div><img src="saved-photo" id="photo" width="70%"></div> </body> <script> var deg = 0; function capturePhoto() { var xhr = new XMLHttpRequest(); xhr.open('GET', "/capture", true); xhr.send(); } function rotatePhoto() { var img = document.getElementById("photo"); deg += 90; if(isOdd(deg/90)){ document.getElementById("container").className = "vert"; } else{ document.getElementById("container").className = "hori"; } img.style.transform = "rotate(" + deg + "deg)"; } function isOdd(n) { return Math.abs(n % 2) == 1; } </script> </html>)rawliteral"; void setup() { // Serial port for debugging purposes Serial.begin(115200); // Connect to Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } if (!SPIFFS.begin(true)) { Serial.println("An Error has occurred while mounting SPIFFS"); ESP.restart(); } else { delay(500); Serial.println("SPIFFS mounted successfully"); } pinMode(FLASH_GPIO_NUM, OUTPUT); // Print ESP32 Local IP Address Serial.print("IP Address: ";); Serial.println(WiFi.localIP()); // Turn-off the 'brownout detector' WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // OV2640 camera module camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM; config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM; config.pin_sscb_sda = SIOD_GPIO_NUM; config.pin_sscb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.pixel_format = PIXFORMAT_JPEG; if (psramFound()) { config.frame_size = FRAMESIZE_UXGA; config.jpeg_quality = 10; config.fb_count = 2; } else { config.frame_size = FRAMESIZE_SVGA; config.jpeg_quality = 12; config.fb_count = 1; } // Camera init esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed with error 0x%x", err); ESP.restart(); } // Route for root / web page server.on("/", HTTP_GET,[](AsyncWebServerRequest* request) { request->send_P(200, "text/html", index_html); }); server.on("/capture", HTTP_GET,[](AsyncWebServerRequest* request) { takeNewPhoto = true; request->send_P(200, "text/plain", "Taking Photo"); }); server.on("/saved-photo", HTTP_GET,[](AsyncWebServerRequest* request) { request->send(SPIFFS, FILE_PHOTO, "image/jpg", false); }); // Start server server.begin(); } void loop() { if (takeNewPhoto) { digitalWrite(FLASH_GPIO_NUM, HIGH); // This is added to keep flash "ON" delay(1500); // before taking actual photos capturePhotoSaveSpiffs(); takeNewPhoto = false; delay(10000); // and in case it loops with image errors digitalWrite(FLASH_GPIO_NUM, LOW); // turn-off the flash light } delay(1); } // Check if photo capture was successful bool checkPhoto( fs::FS &fs ) { File f_pic = fs.open( FILE_PHOTO ); unsigned int pic_sz = f_pic.size(); return ( pic_sz > 100 ); } // Capture Photo and Save it to SPIFFS void capturePhotoSaveSpiffs( void ) { camera_fb_t * fb = NULL; // pointer bool ok = 0; // Boolean indicating if the picture has been taken correctly do { // Take a photo with the camera Serial.println("Taking a photo..."); delay(1); fb = esp_camera_fb_get(); if (!fb) { Serial.println("Camera capture failed"); return; } // Photo file name Serial.printf("Picture file name: %s\n", FILE_PHOTO); File file = SPIFFS.open(FILE_PHOTO, FILE_WRITE); // Insert the data in the photo file if (!file) { Serial.println("Failed to open file in writing mode"); } else { file.write(fb->buf, fb->len); // payload (image), payload length Serial.print("The picture has been saved in "); Serial.print(FILE_PHOTO); Serial.print(" - Size: "); Serial.print(file.size()); Serial.println(" bytes"); } // Close the file file.close(); esp_camera_fb_return(fb); // check if file has been correctly saved in SPIFFS ok = checkPhoto(SPIFFS); } while ( !ok ); } it was updated with flash light extended "ON" to make sure reflective strips on the gates lit when pictures taken. |
ESP32 Cam to verify garage gates and light - ImagesPosted: Wednesday, July 20, 2022 [02:15:13] - 2
This is garage with lights on: and this is lights off: image first checked for a number of colors and if below 10,000 - lights are off. Checking the open/closed gates are easy enough. Convert image to monochrome with 2 colors only. Add mask to the image covering all image except for stripes and compare it to existing image with stripes. If they match - gates are close, otherwise - at least one of them fully or partially open. `convert /http/ipLogD/garage.current.jpg -colorspace gray -threshold 20% -type bilevel /http/ipLogD/garage.mono.jpg`; `composite -geometry +0+0 /http/images.camera/garage.mask.png /http/ipLogD/garage.mono.jpg /http/ipLogD/garage.combmask.png`; my $diff=`compare -metric AE -fuzz 5% /http/images.camera/garage.sample.png /http/ipLogD/garage.combmask.png /http/ipLogD/garage.diffs.jpg 2>&1`; print "\tImages Diff: $diff\n"; if($diff < 400) {return 'closed';} else {return 'open';} } "AI" not required to solve this puzzle :-) |
RE: ESP32 Cam to verify garage gates and light Q&APosted: Wednesday, July 20, 2022 [04:05:16] - 3
To answer a few questions already received Why the actual page has no control buttons: In our case only the daemon makes all requests if(-f '/http/ipLogD/garage.current.jpg') {`mv /http/ipLogD/garage.current.jpg /http/ipLogD/garage.current.$tsttime.jpg`;} print "Getting garage light status:\n"; while(1) {$good++; # Capture request my $curl = `curl --connect-timeout 10 http://garagecamera.local/capture`; sleep(15); if($curl =~ m/ed out/) {last;} # Actual image download $curl = `curl --connect-timeout 10 --verbose -o /http/ipLogD/garage.current.jpg http://garagecamera.local/saved-photo 2>&1`; $curl =~ s#(.*?)Content-Length: (\d+)(.*)#$s; print "Download: $curl\nSize: $size\n"; if($curl =~ m/remaining to read/i) {next;} unless(-f '/http/ipLogD/garage.current.jpg') {print "No image received\n"; my $fsize = (stat ("/http/ipLogD/garage.current.jpg"))[7]; if($fsize < $size) {print "Partial download, downloaded $fsize out of $size\n"; my $res = `identify -format "%k" /http/ipLogD/garage.current.jpg`; print "Number of colors: $res\n"; if($res < 1000000) {print "Data is good - exit loop\n"; if($res < 10000) {$status='off'; if($hrs > 21 || $hrs < 5) {my $open=''; unless(-f '/http/ipLogD/gates.checked.txt') { $open=readgates(); `touch /http/ipLogD/gates.checked.txt`; } if($open eq 'open') {`touch /http/ipLogD/garage.gates.open`;} } } if($good > 3) {last;} } ## WHILE END print "\tGarage light status: $status\n\n"; return $status; } Code above also answers question on how do we get image from camera. This program is part of home IAoT setup and runs from the daemon. It is written in Perl. |
RE: ESP32 Cam to verify garage gates and light - STL filesPosted: Wednesday, July 20, 2022 [10:56:49] - 4
Camera case STL files: www.codemacs.com/download.. - camera case www.codemacs.com/download.. - case lid |