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
/********* | |
Rui Santos | |
Complete instructions at https://RandomNerdTutorials.com/esp32-cam-projects-ebook/ | |
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. | |
*********/ | |
#include "esp_camera.h" | |
#include "SPI.h" | |
#include "driver/rtc_io.h" | |
#include <ESP_Mail_Client.h> | |
#include <FS.h> | |
#include <SPIFFS.h> | |
#include <WiFi.h> | |
// REPLACE WITH YOUR NETWORK CREDENTIALS | |
const char* ssid = ""; | |
const char* password = ""; | |
// 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 "" | |
#define emailSenderPassword "" | |
#define smtpServer "smtp.gmail.com" | |
#define smtpServerPort 465 | |
#define emailSubject "ESP32-CAM Photo Captured" | |
#define emailRecipient "" | |
#define CAMERA_MODEL_AI_THINKER | |
#if defined(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 | |
#else | |
#error "Camera model not selected" | |
#endif | |
// The Email Sending data object contains config and data to send | |
SMTPSession smtp; | |
/* Callback function to get the Email sending status */ | |
void smtpCallback(SMTP_Status status); | |
// Photo File Name to save in SPIFFS | |
String filePhoto = "photo.jpg"; | |
String filePath = "/photo.jpg"; | |
void setup() { | |
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector | |
Serial.begin(115200); | |
Serial.println(); | |
// 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 (!SPIFFS.begin(true)) { | |
Serial.println("An Error has occurred while mounting SPIFFS"); | |
ESP.restart(); | |
} | |
else { | |
delay(500); | |
Serial.println("SPIFFS mounted successfully"); | |
} | |
// Print ESP32 Local IP Address | |
Serial.print("IP Address: http://"); | |
Serial.println(WiFi.localIP()); | |
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; | |
} | |
// Initialize camera | |
esp_err_t err = esp_camera_init(&config); | |
if (err != ESP_OK) { | |
Serial.printf("Camera init failed with error 0x%x", err); | |
return; | |
} | |
capturePhotoSaveSpiffs(); | |
sendPhoto(); | |
} | |
void loop() { | |
} | |
// Check if photo capture was successful | |
bool checkPhoto( fs::FS &fs ) { | |
File f_pic = fs.open( filePath ); | |
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..."); | |
fb = esp_camera_fb_get(); | |
if (!fb) { | |
Serial.println("Camera capture failed"); | |
return; | |
} | |
// Photo file name | |
Serial.printf("Picture file name: %s\n", filePhoto); | |
File file = SPIFFS.open(filePath, 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(filePath); | |
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 ); | |
} | |
void sendPhoto( void ) { | |
/** Enable the debug via Serial port | |
* none debug or 0 | |
* basic debug or 1 | |
*/ | |
smtp.debug(1); | |
/* Set the callback function to get the sending results */ | |
smtp.callback(smtpCallback); | |
/* Declare the session config data */ | |
ESP_Mail_Session session; | |
/* Set the session config */ | |
session.server.host_name = smtpServer; | |
session.server.port = smtpServerPort; | |
session.login.email = emailSenderAccount; | |
session.login.password = emailSenderPassword; | |
session.login.user_domain = "mydomain.net"; | |
/* Declare the message class */ | |
SMTP_Message message; | |
/* Enable the chunked data transfer with pipelining for large message if server supported */ | |
message.enable.chunking = true; | |
message.sender.name = "ESP Mail"; | |
message.sender.email = emailSenderAccount; | |
message.subject = "Test sending Email with attachments and inline images from SD card and Flash"; | |
message.addRecipient("Simon", emailRecipient); | |
String htmlMsg = "<h2>Photo captured with ESP32-CAM and attached in this email.</h2>"; | |
message.html.content = htmlMsg.c_str(); | |
message.html.charSet = "utf-8"; | |
message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; | |
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; | |
message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; | |
/* The attachment data item */ | |
SMTP_Attachment att; | |
att.descr.filename = "photo.jpg"; | |
att.descr.mime = "image/jpg"; //binary data | |
att.file.path = "/photo.jpg"; | |
att.file.storage_type = esp_mail_file_storage_type_flash; | |
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; | |
/* Add attachment to the message */ | |
message.addAttachment(att); | |
/* Connect to server with the session config */ | |
if (!smtp.connect(&session)) | |
return; | |
/* Start sending the Email and close the session */ | |
if (!MailClient.sendMail(&smtp, &message, true)) | |
Serial.println("Error sending Email, " + smtp.errorReason()); | |
} | |
/* Callback function to get the Email sending status */ | |
void smtpCallback(SMTP_Status status){ | |
/* Print the current status */ | |
Serial.println(status.info()); | |
/* Print the sending result */ | |
if (status.success()){ | |
Serial.println("----------------"); | |
ESP_MAIL_PRINTF("Message sent success: %d\n", status.completedCount()); | |
ESP_MAIL_PRINTF("Message sent failled: %d\n", status.failedCount()); | |
Serial.println("----------------\n"); | |
struct tm dt; | |
for (size_t i = 0; i < smtp.sendingResult.size(); i++){ | |
/* Get the result item */ | |
SMTP_Result result = smtp.sendingResult.getItem(i); | |
time_t ts = (time_t)result.timestamp; | |
localtime_r(&ts, &dt); | |
ESP_MAIL_PRINTF("Message No: %d\n", i + 1); | |
ESP_MAIL_PRINTF("Status: %s\n", result.completed ? "success" : "failed"); | |
ESP_MAIL_PRINTF("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); | |
ESP_MAIL_PRINTF("Recipient: %s\n", result.recipients); | |
ESP_MAIL_PRINTF("Subject: %s\n", result.subject); | |
} | |
Serial.println("----------------\n"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment