Camera de supraveghere folosind ESP32 CAM cu PIR
În cadrul acestui proiecțel am creat o cameră de supraveghere care se activează în momentul în care senzorul PIR detectează mișcare. Camera o să facă o fotografie care o sa fie salvată pe cardul SD, iar apoi o sa trimită acea fotografie prin email la o adresă prestabilită. Placa ESP32 CAM a fost programată să rămână în starea de "deep sleep" până primește un impuls de la senzorul PIR, și după ce face poza și o trimite pe email o să se întoarcă automat în "deep sleep".
Din păcate proiectul are câteva limitări cum ar fi cazul în care target-ul din campul vizual al camerei se mișcă mult prea repede și camera nu apucă să-l prindă (obiect în mișcare/vehicul/alergători/animal). Momentan nu am o solutie simplă pentru problema aceasta , și cred ca s-ar rezolva daca as tine camera in "normal mode" și aș folosi o cameră profesională , dar probabil o sa coste mult prea mult.
În cazul în care camera nu are access la internet o să salveze fotografiile și pe un card SD, dar avem iar o limitare legată de spațiul de stocare. Practic o să se umple cardul și o sa apară o eroare în momentul în care încearcă să salveze fotografia.
Componente:
- Modul ESP32-CAM, OV2640 camera inclusa
- Cameră de supraveghere falsă
- Acumulator extern , Esperanza , EMP103WG , Joule , 2200mAh
- Senzor de prezenta HC-SR501
Schema electronica/sistem:
Cod de test cu PIR:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*
Florin Simedru
Complete project details at https://automatic-house.blogspot.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
/********************************************************************************************************************
* Preferences--> Aditional boards Manager URLs : https://dl.espressif.com/dl/package_esp32_index.json, http://arduino.esp8266.com/stable/package_esp8266com_index.json
* Board Settings:
* Board: "ESP32 Wrover Module"
* Upload Speed: "921600"
* Flash Frequency: "80MHz"
* Flash Mode: "QIO"
* Partition Scheme: "Hue APP (3MB No OTA/1MB SPIFFS)"
* Core Debug Level: "None"
* COM Port: Depends *On Your System*
*
* GPIO 0 must be connected to GND pin while uploading the sketch
* After connecting GPIO 0 to GND pin, press the ESP32 CAM on-board RESET button to put the board in flashing mode
*********************************************************************************************************************/
#include "esp_camera.h"
#include "Arduino.h"
#include "FS.h" // SD Card ESP32
#include "SD_MMC.h" // SD Card ESP32
#include "soc/soc.h" // Disable brownour problems
#include "soc/rtc_cntl_reg.h" // Disable brownour problems
#include "driver/rtc_io.h"
#include <WiFi.h>
#include <EEPROM.h>
#include <EMailSender.h>
#include <SPIFFS.h>
#include "ESP32_MailClient.h"
// read and write from flash memory
// define the number of bytes you want to access
#define EEPROM_SIZE 4
// Pin definition for 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
// Photo File Name to save in SPIFFS
#define FILE_PHOTO "photo.jpg"
#define FILE_PHOTO_SLASH "/photo.jpg"
// To send Email using Gmail use port 465 (SSL) and SMTP Server smtp.gmail.com
// YOU MUST ENABLE less secure app option https://myaccount.google.com/lesssecureapps?pli=1
#define emailSenderAccount "emailSenderAccount@gmail.com"
#define emailSenderPassword ""
#define smtpServer "smtp.gmail.com"
#define smtpServerPort 465
#define emailSubject "ESP32-CAM Photo Captured"
#define emailRecipient "emailRecipient@gmail.com"
const char* ssid = "WifiSSID";
const char* password = "password";
RTC_DATA_ATTR int bootCount = 0;
// The Email Sending data object contains config and data to send
//SMTPSession smtpData;
//EMailSender(const char* email_login, const char* email_password, const char* email_from, const char* name_from, const char* smtp_server, uint16_t smtp_port );
EMailSender emailSend(emailSenderAccount, emailSenderPassword,emailRecipient,emailSubject,smtpServer,smtpServerPort);
int pictureNumber = 0;
bool ok = 0;
// The Email Sending data object contains config and data to send
SMTPData smtpData;
// 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( camera_fb_t *fbp )
{
camera_fb_t * fb = fbp; // pointer
bool ok = 0; // Boolean indicating if the picture has been taken correctly
if (!SPIFFS.begin(true))
{
Serial.println("An Error has occurred while mounting SPIFFS");
bool formatted = SPIFFS.format();
if ( formatted )
{
Serial.println("SPIFFS formatted successfully");
}
else
{
Serial.println("Error formatting");
}
ESP.restart();
}
else
{
delay(500);
bool formatted = SPIFFS.format();
if ( formatted )
{
Serial.println("SPIFFS formatted successfully");
}
else
{
Serial.println("Error formatting");
}
Serial.println("SPIFFS mounted successfully");
Serial.println("Taking a photo...");
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();
// check if file has been correctly saved in SPIFFS
ok = checkPhoto(SPIFFS);
}
}
void sendEmailPhoto_via_Gmail( String pic_path, int storage_type)
{
String path_slash;
EMailSender::EMailMessage message;
message.subject = "ESP32 CAM email";
message.message = "Salut, ESP32 CAM a detectat miscare ! /"+ pic_path;
EMailSender::FileDescriptior fileDescriptor[1];
fileDescriptor[0].filename = F(pic_path.c_str());
path_slash = "/"+pic_path;
fileDescriptor[0].url = F(path_slash.c_str());
fileDescriptor[0].mime = "image/jpg";
fileDescriptor[0].encode64 = true;
fileDescriptor[0].storageType = EMailSender::EMAIL_STORAGE_TYPE_SPIFFS;
EMailSender::Attachments attachs = {1, fileDescriptor};
EMailSender::Response resp = emailSend.send(emailRecipient, message, attachs); //, attachs
Serial.println("Sending status: ");
Serial.println(resp.status);
Serial.println(resp.code);
Serial.println(resp.desc);
}
int sendPhoto( void ) {
int ret_value = -1;
// Preparing email
Serial.println("Sending email...");
// Set the SMTP Server Email host, port, account and password
smtpData.setLogin(smtpServer, smtpServerPort, emailSenderAccount, emailSenderPassword);
// Set the sender name and Email
smtpData.setSender("ESP32-CAM", emailSenderAccount);
// Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest)
smtpData.setPriority("High");
// Set the subject
smtpData.setSubject(emailSubject);
// Set the email message in HTML format
smtpData.setMessage("<h2>Photo captured with ESP32-CAM and attached in this email.</h2>", true);
// Set the email message in text format
//smtpData.setMessage("Photo captured with ESP32-CAM and attached in this email.", false);
// Add recipients, can add more than one recipient
smtpData.addRecipient(emailRecipient);
// Add attach files from SPIFFS
smtpData.addAttachFile(FILE_PHOTO_SLASH, "image/jpg");
// Set the storage type to attach files in your email (SPIFFS)
smtpData.setFileStorageType(MailClientStorageType::SPIFFS);
smtpData.setSendCallback(sendCallback);
delay(500);
// Start sending Email, can be set callback function to track the status
if (!MailClient.sendMail(smtpData))
{
Serial.println("Error sending Email, " + MailClient.smtpErrorReason());
ret_value = 1;
}
else
{
ret_value = 2;
Serial.println("Email sent! " );
}
// Clear all data from Email object to free memory
smtpData.empty();
return ret_value;
}
// Callback function to get the Email sending status
void sendCallback(SendStatus msg)
{
//Print the current status
Serial.println(msg.info());
}
void camera_sensor_setup()
{
sensor_t * s = esp_camera_sensor_get();
s->set_contrast(s, 2); //min=-2, max=2
s->set_brightness(s, 2); //min=-2, max=2
s->set_saturation(s, 2); //min=-2, max=2
s->set_brightness(s, 0); // -2 to 2
s->set_contrast(s, 0); // -2 to 2
s->set_saturation(s, 0); // -2 to 2
s->set_special_effect(s, 2); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)
s->set_whitebal(s, 1); // 0 = disable , 1 = enable
s->set_awb_gain(s, 1); // 0 = disable , 1 = enable
s->set_wb_mode(s, 0); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
s->set_exposure_ctrl(s, 1); // 0 = disable , 1 = enable
s->set_aec2(s, 0); // 0 = disable , 1 = enable
s->set_ae_level(s, 0); // -2 to 2
s->set_aec_value(s, 300); // 0 to 1200
s->set_gain_ctrl(s, 1); // 0 = disable , 1 = enable
s->set_agc_gain(s, 0); // 0 to 30
s->set_gainceiling(s, (gainceiling_t)0); // 0 to 6
s->set_bpc(s, 0); // 0 = disable , 1 = enable
s->set_wpc(s, 1); // 0 = disable , 1 = enable
s->set_raw_gma(s, 1); // 0 = disable , 1 = enable
s->set_lenc(s, 1); // 0 = disable , 1 = enable
s->set_hmirror(s, 0); // 0 = disable , 1 = enable
s->set_vflip(s, 1); // 0 = disable , 1 = enable
s->set_dcw(s, 1); // 0 = disable , 1 = enable
s->set_colorbar(s, 0); // 0 = disable , 1 = enable
}
void setup() {
File file_spiffs;
camera_fb_t * fb = NULL;
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
Serial.begin(115200);
Serial.setDebugOutput(true);
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;
pinMode(4, INPUT);
digitalWrite(4, LOW);
rtc_gpio_hold_dis(GPIO_NUM_4);
rtc_gpio_hold_dis(GPIO_NUM_13);
if(psramFound()){
config.frame_size = FRAMESIZE_SVGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// Init Camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
//set the camera parameters
sensor_t * s = esp_camera_sensor_get();
s->set_contrast(s, 2); //min=-2, max=2
s->set_brightness(s, 2); //min=-2, max=2
s->set_saturation(s, 1); //min=-2, max=2
s->set_vflip(s, 1); // 0 = disable , 1 = enable
s->set_hmirror(s, 1); // 0 = disable , 1 = enable
delay(100); //wait a little for settings to take effect
// Take a picture with Camera
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
Serial.println("Exiting now");
while(1); //wait here as something is not right
}
Serial.println("Starting SD Card");
delay(500);
// Configure SD_MMC card
if(!SD_MMC.begin()){
Serial.println("SD Card Mount Failed");
}
uint8_t cardType = SD_MMC.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD Card attached");
}
// Initialize EEPROM with predefined size
EEPROM.begin(EEPROM_SIZE);
pictureNumber = EEPROM.read(0) + 1;
// Path where new picture will be saved in SD Card
String path = "/picture" + String(pictureNumber) +".jpg";
String path_email = "picture" + String(pictureNumber) +".jpg";
fs::FS &fs = SD_MMC;
Serial.printf("Picture file name: %s\n", path.c_str());
//create new file
File file = fs.open(path.c_str(), FILE_WRITE);
if(!file){
Serial.println("Failed to open file in writing mode");
Serial.println("Exiting now");
}
else {
file.write(fb->buf, fb->len); // payload (image), payload length
Serial.printf("Saved file to path: %s\n", path.c_str());
EEPROM.write(0, pictureNumber);
EEPROM.commit();
}
file.close();
delay(500);
// Turns off the ESP32-CAM white on-board LED (flash) connected to GPIO 4
pinMode(4, OUTPUT); //GPIO for LED flash
digitalWrite(4, LOW); //turn OFF flash LED
rtc_gpio_hold_en(GPIO_NUM_4); //make sure flash is held LOW in sleep
// Connect to Wi-Fi
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println();
if(WiFi.status() == WL_CONNECTED)
{
if (!SPIFFS.begin(true))
{
Serial.println("An Error has occurred while mounting SPIFFS");
bool formatted = SPIFFS.format();
if ( formatted )
{
Serial.println("SPIFFS formatted successfully");
}
else
{
Serial.println("Error formatting");
}
ESP.restart();
}
else
{
delay(500);
bool formatted = SPIFFS.format();
if ( formatted )
{
Serial.println("SPIFFS formatted successfully");
}
else
{
Serial.println("Error formatting");
}
Serial.println("SPIFFS mounted successfully");
//save the photo to SPIFFS
Serial.println("Save the photo to SPIFFS...");
if (!fb) {
Serial.println("Camera capture failed");
return;
}
// Photo file name
Serial.printf("Picture file name: %s\n", FILE_PHOTO_SLASH);
file_spiffs = SPIFFS.open(FILE_PHOTO_SLASH, FILE_WRITE);
// Insert the data in the photo file
if (!file_spiffs)
{
Serial.println("Failed to open file in writing mode");
}
else
{
file_spiffs.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_spiffs.size());
Serial.println(" bytes");
}
}
if( file_spiffs.size() >100)
{
(void)sendPhoto();
}
}
// Close the file
file_spiffs.close();
esp_camera_fb_return(fb);
esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 0);
Serial.println("Going to sleep now");
delay(3000);
esp_deep_sleep_start();
Serial.println("Now in Deep Sleep Mode");
}
void loop() {
// Nothing to do in the loop
}
/* | |
Florin Simedru | |
Complete project details at https://automatic-house.blogspot.com | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files. | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
*/ | |
/******************************************************************************************************************** | |
* Preferences--> Aditional boards Manager URLs : https://dl.espressif.com/dl/package_esp32_index.json, http://arduino.esp8266.com/stable/package_esp8266com_index.json | |
* Board Settings: | |
* Board: "ESP32 Wrover Module" | |
* Upload Speed: "921600" | |
* Flash Frequency: "80MHz" | |
* Flash Mode: "QIO" | |
* Partition Scheme: "Hue APP (3MB No OTA/1MB SPIFFS)" | |
* Core Debug Level: "None" | |
* COM Port: Depends *On Your System* | |
* | |
* GPIO 0 must be connected to GND pin while uploading the sketch | |
* After connecting GPIO 0 to GND pin, press the ESP32 CAM on-board RESET button to put the board in flashing mode | |
*********************************************************************************************************************/ | |
#include "esp_camera.h" | |
#include "Arduino.h" | |
#include "FS.h" // SD Card ESP32 | |
#include "SD_MMC.h" // SD Card ESP32 | |
#include "soc/soc.h" // Disable brownour problems | |
#include "soc/rtc_cntl_reg.h" // Disable brownour problems | |
#include "driver/rtc_io.h" | |
#include <WiFi.h> | |
#include <EEPROM.h> | |
#include <EMailSender.h> | |
#include <SPIFFS.h> | |
#include "ESP32_MailClient.h" | |
// read and write from flash memory | |
// define the number of bytes you want to access | |
#define EEPROM_SIZE 4 | |
// Pin definition for 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 | |
// Photo File Name to save in SPIFFS | |
#define FILE_PHOTO "photo.jpg" | |
#define FILE_PHOTO_SLASH "/photo.jpg" | |
// To send Email using Gmail use port 465 (SSL) and SMTP Server smtp.gmail.com | |
// YOU MUST ENABLE less secure app option https://myaccount.google.com/lesssecureapps?pli=1 | |
#define emailSenderAccount "emailSenderAccount@gmail.com" | |
#define emailSenderPassword "" | |
#define smtpServer "smtp.gmail.com" | |
#define smtpServerPort 465 | |
#define emailSubject "ESP32-CAM Photo Captured" | |
#define emailRecipient "emailRecipient@gmail.com" | |
const char* ssid = "WifiSSID"; | |
const char* password = "password"; | |
RTC_DATA_ATTR int bootCount = 0; | |
// The Email Sending data object contains config and data to send | |
//SMTPSession smtpData; | |
//EMailSender(const char* email_login, const char* email_password, const char* email_from, const char* name_from, const char* smtp_server, uint16_t smtp_port ); | |
EMailSender emailSend(emailSenderAccount, emailSenderPassword,emailRecipient,emailSubject,smtpServer,smtpServerPort); | |
int pictureNumber = 0; | |
bool ok = 0; | |
// The Email Sending data object contains config and data to send | |
SMTPData smtpData; | |
// 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( camera_fb_t *fbp ) | |
{ | |
camera_fb_t * fb = fbp; // pointer | |
bool ok = 0; // Boolean indicating if the picture has been taken correctly | |
if (!SPIFFS.begin(true)) | |
{ | |
Serial.println("An Error has occurred while mounting SPIFFS"); | |
bool formatted = SPIFFS.format(); | |
if ( formatted ) | |
{ | |
Serial.println("SPIFFS formatted successfully"); | |
} | |
else | |
{ | |
Serial.println("Error formatting"); | |
} | |
ESP.restart(); | |
} | |
else | |
{ | |
delay(500); | |
bool formatted = SPIFFS.format(); | |
if ( formatted ) | |
{ | |
Serial.println("SPIFFS formatted successfully"); | |
} | |
else | |
{ | |
Serial.println("Error formatting"); | |
} | |
Serial.println("SPIFFS mounted successfully"); | |
Serial.println("Taking a photo..."); | |
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(); | |
// check if file has been correctly saved in SPIFFS | |
ok = checkPhoto(SPIFFS); | |
} | |
} | |
void sendEmailPhoto_via_Gmail( String pic_path, int storage_type) | |
{ | |
String path_slash; | |
EMailSender::EMailMessage message; | |
message.subject = "ESP32 CAM email"; | |
message.message = "Salut, ESP32 CAM a detectat miscare ! /"+ pic_path; | |
EMailSender::FileDescriptior fileDescriptor[1]; | |
fileDescriptor[0].filename = F(pic_path.c_str()); | |
path_slash = "/"+pic_path; | |
fileDescriptor[0].url = F(path_slash.c_str()); | |
fileDescriptor[0].mime = "image/jpg"; | |
fileDescriptor[0].encode64 = true; | |
fileDescriptor[0].storageType = EMailSender::EMAIL_STORAGE_TYPE_SPIFFS; | |
EMailSender::Attachments attachs = {1, fileDescriptor}; | |
EMailSender::Response resp = emailSend.send(emailRecipient, message, attachs); //, attachs | |
Serial.println("Sending status: "); | |
Serial.println(resp.status); | |
Serial.println(resp.code); | |
Serial.println(resp.desc); | |
} | |
int sendPhoto( void ) { | |
int ret_value = -1; | |
// Preparing email | |
Serial.println("Sending email..."); | |
// Set the SMTP Server Email host, port, account and password | |
smtpData.setLogin(smtpServer, smtpServerPort, emailSenderAccount, emailSenderPassword); | |
// Set the sender name and Email | |
smtpData.setSender("ESP32-CAM", emailSenderAccount); | |
// Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest) | |
smtpData.setPriority("High"); | |
// Set the subject | |
smtpData.setSubject(emailSubject); | |
// Set the email message in HTML format | |
smtpData.setMessage("<h2>Photo captured with ESP32-CAM and attached in this email.</h2>", true); | |
// Set the email message in text format | |
//smtpData.setMessage("Photo captured with ESP32-CAM and attached in this email.", false); | |
// Add recipients, can add more than one recipient | |
smtpData.addRecipient(emailRecipient); | |
// Add attach files from SPIFFS | |
smtpData.addAttachFile(FILE_PHOTO_SLASH, "image/jpg"); | |
// Set the storage type to attach files in your email (SPIFFS) | |
smtpData.setFileStorageType(MailClientStorageType::SPIFFS); | |
smtpData.setSendCallback(sendCallback); | |
delay(500); | |
// Start sending Email, can be set callback function to track the status | |
if (!MailClient.sendMail(smtpData)) | |
{ | |
Serial.println("Error sending Email, " + MailClient.smtpErrorReason()); | |
ret_value = 1; | |
} | |
else | |
{ | |
ret_value = 2; | |
Serial.println("Email sent! " ); | |
} | |
// Clear all data from Email object to free memory | |
smtpData.empty(); | |
return ret_value; | |
} | |
// Callback function to get the Email sending status | |
void sendCallback(SendStatus msg) | |
{ | |
//Print the current status | |
Serial.println(msg.info()); | |
} | |
void camera_sensor_setup() | |
{ | |
sensor_t * s = esp_camera_sensor_get(); | |
s->set_contrast(s, 2); //min=-2, max=2 | |
s->set_brightness(s, 2); //min=-2, max=2 | |
s->set_saturation(s, 2); //min=-2, max=2 | |
s->set_brightness(s, 0); // -2 to 2 | |
s->set_contrast(s, 0); // -2 to 2 | |
s->set_saturation(s, 0); // -2 to 2 | |
s->set_special_effect(s, 2); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) | |
s->set_whitebal(s, 1); // 0 = disable , 1 = enable | |
s->set_awb_gain(s, 1); // 0 = disable , 1 = enable | |
s->set_wb_mode(s, 0); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) | |
s->set_exposure_ctrl(s, 1); // 0 = disable , 1 = enable | |
s->set_aec2(s, 0); // 0 = disable , 1 = enable | |
s->set_ae_level(s, 0); // -2 to 2 | |
s->set_aec_value(s, 300); // 0 to 1200 | |
s->set_gain_ctrl(s, 1); // 0 = disable , 1 = enable | |
s->set_agc_gain(s, 0); // 0 to 30 | |
s->set_gainceiling(s, (gainceiling_t)0); // 0 to 6 | |
s->set_bpc(s, 0); // 0 = disable , 1 = enable | |
s->set_wpc(s, 1); // 0 = disable , 1 = enable | |
s->set_raw_gma(s, 1); // 0 = disable , 1 = enable | |
s->set_lenc(s, 1); // 0 = disable , 1 = enable | |
s->set_hmirror(s, 0); // 0 = disable , 1 = enable | |
s->set_vflip(s, 1); // 0 = disable , 1 = enable | |
s->set_dcw(s, 1); // 0 = disable , 1 = enable | |
s->set_colorbar(s, 0); // 0 = disable , 1 = enable | |
} | |
void setup() { | |
File file_spiffs; | |
camera_fb_t * fb = NULL; | |
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector | |
Serial.begin(115200); | |
Serial.setDebugOutput(true); | |
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; | |
pinMode(4, INPUT); | |
digitalWrite(4, LOW); | |
rtc_gpio_hold_dis(GPIO_NUM_4); | |
rtc_gpio_hold_dis(GPIO_NUM_13); | |
if(psramFound()){ | |
config.frame_size = FRAMESIZE_SVGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA | |
config.jpeg_quality = 10; | |
config.fb_count = 2; | |
} else { | |
config.frame_size = FRAMESIZE_SVGA; | |
config.jpeg_quality = 12; | |
config.fb_count = 1; | |
} | |
// Init Camera | |
esp_err_t err = esp_camera_init(&config); | |
if (err != ESP_OK) { | |
Serial.printf("Camera init failed with error 0x%x", err); | |
return; | |
} | |
//set the camera parameters | |
sensor_t * s = esp_camera_sensor_get(); | |
s->set_contrast(s, 2); //min=-2, max=2 | |
s->set_brightness(s, 2); //min=-2, max=2 | |
s->set_saturation(s, 1); //min=-2, max=2 | |
s->set_vflip(s, 1); // 0 = disable , 1 = enable | |
s->set_hmirror(s, 1); // 0 = disable , 1 = enable | |
delay(100); //wait a little for settings to take effect | |
// Take a picture with Camera | |
fb = esp_camera_fb_get(); | |
if(!fb) { | |
Serial.println("Camera capture failed"); | |
Serial.println("Exiting now"); | |
while(1); //wait here as something is not right | |
} | |
Serial.println("Starting SD Card"); | |
delay(500); | |
// Configure SD_MMC card | |
if(!SD_MMC.begin()){ | |
Serial.println("SD Card Mount Failed"); | |
} | |
uint8_t cardType = SD_MMC.cardType(); | |
if(cardType == CARD_NONE){ | |
Serial.println("No SD Card attached"); | |
} | |
// Initialize EEPROM with predefined size | |
EEPROM.begin(EEPROM_SIZE); | |
pictureNumber = EEPROM.read(0) + 1; | |
// Path where new picture will be saved in SD Card | |
String path = "/picture" + String(pictureNumber) +".jpg"; | |
String path_email = "picture" + String(pictureNumber) +".jpg"; | |
fs::FS &fs = SD_MMC; | |
Serial.printf("Picture file name: %s\n", path.c_str()); | |
//create new file | |
File file = fs.open(path.c_str(), FILE_WRITE); | |
if(!file){ | |
Serial.println("Failed to open file in writing mode"); | |
Serial.println("Exiting now"); | |
} | |
else { | |
file.write(fb->buf, fb->len); // payload (image), payload length | |
Serial.printf("Saved file to path: %s\n", path.c_str()); | |
EEPROM.write(0, pictureNumber); | |
EEPROM.commit(); | |
} | |
file.close(); | |
delay(500); | |
// Turns off the ESP32-CAM white on-board LED (flash) connected to GPIO 4 | |
pinMode(4, OUTPUT); //GPIO for LED flash | |
digitalWrite(4, LOW); //turn OFF flash LED | |
rtc_gpio_hold_en(GPIO_NUM_4); //make sure flash is held LOW in sleep | |
// Connect to Wi-Fi | |
WiFi.begin(ssid, password); | |
Serial.print("Connecting to WiFi..."); | |
while (WiFi.status() != WL_CONNECTED) | |
{ | |
delay(500); | |
Serial.print("."); | |
} | |
Serial.println(); | |
if(WiFi.status() == WL_CONNECTED) | |
{ | |
if (!SPIFFS.begin(true)) | |
{ | |
Serial.println("An Error has occurred while mounting SPIFFS"); | |
bool formatted = SPIFFS.format(); | |
if ( formatted ) | |
{ | |
Serial.println("SPIFFS formatted successfully"); | |
} | |
else | |
{ | |
Serial.println("Error formatting"); | |
} | |
ESP.restart(); | |
} | |
else | |
{ | |
delay(500); | |
bool formatted = SPIFFS.format(); | |
if ( formatted ) | |
{ | |
Serial.println("SPIFFS formatted successfully"); | |
} | |
else | |
{ | |
Serial.println("Error formatting"); | |
} | |
Serial.println("SPIFFS mounted successfully"); | |
//save the photo to SPIFFS | |
Serial.println("Save the photo to SPIFFS..."); | |
if (!fb) { | |
Serial.println("Camera capture failed"); | |
return; | |
} | |
// Photo file name | |
Serial.printf("Picture file name: %s\n", FILE_PHOTO_SLASH); | |
file_spiffs = SPIFFS.open(FILE_PHOTO_SLASH, FILE_WRITE); | |
// Insert the data in the photo file | |
if (!file_spiffs) | |
{ | |
Serial.println("Failed to open file in writing mode"); | |
} | |
else | |
{ | |
file_spiffs.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_spiffs.size()); | |
Serial.println(" bytes"); | |
} | |
} | |
if( file_spiffs.size() >100) | |
{ | |
(void)sendPhoto(); | |
} | |
} | |
// Close the file | |
file_spiffs.close(); | |
esp_camera_fb_return(fb); | |
esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 0); | |
Serial.println("Going to sleep now"); | |
delay(3000); | |
esp_deep_sleep_start(); | |
Serial.println("Now in Deep Sleep Mode"); | |
} | |
void loop() { | |
// Nothing to do in the loop | |
} |
Documentatie proiect:
- https://randomnerdtutorials.com/esp32-cam-pir-motion-detector-photo-capture/
- https://easyelectronicsproject.com/esp32-projects/esp32-cam-pir-motion-detector-with-photo-capture-1/
To Do:
- O functie de configurare prin bluetooth pentru putea configura mai usor accesul la Wifi și email
- O functie de trezire folosind un senzor magnetic , eventual pentru trecerea în modul de configurare.
- O functie pentru a înregistra video în cazul în care sunt foarte multe mișcări în raza vizuală a camerei.
- O functie de atenționare pe email pentru cazul în care se umple spatiul de stocare pentru cardul de memorie SD.
Pentru întrebari și/sau consultanță tehnică vă stau la dispozitie pe blog sau pe email simedruflorin@automatic-house.ro. O seară/zi plăcută tuturor !