# 遙控拍攝及電郵傳送影像(使用Blynk) ###### tags: `iot project` `ESP32` `CAM` ## 目的﹕用Blynk app控制ESP32攝影機並即時電郵照片。 ## 流程﹕ ![](https://i.imgur.com/s2bdR8r.png) 1.按拍攝掣 ![](https://i.imgur.com/viWwX1m.jpg) 2.隨即收到電郵 ![](https://i.imgur.com/v7xYa9L.jpg) ![](https://i.imgur.com/DtY4Wzs.jpg) ## 材料﹕便用一體化的ESP32+攝影機模組 https://item.taobao.com/item.htm?spm=a1z09.2.0.0.23062e8dKwuvn0&id=636886868914&_u=gd5ed5tc877 ## Blynk 新增項目 ![](https://i.imgur.com/sLRr9St.jpg) 按Create產生Token(待會使用) ![](https://i.imgur.com/iCpaU0y.jpg) 新增Styled Button, 設定如下﹕ OUTPUT是V1 ![](https://i.imgur.com/qAxlsbx.jpg) 新增Email, 設定如下(不用填寫電郵(在程式設定))﹕ ![](https://i.imgur.com/AMKNa4r.jpg) ## Arduino 選擇ESP32 Wrover Module ![](https://i.imgur.com/dd3RKwL.png) 選擇Huge App (3MB No OTA/1MB SPIFFS) ![](https://i.imgur.com/VgsK59K.png) 程式﹕ ```c= /********* 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. *********/ #define BLYNK_PRINT Serial #include "esp_camera.h" #include "SPI.h" #include "driver/rtc_io.h" #include "ESP32_MailClient.h" #include <FS.h> #include <SPIFFS.h> #include <WiFi.h> #include <WiFiClient.h> #include <BlynkSimpleEsp32.h> #include "time.h" // REPLACE WITH YOUR NETWORK CREDENTIALS char auth[] = ""; // You can also specify server: //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 80); //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8080); //**Change ↓ char server[] = ""; char ssid[] = ""; char pass[] = ""; //**Change ↑ char showtime[50]; const char* ntpServer = "pool.ntp.org"; const long gmtOffset_sec = 28800; //HK time const int daylightOffset_sec = 3600; // 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 "" #define smtpServerPort 465 #define emailSubject "遠程拍攝傳送" #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 SMTPData smtpData; // Photo File Name to save in SPIFFS #define FILE_PHOTO "/photo.jpg" BLYNK_WRITE(V1) { Serial.println("event triggers"); Serial.println("should send email..."); //emailOnButtonPress(); capturePhotoSaveSpiffs(); sendPhoto(); } void printLocalTime(){ struct tm timeinfo; if(!getLocalTime(&timeinfo)){ Serial.println("Failed to obtain time"); return; } //Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); //"strftime"-Format time as string //http://www.cplusplus.com/reference/ctime/strftime/ strftime(showtime,50, "%A, %B %d %Y %H:%M:%S", &timeinfo); Serial.print("As taken photo time:"); Serial.println(showtime); /* Serial.print("Day of week: "); Serial.println(&timeinfo, "%A"); Serial.print("Month: "); Serial.println(&timeinfo, "%B"); Serial.print("Day of Month: "); Serial.println(&timeinfo, "%d"); Serial.print("Year: "); Serial.println(&timeinfo, "%Y"); Serial.print("Hour: "); Serial.println(&timeinfo, "%H"); Serial.print("Hour (12 hour format): "); Serial.println(&timeinfo, "%I"); Serial.print("Minute: "); Serial.println(&timeinfo, "%M"); Serial.print("Second: "); Serial.println(&timeinfo, "%S"); Serial.println("Time variables"); char timeHour[3]; strftime(timeHour,3, "%H", &timeinfo); Serial.println(timeHour); char timeWeekDay[10]; strftime(timeWeekDay,10, "%A", &timeinfo); Serial.println(timeWeekDay); */ Serial.println(); } void setup() { Serial.begin(115200); Blynk.begin(auth, ssid, pass, server, 8080); WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector Serial.println(); // Init and get the time configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); //printLocalTime(); // Connect to Wi-Fi //WiFi.begin(ssid, password); //Serial.print("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"); } // 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; } } void loop() { Blynk.run(); } // 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..."); fb = esp_camera_fb_get(); //Call printLocalTime as the photo taken time and record/update it printLocalTime(); 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 ); } void sendPhoto( void ) { // 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("遠程拍攝傳送", 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 //printLocalTime(); String emailMsg = "拍攝時間(香港標準時間):"; emailMsg += showtime; smtpData.setMessage(emailMsg, 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); //smtpData.addRecipient(emailRecipient2); // Add attach files from SPIFFS smtpData.addAttachFile(FILE_PHOTO, "image/jpg"); // Set the storage type to attach files in your email (SPIFFS) smtpData.setFileStorageType(MailClientStorageType::SPIFFS); smtpData.setSendCallback(sendCallback); // Start sending Email, can be set callback function to track the status if(!MailClient.sendMail(smtpData)){ Serial.println("Error sending Email, " + MailClient.smtpErrorReason()); Blynk.notify("傳送電郵出錯:" + MailClient.smtpErrorReason()); } else{ Blynk.notify("已電郵最新照片"); } // Clear all data from Email object to free memory smtpData.empty(); } // Callback function to get the Email sending status void sendCallback(SendStatus msg) { //Print the current status Serial.println(msg.info()); } ``` ### 程式資料設定 ![](https://i.imgur.com/CZzbhjR.png) ```c char auth[] = ""; //新增Blynk應用時的Token ``` ```c char server[] = ""; //預設 blynk-cloud.com char ssid[] = ""; //ESP32 要盈入的Wifi ssid char pass[] = ""; //Wifi 密碼 ``` ```c //僅以gmail為例 #define emailSenderAccount "" //sender@gmail.com #define emailSenderPassword "" //emailPassword #define smtpServer "" //"smtp.gmail.com" #define smtpServerPort 465 #define emailSubject "遠程拍攝傳送" #define emailRecipient "" //whoreceive@gmail.com ``` ### 上載程式注意﹕ 見 ``` Connecting........_____....._____....._____.... ``` 時要FLUSH(Press)->RST(Press)->FLUSH(Release)->RST(Release) (動畫) ![](https://i.imgur.com/i4iYHm0.gif) 才能上載程式 https://github.com/snakeleader/blynk_sent_email