{"id":90367,"date":"2019-11-08T12:53:59","date_gmt":"2019-11-08T12:53:59","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=90367"},"modified":"2025-03-15T11:33:23","modified_gmt":"2025-03-15T11:33:23","slug":"esp32-cam-take-photo-display-web-server","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-cam-take-photo-display-web-server\/","title":{"rendered":"ESP32-CAM Take Photo and Display in Web Server"},"content":{"rendered":"\n<p>Learn how to build a web server with the ESP32-CAM board that allows you to send a command to take a photo and visualize the latest captured photo in your browser saved in SPIFFS. We also added the option to rotate the image if necessary.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Take-Photo-Display-Web-Server.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM Take Photo and Display in Web Server\" class=\"wp-image-90449\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Take-Photo-Display-Web-Server.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Take-Photo-Display-Web-Server.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Take-Photo-Display-Web-Server.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Take-Photo-Display-Web-Server.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p>We have other ESP32-CAM projects in our blog that you might like. In fact you can take this project further, by <a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-pir-motion-detector-photo-capture\/\">adding a PIR sensor to take a photo when motion is detected<\/a>, a physical pushbutton to take a photo, or also include <a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-video-streaming-web-server-camera-home-assistant\/\">video streaming<\/a> capabilities in another URL path.<\/p>\n\n\n\n<p>Other ESP32-CAM projects and tutorials:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-pir-motion-detector-photo-capture\/\">ESP32-CAM PIR Motion Detector with Photo Capture (saves to microSD card)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-video-streaming-face-recognition-arduino-ide\/\">ESP32-CAM Video Streaming and Face Recognition with Arduino IDE<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-video-streaming-web-server-camera-home-assistant\/\">ESP32-CAM Video Streaming Web Server (Home Assistant, Node-RED, etc\u2026)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-take-photo-save-microsd-card\/\">ESP32-CAM Take Photo and Save to MicroSD Card<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-troubleshooting-guide\/\">ESP32-CAM Troubleshooting Guide<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Watch the Video Demonstration<\/h2>\n\n\n\n<p>Watch the following video demonstration to see what you&#8217;re going to build throughout this tutorial.<\/p>\n\n\n<p style=\"text-align:center\"><iframe width=\"720\" height=\"405\" src=\"https:\/\/www.youtube.com\/embed\/p_INtiE_-WQ?rel=0\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Parts Required<\/h2>\n\n\n\n<p>To follow this project, you need the following parts:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><a aria-label=\" (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/tools\/esp32-cam\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32-CAM with OV2640<\/a><\/strong> (<a aria-label=\"read board overview (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/esp32-cam-ov2640-camera\/\" target=\"_blank\" rel=\"noreferrer noopener\">read board overview<\/a>) &#8211; read <a aria-label=\"Best ESP32-CAM Dev Boards (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/esp32-camera-cam-boards-review-comparison\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP32-CAM Dev Boards<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noreferrer noopener\">Female-to-female jumper wires<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/ftdi-programmer-board\/\" target=\"_blank\" rel=\"noreferrer noopener\">FTDI programmer<\/a><\/li>\n\n\n\n<li>5V power supply or power bank<\/li>\n<\/ul>\n\n\n<p>You can use the preceding links or go directly to <a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\">MakerAdvisor.com\/tools<\/a> to find all the parts for your projects at the best price!<\/p><p style=\"text-align:center;\"><a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2017\/10\/header-200.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\"><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Project Overview<\/h2>\n\n\n\n<p>The following image shows the web server we&#8217;ll build in this tutorial.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"492\" height=\"650\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Web-Server-Display-Last-Photo-Captured.jpg?resize=492%2C650&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM Last photo Web Server Display Last Photo Captured\" class=\"wp-image-90439\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Web-Server-Display-Last-Photo-Captured.jpg?w=492&amp;quality=100&amp;strip=all&amp;ssl=1 492w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Web-Server-Display-Last-Photo-Captured.jpg?resize=227%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 227w\" sizes=\"(max-width: 492px) 100vw, 492px\" \/><\/figure><\/div>\n\n\n<p>When you access the web server, you\u2019ll see three buttons:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span class=\"rnthl rntclgray\"><strong>ROTATE:<\/strong><\/span> depending on your ESP32-CAM orientation, you might need to rotate the photo;<\/li>\n\n\n\n<li><span class=\"rnthl rntclgray\"><strong>CAPTURE PHOTO:<\/strong><\/span> when you click this button, the ESP32-CAM takes a new photo and saves it in the ESP32 SPIFFS. Please wait at least 5 seconds before refreshing the web page to ensure the ESP32-CAM takes and stores the photo;<\/li>\n\n\n\n<li><span class=\"rnthl rntclgray\"><strong>REFRESH PAGE:<\/strong><\/span> when you click this button, the web page refreshes and it\u2019s updated with the latest photo.<\/li>\n<\/ul>\n\n\n\n<p><strong>Note: <\/strong> as mentioned previously the latest photo captured is stored in the ESP32 SPIFFS, so even if you restart your board, you can always access the last saved photo.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Installing the ESP32 add-on<\/h2>\n\n\n\n<p>We\u2019ll program the ESP32 board using Arduino IDE. So, you need the Arduino IDE installed as well as the ESP32 add-on:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-esp32-arduino-ide-2-0\/\" title=\"\">Installing the ESP32 Board in Arduino IDE (Windows, Mac OS X, Linux)<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Installing Libraries<\/h2>\n\n\n\n<p>We&#8217;ll build the web server using the following libraries:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncWebServer\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncWebServer&nbsp;<\/a>by ESP32Async<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/ESP32Async\/AsyncTCP\" target=\"_blank\" rel=\"noopener\" title=\"\">AsyncTCP<\/a> by ESP32Async<\/li>\n<\/ul>\n\n\n\n<p>You can install these libraries in the Arduino Library Manager. Open the Library Manager by clicking the Library icon at the left sidebar.<\/p>\n\n\n\n<p>Search for <span class=\"rnthl rntliteral\">ESPAsyncWebServer<\/span> and install the <strong>ESPAsyncWebServer by ESP32Async<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"666\" height=\"586\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-ESPAsyncWebServer-Library-ArduinoIDE-2-f.png?resize=666%2C586&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Installing ESPAsyncWebServer ESP32 Arduino IDE\" class=\"wp-image-167890\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-ESPAsyncWebServer-Library-ArduinoIDE-2-f.png?w=666&amp;quality=100&amp;strip=all&amp;ssl=1 666w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-ESPAsyncWebServer-Library-ArduinoIDE-2-f.png?resize=300%2C264&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 666px) 100vw, 666px\" \/><\/figure><\/div>\n\n\n<p>Then, install the AsyncTCP library. Search for <span class=\"rnthl rntliteral\">AsyncTCP<\/span> and install the <strong>AsyncTCP by ESP32Async<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"722\" height=\"586\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-AsyncTCP-Library-ArduinoIDE.png?resize=722%2C586&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Installing AsyncTCP ESP32 Arduino IDE\" class=\"wp-image-167886\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-AsyncTCP-Library-ArduinoIDE.png?w=722&amp;quality=100&amp;strip=all&amp;ssl=1 722w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-AsyncTCP-Library-ArduinoIDE.png?resize=300%2C243&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 722px) 100vw, 722px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">ESP32-CAM Take and Display Photo Web Server Sketch<\/h2>\n\n\n\n<p>Copy the following code to your Arduino IDE. This code builds a web server that allows you to take a photo with your ESP32-CAM and display the last photo taken. Depending on the orientation of your ESP32-CAM, you may want to rotate the picture, so we also included that feature.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*********\n  Rui Santos\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-cam-take-photo-display-web-server\/\n  \n  IMPORTANT!!! \n   - Select Board &quot;AI Thinker ESP32-CAM&quot;\n   - GPIO 0 must be connected to GND to upload a sketch\n   - After connecting GPIO 0 to GND, press the ESP32-CAM on-board RESET button to put your board in flashing mode\n  \n  The above copyright notice and this permission notice shall be included in all\n  copies or substantial portions of the Software.\n*********\/\n\n#include &quot;WiFi.h&quot;\n#include &quot;esp_camera.h&quot;\n#include &quot;esp_timer.h&quot;\n#include &quot;img_converters.h&quot;\n#include &quot;Arduino.h&quot;\n#include &quot;soc\/soc.h&quot;           \/\/ Disable brownour problems\n#include &quot;soc\/rtc_cntl_reg.h&quot;  \/\/ Disable brownour problems\n#include &quot;driver\/rtc_io.h&quot;\n#include &lt;ESPAsyncWebServer.h&gt;\n#include &lt;SPIFFS.h&gt;\n#include &lt;FS.h&gt;\n\n\/\/ Replace with your network credentials\nconst char* ssid = &quot;REPLACE_WITH_YOUR_SSID&quot;;\nconst char* password = &quot;REPLACE_WITH_YOUR_PASSWORD&quot;;\n\n\/\/ Create AsyncWebServer object on port 80\nAsyncWebServer server(80);\n\nboolean takeNewPhoto = false;\n\n\/\/ Photo File Name to save in SPIFFS\n#define FILE_PHOTO &quot;\/photo.jpg&quot;\n\n\/\/ OV2640 camera module pins (CAMERA_MODEL_AI_THINKER)\n#define PWDN_GPIO_NUM     32\n#define RESET_GPIO_NUM    -1\n#define XCLK_GPIO_NUM      0\n#define SIOD_GPIO_NUM     26\n#define SIOC_GPIO_NUM     27\n#define Y9_GPIO_NUM       35\n#define Y8_GPIO_NUM       34\n#define Y7_GPIO_NUM       39\n#define Y6_GPIO_NUM       36\n#define Y5_GPIO_NUM       21\n#define Y4_GPIO_NUM       19\n#define Y3_GPIO_NUM       18\n#define Y2_GPIO_NUM        5\n#define VSYNC_GPIO_NUM    25\n#define HREF_GPIO_NUM     23\n#define PCLK_GPIO_NUM     22\n\nconst char index_html[] PROGMEM = R&quot;rawliteral(\n&lt;!DOCTYPE HTML&gt;&lt;html&gt;\n&lt;head&gt;\n  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\n  &lt;style&gt;\n    body { text-align:center; }\n    .vert { margin-bottom: 10%; }\n    .hori{ margin-bottom: 0%; }\n  &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;div id=&quot;container&quot;&gt;\n    &lt;h2&gt;ESP32-CAM Last Photo&lt;\/h2&gt;\n    &lt;p&gt;It might take more than 5 seconds to capture a photo.&lt;\/p&gt;\n    &lt;p&gt;\n      &lt;button onclick=&quot;rotatePhoto();&quot;&gt;ROTATE&lt;\/button&gt;\n      &lt;button onclick=&quot;capturePhoto()&quot;&gt;CAPTURE PHOTO&lt;\/button&gt;\n      &lt;button onclick=&quot;location.reload();&quot;&gt;REFRESH PAGE&lt;\/button&gt;\n    &lt;\/p&gt;\n  &lt;\/div&gt;\n  &lt;div&gt;&lt;img src=&quot;saved-photo&quot; id=&quot;photo&quot; width=&quot;70%&quot;&gt;&lt;\/div&gt;\n&lt;\/body&gt;\n&lt;script&gt;\n  var deg = 0;\n  function capturePhoto() {\n    var xhr = new XMLHttpRequest();\n    xhr.open('GET', &quot;\/capture&quot;, true);\n    xhr.send();\n  }\n  function rotatePhoto() {\n    var img = document.getElementById(&quot;photo&quot;);\n    deg += 90;\n    if(isOdd(deg\/90)){ document.getElementById(&quot;container&quot;).className = &quot;vert&quot;; }\n    else{ document.getElementById(&quot;container&quot;).className = &quot;hori&quot;; }\n    img.style.transform = &quot;rotate(&quot; + deg + &quot;deg)&quot;;\n  }\n  function isOdd(n) { return Math.abs(n % 2) == 1; }\n&lt;\/script&gt;\n&lt;\/html&gt;)rawliteral&quot;;\n\nvoid setup() {\n  \/\/ Serial port for debugging purposes\n  Serial.begin(115200);\n\n  \/\/ Connect to Wi-Fi\n  WiFi.begin(ssid, password);\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(1000);\n    Serial.println(&quot;Connecting to WiFi...&quot;);\n  }\n  if (!SPIFFS.begin(true)) {\n    Serial.println(&quot;An Error has occurred while mounting SPIFFS&quot;);\n    ESP.restart();\n  }\n  else {\n    delay(500);\n    Serial.println(&quot;SPIFFS mounted successfully&quot;);\n  }\n\n  \/\/ Print ESP32 Local IP Address\n  Serial.print(&quot;IP Address: http:\/\/&quot;);\n  Serial.println(WiFi.localIP());\n\n  \/\/ Turn-off the 'brownout detector'\n  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);\n\n  \/\/ OV2640 camera module\n  camera_config_t config;\n  config.ledc_channel = LEDC_CHANNEL_0;\n  config.ledc_timer = LEDC_TIMER_0;\n  config.pin_d0 = Y2_GPIO_NUM;\n  config.pin_d1 = Y3_GPIO_NUM;\n  config.pin_d2 = Y4_GPIO_NUM;\n  config.pin_d3 = Y5_GPIO_NUM;\n  config.pin_d4 = Y6_GPIO_NUM;\n  config.pin_d5 = Y7_GPIO_NUM;\n  config.pin_d6 = Y8_GPIO_NUM;\n  config.pin_d7 = Y9_GPIO_NUM;\n  config.pin_xclk = XCLK_GPIO_NUM;\n  config.pin_pclk = PCLK_GPIO_NUM;\n  config.pin_vsync = VSYNC_GPIO_NUM;\n  config.pin_href = HREF_GPIO_NUM;\n  config.pin_sccb_sda = SIOD_GPIO_NUM;\n  config.pin_sccb_scl = SIOC_GPIO_NUM;\n  config.pin_pwdn = PWDN_GPIO_NUM;\n  config.pin_reset = RESET_GPIO_NUM;\n  config.xclk_freq_hz = 20000000;\n  config.pixel_format = PIXFORMAT_JPEG;\n\n  if (psramFound()) {\n    config.frame_size = FRAMESIZE_UXGA;\n    config.jpeg_quality = 10;\n    config.fb_count = 2;\n  } else {\n    config.frame_size = FRAMESIZE_SVGA;\n    config.jpeg_quality = 12;\n    config.fb_count = 1;\n  }\n  \/\/ Camera init\n  esp_err_t err = esp_camera_init(&amp;config);\n  if (err != ESP_OK) {\n    Serial.printf(&quot;Camera init failed with error 0x%x&quot;, err);\n    ESP.restart();\n  }\n\n  \/\/ Route for root \/ web page\n  server.on(&quot;\/&quot;, HTTP_GET, [](AsyncWebServerRequest * request) {\n    request-&gt;send(200, &quot;text\/html&quot;, index_html);\n  });\n\n  server.on(&quot;\/capture&quot;, HTTP_GET, [](AsyncWebServerRequest * request) {\n    takeNewPhoto = true;\n    request-&gt;send(200, &quot;text\/plain&quot;, &quot;Taking Photo&quot;);\n  });\n\n  server.on(&quot;\/saved-photo&quot;, HTTP_GET, [](AsyncWebServerRequest * request) {\n    request-&gt;send(SPIFFS, FILE_PHOTO, &quot;image\/jpg&quot;, false);\n  });\n\n  \/\/ Start server\n  server.begin();\n\n}\n\nvoid loop() {\n  if (takeNewPhoto) {\n    capturePhotoSaveSpiffs();\n    takeNewPhoto = false;\n  }\n  delay(1);\n}\n\n\/\/ Check if photo capture was successful\nbool checkPhoto( fs::FS &amp;fs ) {\n  File f_pic = fs.open( FILE_PHOTO );\n  unsigned int pic_sz = f_pic.size();\n  return ( pic_sz &gt; 100 );\n}\n\n\/\/ Capture Photo and Save it to SPIFFS\nvoid capturePhotoSaveSpiffs( void ) {\n  camera_fb_t * fb = NULL; \/\/ pointer\n  bool ok = 0; \/\/ Boolean indicating if the picture has been taken correctly\n\n  do {\n    \/\/ Take a photo with the camera\n    Serial.println(&quot;Taking a photo...&quot;);\n\n    fb = esp_camera_fb_get();\n    if (!fb) {\n      Serial.println(&quot;Camera capture failed&quot;);\n      return;\n    }\n\n    \/\/ Photo file name\n    Serial.printf(&quot;Picture file name: %s\\n&quot;, FILE_PHOTO);\n    File file = SPIFFS.open(FILE_PHOTO, FILE_WRITE);\n\n    \/\/ Insert the data in the photo file\n    if (!file) {\n      Serial.println(&quot;Failed to open file in writing mode&quot;);\n    }\n    else {\n      file.write(fb-&gt;buf, fb-&gt;len); \/\/ payload (image), payload length\n      Serial.print(&quot;The picture has been saved in &quot;);\n      Serial.print(FILE_PHOTO);\n      Serial.print(&quot; - Size: &quot;);\n      Serial.print(file.size());\n      Serial.println(&quot; bytes&quot;);\n    }\n    \/\/ Close the file\n    file.close();\n    esp_camera_fb_return(fb);\n\n    \/\/ check if file has been correctly saved in SPIFFS\n    ok = checkPhoto(SPIFFS);\n  } while ( !ok );\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-CAM-Arduino-IDE\/raw\/master\/ESP32-CAM-Take-Photo-and-Display-Web-Server\/ESP32-CAM-Take-Photo-and-Display-Web-Server.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How the Code Works<\/h2>\n\n\n\n<p>First, include the required libraries to work with the camera, to build the web server and to use SPIFFS.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include \"WiFi.h\"\n#include \"esp_camera.h\"\n#include \"esp_timer.h\"\n#include \"img_converters.h\"\n#include \"Arduino.h\"\n#include \"soc\/soc.h\"           \/\/ Disable brownout problems\n#include \"soc\/rtc_cntl_reg.h\"  \/\/ Disable brownout problems\n#include \"driver\/rtc_io.h\"\n#include &lt;ESPAsyncWebServer.h&gt;\n#include &lt;SPIFFS.h&gt;\n#include &lt;FS.h&gt;<\/code><\/pre>\n\n\n\n<p>Next, write your network credentials in the following variables, so that the ESP32-CAM can connect to your local network.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const char* ssid = \"REPLACE_WITH_YOUR_SSID\";\nconst char* password = \"REPLACE_WITH_YOUR_PASSWORD\";<\/code><\/pre>\n\n\n\n<p>Create an <span class=\"rnthl rntliteral\">AsyncWebServer<\/span> object on port 80.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>AsyncWebServer server(80);<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">takeNewPhoto<\/span> boolean variable indicates when it&#8217;s time to take a new photo.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>boolean takeNewPhoto = false;<\/code><\/pre>\n\n\n\n<p>Then, define the path and name of the photo to be saved in SPIFFS. <\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define FILE_PHOTO \"\/photo.jpg\"<\/code><\/pre>\n\n\n\n<p>Next, define the camera pins for the ESP32-CAM AI THINKER module.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define PWDN_GPIO_NUM     32\n#define RESET_GPIO_NUM    -1\n#define XCLK_GPIO_NUM      0\n#define SIOD_GPIO_NUM     26\n#define SIOC_GPIO_NUM     27\n#define Y9_GPIO_NUM       35\n#define Y8_GPIO_NUM       34\n#define Y7_GPIO_NUM       39\n#define Y6_GPIO_NUM       36\n#define Y5_GPIO_NUM       21\n#define Y4_GPIO_NUM       19\n#define Y3_GPIO_NUM       18\n#define Y2_GPIO_NUM        5\n#define VSYNC_GPIO_NUM    25\n#define HREF_GPIO_NUM     23\n#define PCLK_GPIO_NUM     22<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Building the Web Page<\/h3>\n\n\n\n<p>Next, we have the HTML to build the web page:<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>const char index_html&#091;] PROGMEM = R\"rawliteral(\n&lt;!DOCTYPE HTML&gt;&lt;html&gt;\n&lt;head&gt;\n  &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;\n  &lt;style&gt;\n    body { text-align:center; }\n    .vert { margin-bottom: 10%; }\n    .hori{ margin-bottom: 0%; }\n  &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;div id=\"container\"&gt;\n    &lt;h2&gt;ESP32-CAM Last Photo&lt;\/h2&gt;\n    &lt;p&gt;It might take more than 5 seconds to capture a photo.&lt;\/p&gt;\n    &lt;p&gt;\n      &lt;button onclick=\"rotatePhoto();\"&gt;ROTATE&lt;\/button&gt;\n      &lt;button onclick=\"capturePhoto()\"&gt;CAPTURE PHOTO&lt;\/button&gt;\n      &lt;button onclick=\"location.reload();\"&gt;REFRESH PAGE&lt;\/button&gt;\n    &lt;\/p&gt;\n  &lt;\/div&gt;\n  &lt;div&gt;&lt;img src=\"saved-photo\" id=\"photo\" width=\"70%\"&gt;&lt;\/div&gt;\n&lt;\/body&gt;\n&lt;script&gt;\n  var deg = 0;\n  function capturePhoto() {\n    var xhr = new XMLHttpRequest();\n    xhr.open('GET', \"\/capture\", true);\n    xhr.send();\n  }\n  function rotatePhoto() {\n    var img = document.getElementById(\"photo\");\n    deg += 90;\n    if(isOdd(deg\/90)){ document.getElementById(\"container\").className = \"vert\"; }\n    else{ document.getElementById(\"container\").className = \"hori\"; }\n    img.style.transform = \"rotate(\" + deg + \"deg)\";\n  }\n  function isOdd(n) { return Math.abs(n % 2) == 1; }\n&lt;\/script&gt;\n&lt;\/html&gt;)rawliteral\";<\/code><\/pre>\n\n\n\n<p>We won&#8217;t go into much detail on how this HTML works. We&#8217;ll just take a quick overview.<\/p>\n\n\n\n<p>Basically, create three buttons: <strong><span class=\"rnthl rntliteral\">ROTATE<\/span><\/strong>; <strong><span class=\"rnthl rntliteral\">CAPTURE PHOTO<\/span><\/strong> and <strong><span class=\"rnthl rntliteral\">REFRESH PAGE<\/span><\/strong>. Each photo calls a different JavaScript function: <span class=\"rnthl rntliteral\">rotatePhoto()<\/span>, <span class=\"rnthl rntliteral\">capturePhoto()<\/span> and <span class=\"rnthl rntliteral\">reload()<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;button onclick=\"rotatePhoto();\"&gt;ROTATE&lt;\/button&gt;\n&lt;button onclick=\"capturePhoto()\"&gt;CAPTURE PHOTO&lt;\/button&gt;\n&lt;button onclick=\"location.reload();\"&gt;REFRESH PAGE&lt;\/button&gt;<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">capturePhoto()<\/span> function sends a request on the <span class=\"rnthl rntliteral\">\/capture<\/span> URL to the ESP32, so it takes a new photo.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function capturePhoto() {\n  var xhr = new XMLHttpRequest();\n  xhr.open('GET', \"\/capture\", true);\n  xhr.send();\n}<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">rotatePhoto()<\/span> function rotates the photo.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function rotatePhoto() {\n  var img = document.getElementById(\"photo\");\n  deg += 90;\n  if(isOdd(deg\/90)){ document.getElementById(\"container\").className = \"vert\"; }\n  else{ document.getElementById(\"container\").className = \"hori\"; }\n  img.style.transform = \"rotate(\" + deg + \"deg)\";\n}\nfunction isOdd(n) { return Math.abs(n % 2) == 1; }<\/code><\/pre>\n\n\n\n<p>We&#8217;re not sure what&#8217;s the &#8220;best&#8221; way to rotate a photo with JavaScript. This method works perfectly, but there may be better ways to do this. If you have any suggestion please share with us.<\/p>\n\n\n\n<p>Finally, the following section displays the photo.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;div&gt;&lt;img src=\"saved-photo\" id=\"photo\" width=\"70%\"&gt;&lt;\/div&gt;<\/code><\/pre>\n\n\n\n<p>When, you click the <strong><span class=\"rnthl rntliteral\">REFRESH<\/span><\/strong> button, it will load the latest image.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">setup()<\/h3>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, initialize a Serial communication:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.begin(115200);<\/code><\/pre>\n\n\n\n<p>Connect the ESP32-CAM to your local network:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>WiFi.begin(ssid, password);\nwhile (WiFi.status() != WL_CONNECTED) {\n  delay(1000);\n  Serial.println(\"Connecting to WiFi...\");\n}<\/code><\/pre>\n\n\n\n<p>Initialize SPIFFS:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (!SPIFFS.begin(true)) {\n  Serial.println(\"An Error has occurred while mounting SPIFFS\");\n  ESP.restart();\n}\nelse {\n  delay(500);\n  Serial.println(\"SPIFFS mounted successfully\");\n}<\/code><\/pre>\n\n\n\n<p>Print the ESP32-CAM local IP address:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.print(\"IP Address: http:\/\/\");\nSerial.println(WiFi.localIP());<\/code><\/pre>\n\n\n\n<p>The lines that follow, configure and initialize the camera with the right settings.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Handle the Web Server<\/h3>\n\n\n\n<p>Next, we need to handle what happens when the ESP32-CAM receives a request on a URL.<\/p>\n\n\n\n<p>When the ESP32-CAM receives a request on the root <strong>\/<\/strong> URL, we send the HTML text to build the web page.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/\", HTTP_GET, &#091;](AsyncWebServerRequest * request) {\n  request-&gt;send(200, \"text\/html\", index_html);\n});<\/code><\/pre>\n\n\n\n<p>When we press the &#8220;<span class=\"rnthl rntliteral\">CAPTURE<\/span>&#8221; button on the web server, we send a request to the ESP32 <strong>\/capture<\/strong> URL. When that happens, we set the <span class=\"rnthl rntliteral\">takeNewPhoto<\/span> variable to <span class=\"rnthl rntliteral\">true<\/span>, so that we know it is time to take a new photo.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/capture\", HTTP_GET, &#091;](AsyncWebServerRequest * request) {\n  takeNewPhoto = true;\n  request-&gt;send(200, \"text\/plain\", \"Taking Photo\");\n});<\/code><\/pre>\n\n\n\n<p>In case there&#8217;s a request on the <strong>\/saved-photo<\/strong> URL, send the photo saved in SPIFFS to a connected client:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/saved-photo\", HTTP_GET, &#091;](AsyncWebServerRequest * request) {\n  request-&gt;send(SPIFFS, FILE_PHOTO, \"image\/jpg\", false);\n});<\/code><\/pre>\n\n\n\n<p>Finally, start the web server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.begin();<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">loop()<\/h3>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">loop()<\/span>, if the <span class=\"rnthl rntliteral\">takeNewPhoto<\/span> variable is True, we call the <span class=\"rnthl rntliteral\">capturePhotoSaveSpiffs()<\/span> to take a new photo and save it to SPIFFS. Then, set the <span class=\"rnthl rntliteral\">takeNewPhoto<\/span> variable to <span class=\"rnthl rntliteral\">false<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void loop() {\n  if (takeNewPhoto) {\n    capturePhotoSaveSpiffs();\n    takeNewPhoto = false;\n  }\n  delay(1);\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Take a Photo<\/h3>\n\n\n\n<p>There are two other functions in the sketch: <span class=\"rnthl rntliteral\">checkPhoto()<\/span> and <span class=\"rnthl rntliteral\">capturePhotoSaveSpiffs()<\/span>.<\/p>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">checkPhoto()<\/span> function checks if the photo was successfully saved to SPIFFS.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>bool checkPhoto( fs::FS &amp;fs ) {\n  File f_pic = fs.open( FILE_PHOTO );\n  unsigned int pic_sz = f_pic.size();\n  return ( pic_sz &gt; 100 );\n}<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">capturePhotoSaveSpiffs()<\/span> function takes a photo and saves it to SPIFFS.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void capturePhotoSaveSpiffs( void ) {\n  camera_fb_t * fb = NULL; \/\/ pointer\n  bool ok = 0; \/\/ Boolean indicating if the picture has been taken correctly\n\n  do {\n    \/\/ Take a photo with the camera\n    Serial.println(\"Taking a photo...\");\n\n    fb = esp_camera_fb_get();\n    if (!fb) {\n      Serial.println(\"Camera capture failed\");\n      return;\n    }\n\n    \/\/ Photo file name\n    Serial.printf(\"Picture file name: %s\\n\", FILE_PHOTO);\n    File file = SPIFFS.open(FILE_PHOTO, FILE_WRITE);\n\n    \/\/ Insert the data in the photo file\n    if (!file) {\n      Serial.println(\"Failed to open file in writing mode\");\n    }\n    else {\n      file.write(fb-&gt;buf, fb-&gt;len); \/\/ payload (image), payload length\n      Serial.print(\"The picture has been saved in \");\n      Serial.print(FILE_PHOTO);\n      Serial.print(\" - Size: \");\n      Serial.print(file.size());\n      Serial.println(\" bytes\");\n    }\n    \/\/ Close the file\n    file.close();\n    esp_camera_fb_return(fb);\n\n    \/\/ check if file has been correctly saved in SPIFFS\n    ok = checkPhoto(SPIFFS);\n  } while ( !ok );\n}<\/code><\/pre>\n\n\n\n<p>This function was based on <a rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\" href=\"https:\/\/github.com\/dualvim\/BasicESP32-CAM\" target=\"_blank\">this sketch by dualvim<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">ESP32-CAM Upload Code<\/h3>\n\n\n\n<p>To upload code to the <a aria-label=\"ESP32-CAM (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/tools\/esp32-cam\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32-CAM<\/a> board, connect it to your computer using an&nbsp;<a aria-label=\" (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/tools\/ftdi-programmer-board\/\" target=\"_blank\" rel=\"noreferrer noopener\">FTDI programmer<\/a>. Follow the next schematic diagram:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"877\" height=\"532\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/ESP32-CAM-FTDI-programmer.png?resize=877%2C532&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM connected to an FTDI Programmer to upload program using Arduino IDE\" class=\"wp-image-159060\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/ESP32-CAM-FTDI-programmer.png?w=877&amp;quality=100&amp;strip=all&amp;ssl=1 877w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/ESP32-CAM-FTDI-programmer.png?resize=300%2C182&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/ESP32-CAM-FTDI-programmer.png?resize=768%2C466&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 877px) 100vw, 877px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntcred\"><strong>Important: <\/strong> GPIO 0&nbsp;needs to be connected to&nbsp;GND&nbsp;so that you\u2019re able to upload code.<\/p>\n\n\n\n<p>Many FTDI programmers have a jumper that allows you to select 3.3V or 5V. Make sure the jumper is in the right place to select 5V.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>ESP32-CAM<\/strong><\/td><td><strong>FTDI Programmer<\/strong><\/td><\/tr><tr><td>GND<\/td><td>GND<\/td><\/tr><tr><td>5V<\/td><td>VCC (5V)<\/td><\/tr><tr><td>U0R<\/td><td>TX<\/td><\/tr><tr><td>U0T<\/td><td>RX<\/td><\/tr><tr><td>GPIO 0<\/td><td>GND<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>To upload the code, follow the next steps:<\/p>\n\n\n\n<p>1) Go to <strong>Tools <\/strong>&gt; <strong>Board <\/strong>and select <strong>AI-Thinker ESP32-CAM<\/strong>.<\/p>\n\n\n\n<p>2) Go to <strong>Tools <\/strong>&gt; <strong>Port <\/strong>and select the COM port the ESP32 is connected to.<\/p>\n\n\n\n<p>3) Then, click the upload button to upload the code.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"32\" height=\"32\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/12\/upload-button-arduino-ide.png?resize=32%2C32&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" class=\"wp-image-91745\"\/><\/figure><\/div>\n\n\n<p>4) When you start to see these dots on the debugging window as shown below, press the ESP32-CAM on-board RST button.   <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1009\" height=\"91\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/12\/dots-uploading-code.png?resize=1009%2C91&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" class=\"wp-image-91746\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/12\/dots-uploading-code.png?w=1009&amp;quality=100&amp;strip=all&amp;ssl=1 1009w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/12\/dots-uploading-code.png?resize=300%2C27&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/12\/dots-uploading-code.png?resize=768%2C69&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1009px) 100vw, 1009px\" \/><\/figure>\n\n\n\n<p>After a few seconds, the code should be successfully uploaded to your board.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Demonstration<\/h2>\n\n\n\n<p>Open your browser and type the ESP32-CAM IP Address. Then, click the &#8220;<strong>CAPTURE PHOTO<\/strong>&#8221; to take a new photo and wait a few seconds for the photo to be saved in SPIFFS.<\/p>\n\n\n\n<p>Then, if you press the &#8220;<strong>REFRESH PAGE<\/strong>&#8221; button, the page will update with the latest saved photo. If you need to adjust the image orientation, you can always use the &#8220;<strong>ROTATE<\/strong>&#8221; button to do it so.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Web-Server-Display-Last-Photo-Captured-Demonstration.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM Web Server Display Last Photo Captured Demonstration\" class=\"wp-image-90447\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Web-Server-Display-Last-Photo-Captured-Demonstration.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Web-Server-Display-Last-Photo-Captured-Demonstration.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>In your Arduino IDE Serial Monitor window, you should see similar messages:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"769\" height=\"504\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Take-Photo-Display-Web-Server-Arduino-IDE-Serial-Monitor.png?resize=769%2C504&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32-CAM Web Server Display Last Photo Captured Arduino IDE Serial Monitor\" class=\"wp-image-90457\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Take-Photo-Display-Web-Server-Arduino-IDE-Serial-Monitor.png?w=769&amp;quality=100&amp;strip=all&amp;ssl=1 769w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Take-Photo-Display-Web-Server-Arduino-IDE-Serial-Monitor.png?resize=300%2C197&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Take-Photo-Display-Web-Server-Arduino-IDE-Serial-Monitor.png?resize=768%2C503&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 769px) 100vw, 769px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Troublehsooting<\/h2>\n\n\n\n<p>If you\u2019re getting any of the following errors, read our&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-troubleshooting-guide\/\"><strong>ESP32-CAM Troubleshooting Guide: Most Common Problems Fixed<\/strong><\/a><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Failed to connect to ESP32: Timed out waiting for packet header<\/li>\n\n\n\n<li>Camera init failed with error 0x20001 or similar<\/li>\n\n\n\n<li>Brownout detector or Guru meditation error<\/li>\n\n\n\n<li>Sketch too big error \u2013 Wrong partition scheme selected<\/li>\n\n\n\n<li>Board at COMX is not available \u2013 COM Port Not Selected<\/li>\n\n\n\n<li>Psram error: GPIO isr service is not installed<\/li>\n\n\n\n<li>Weak Wi-Fi Signal<\/li>\n\n\n\n<li>No IP Address in Arduino IDE Serial Monitor<\/li>\n\n\n\n<li>Can\u2019t open web server<\/li>\n\n\n\n<li>The image lags\/shows lots of latency<\/li>\n<\/ul>\n\n\n\t\t<div data-elementor-type=\"section\" data-elementor-id=\"94673\" class=\"elementor elementor-94673\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-2689e44b elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"2689e44b\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-7490d123\" data-id=\"7490d123\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-inner-section elementor-element elementor-element-35934f78 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"35934f78\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-3de108d9\" data-id=\"3de108d9\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-5aca63ab elementor-widget elementor-widget-image\" data-id=\"5aca63ab\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-projects-ebook\/\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"334\" height=\"334\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/03\/ESP32-CAM-eBook-334.jpg?fit=334%2C334&amp;quality=100&amp;strip=all&amp;ssl=1\" class=\"attachment-full size-full wp-image-94555\" alt=\"\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/03\/ESP32-CAM-eBook-334.jpg?w=334&amp;quality=100&amp;strip=all&amp;ssl=1 334w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/03\/ESP32-CAM-eBook-334.jpg?resize=300%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/03\/ESP32-CAM-eBook-334.jpg?resize=150%2C150&amp;quality=100&amp;strip=all&amp;ssl=1 150w\" sizes=\"(max-width: 334px) 100vw, 334px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-4bd084e0\" data-id=\"4bd084e0\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-517cf0fa elementor-widget elementor-widget-heading\" data-id=\"517cf0fa\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\"><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-projects-ebook\/\">[eBook] Build ESP32-CAM Projects using Arduino IDE<\/a><\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3438ea70 elementor-hidden-phone elementor-widget elementor-widget-text-editor\" data-id=\"3438ea70\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Learn how to program and build 17 projects with the ESP32-CAM using Arduino IDE\u00a0<strong><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-projects-ebook\/\" rel=\"noopener\">DOWNLOAD \u00bb<\/a><\/strong><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<div class=\"elementor-element elementor-element-674524a5 elementor-hidden-desktop elementor-hidden-tablet elementor-widget elementor-widget-text-editor\" data-id=\"674524a5\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Learn how to program and build 17 projects with the ESP32-CAM using Arduino IDE <strong><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-projects-ebook\/\" rel=\"noopener\">DOWNLOAD \u00bb<\/a><\/strong><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>We hope you&#8217;ve found this example useful. We&#8217;ve tried to keep it as simple as possible so it is easy for you to modify and include it in your own projects. You can combine this example with the <a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-pir-motion-detector-photo-capture\/\">ESP32-CAM PIR Motion Detector with Photo Capture<\/a> to capture and display a new photo when motion is detected.<\/p>\n\n\n\n<p>For more ESP32-CAM projects you can&nbsp;<strong><a href=\"https:\/\/randomnerdtutorials.com\/download\/\">subscribe to our newsletter<\/a><\/strong>. If you don\u2019t have an ESP32-CAM yet, you can&nbsp;<a rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\" href=\"https:\/\/makeradvisor.com\/tools\/esp32-cam\/\" target=\"_blank\">get one for approximately $6<\/a>.<\/p>\n\n\n\n<p>If you like this project, you may also like other projects with the ESP32-CAM:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-ai-thinker-pinout\/\">ESP32-CAM AI-Thinker Pinout Guide: GPIOs Usage Explained<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-video-streaming-face-recognition-arduino-ide\/\" target=\"_blank\" rel=\"noreferrer noopener\">Video Streaming, Face Detection and Face Recognition<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-projects-ebook\/\"><strong>Build ESP32-CAM Projects (eBook)<\/strong><\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32-cam\/\"><strong>Read all our ESP32-CAM Projects, Tutorials and Guides<\/strong><\/a><\/li>\n<\/ul>\n\n\n\n<p>Thank you for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to build a web server with the ESP32-CAM board that allows you to send a command to take a photo and visualize the latest captured photo in your &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32-CAM Take Photo and Display in Web Server\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-take-photo-display-web-server\/#more-90367\" aria-label=\"Read more about ESP32-CAM Take Photo and Display in Web Server\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":1,"featured_media":90449,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[281,276,277,319,264],"tags":[],"class_list":["post-90367","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32-project","category-esp32","category-esp32-arduino-ide","category-esp32-cam","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/10\/ESP32-CAM-Take-Photo-Display-Web-Server.jpg?fit=1280%2C720&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/90367","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=90367"}],"version-history":[{"count":4,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/90367\/revisions"}],"predecessor-version":[{"id":167994,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/90367\/revisions\/167994"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/90449"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=90367"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=90367"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=90367"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}