General Information Applications Server Routing

ESP32 Cam to verify garage gates and light

Post Reply
iaot / applications     Views: 835Prev .. Next
ESP32 Cam to verify garage gates and lightPosted: Wednesday, July 20, 2022 [02:00:21] - 1
rootPosted by:rootMember Since:
June 16 2010
Posts: 357
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.

ESP32 Cam to verify garage gates and light

ESP32 Cam to verify garage gates and light

Enclosure STL file was taken and forked from Thingiverse.

This is the code used for taking pictures:
View Code/*********
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.There's no place like ~
ESP32 Cam to verify garage gates and light - ImagesPosted: Wednesday, July 20, 2022 [02:15:13] - 2
rootPosted by:rootMember Since:
June 16 2010
Posts: 357
This is garage with lights on:

ESP32 Cam to verify garage gates and light - Images

and this is lights off:

ESP32 Cam to verify garage gates and light - Images

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.
View Codesub readgates {
`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 :-)There's no place like ~
RE: ESP32 Cam to verify garage gates and light Q&APosted: Wednesday, July 20, 2022 [04:05:16] - 3
rootPosted by:rootMember Since:
June 16 2010
Posts: 357
To answer a few questions already received
Why the actual page has no control buttons:
In our case only the daemon makes all requests
View Codesub getstatus {
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";my $good=0;my $status='on';
while(1) {$good++;my $ttm=time;print "Time: $ttm\n";
# Capture request
my $curl = `curl --connect-timeout 10 http://garagecamera.local/capture`;
sleep(15);print "Capture: \"$curl\"\n";
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;my $size=$2;
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";next;}
my $fsize = (stat ("/http/ipLogD/garage.current.jpg"))[7];print "Downloaded file size: $fsize\n";
if($fsize < $size) {print "Partial download, downloaded $fsize out of $size\n";sleep(5);next;}
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";$good=5;}
if($res < 10000) {$status='off';
if($hrs > 21 || $hrs < 5) {my $open='';
unless(-f '/http/ipLogD/gates.checked.txt') {
$open=readgates();print "Gates are $open\n";
`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.There's no place like ~
RE: ESP32 Cam to verify garage gates and light - STL filesPosted: Wednesday, July 20, 2022 [10:56:49] - 4
rootPosted by:rootMember Since:
June 16 2010
Posts: 357
Camera case STL files:
www.codemacs.com/download.. - camera case
www.codemacs.com/download.. - case lidThere's no place like ~
iaot / applicationsPrev .. Next
 
Post Reply
Home - Iaot: General Information Applications Server Routing
Our Telegram Group