/********* Rui Santos Complete project details at https://RandomNerdTutorials.com/esp32-cam-take-photo-display-web-server/ 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. Modified by Jason Pettiaux *********/ #include "WiFi.h" #include "esp_camera.h" #include "esp_timer.h" #include "img_converters.h" #include "Arduino.h" #include "soc/soc.h" // Disable brownout problems #include "soc/rtc_cntl_reg.h" // Disable brownout problems #include "driver/rtc_io.h" #include #include #include #include // Replace with your network credentials const char* ssid = ""; const char* password = ""; // Create AsyncWebServer object on port 80 AsyncWebServer server(80); boolean takeNewPhoto = false; boolean moveMotor = false; // Photo File Name to save in SPIFFS #define FILE_PHOTO "/photo.jpg" #define LED 33 // 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 // Motor steps per rotation const int STEPS_PER_REV = 200; const char index_html[] PROGMEM = R"rawliteral(

ESP32-CAM Last Photo

It might take more than 5 seconds to capture a photo.

)rawliteral"; void setup() { // Setup the pins as Outputs pinMode(LED,OUTPUT); // 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"); } // Print ESP32 Local IP Address Serial.print("IP Address: http://"); 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("/moveMotor", HTTP_GET, [](AsyncWebServerRequest * request) { moveMotor = true; request->send_P(200, "text/plain", "Moving Motor"); }); server.on("/saved-photo", HTTP_GET, [](AsyncWebServerRequest * request) { request->send(SPIFFS, FILE_PHOTO, "image/jpg", false); }); // Start server server.begin(); } void loop() { if (takeNewPhoto) { capturePhotoSaveSpiffs(); takeNewPhoto = false; } if (moveMotor) { digitalWrite(33, LOW); delay(1000); digitalWrite(33, HIGH); moveMotor = false; } delay(1000); Serial.println("LED ON"); Serial.println(moveMotor); } // 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(); 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 ); }