Skip to content

Works with ESP32-CAM

What this example presents

ESP-IDF is offering ESP32 Camera Driver as an interface to small image sensors that can work with ESP32. This driver supports a variety of popular image sensors, such as the OV2640, which has low power consumption and mega-pixel sensing capability. By reading through this chapter you will know how to make the sketch featuring a UI that looks like the followings. Of course, it has the convenience of AutoConnect as well. This example shows how to sketch the Web Camera Application that involves using AutoConnect together with the ESP32 Camera Driver.

Why we can not use app_httpd.cpp together with AutoConnect

The ESP32 library of the ESP32 Arduino core features a CameraWebServer.ino that includes an interface to drive the Camera Driver. The core process of the server-side of that sketch application is app_httpd.cpp, which consists of initializing and configuring the image sensor, configuring and capturing image frames, and sending the image frames through an internally started HTTP server.

While Web UI provided by CameraWebServer.ino is sophisticated, the role of app_httpd.cpp is focused on responding to the Fetch required by the Web UI (which is actually an HTML page specific to each sensor model that is extracted from the gzipped camera_index.h). It is a set of primitive functions that are integrated with the Web UI. Also, app_httpd.cpp has hardcoded the TCP port of the internally invoking HTTP server as fixed at 80, which conflicts with the HTTP port used by a typical captive portal. Therefore, It is impossible to apply app_httpd.cpp which has fixed 80 TCP port depending on the WebUI of CameraWebServer.ino to sketches using AutoConnect as it is.

CameraWebServer.ino extended version available on GitHub

An extended version of app_httpd.cpp is available on the GitHub repository to make it a bit more flexible for different usage scenarios. It also can handling the captive portal itself.

Strategy

As mentioned earlier, app_httpd.cpp is integrated with CameraWebServer.ino's Web UI. However, its functionality can be separated into two parts: an interface for driving the image sensor correctly and sending the captured images on the HTTP stream as requested by the client. It also has the ability to configure the sensor settings over the network remotely, but this can be omitted at the expense of interactivity. (We can implement that feature after the initial purpose is achieved)

So, I have prepared two separate classes with these functions. ESP32WebCam and ESP32Cam are independent classes inspired by app-httpd.cpp, and they can interface with the ESP32 Camera Driver individually, or send out motion JPEGs via an HTTP server task running inside the class.

These two classes are completely independent of the AutoConnect library and can be incorporated into your various other sketches on their own. the source code for the ESP32WebCam and ESP32Cam classes can be found in the AutoConnect library examples and are distributed together. The API specifications for these two classes are described later in this chapter.

Implementing a Streaming Server with ESP32-CAM using AutoConnect

A minimal sketch that involves the ESP32WebCam and ESP32Cam classes and incorporates them together with AutoConnect is shown below. This sketch will work with Ai-Thinker ESP32-CAM, which is one of the most popular ESP32 modules with OmniVision OV2640 image sensor.

In order to experience this sketch, copy the five files ESP32WebCam.h, ESP32WebCam.cpp, ESP32Cam.h, ESP32Cam.cpp, and ESP32Cam_pins.h from the WebCamServer folder located AutoConnect library examples to the same folder as the sketchbook folder where you placed this sketch. Connect the ESP32-CAM module to your PC and launch the Arduino IDE. Then select the correct board you using from the Tool menu of Arduino IDE and compile it. (Don't forget to open the serial monitor)

#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <AutoConnect.h>
#include "ESP32WebCam.h"

const char  CAMERA_VIEWER[] = R"*(
{
  "title": "Camera",
  "uri": "/",
  "menu": false,
  "element": [
    {
      "name": "viewport",
      "type": "ACText",
      "format": "<img src='http://%s'>",
      "posterior": "none"
    },
    {
      "name": "discon",
      "type": "ACElement",
      "value": "<script>window.addEventListener('pagehide',function(){window.stop();});</script>"
    }
  ]
}
)*";

// Declare ESP32-CAM handling interface. It contains ESP-IDF Web Server.
ESP32WebCam webcam(ESP32Cam::CAMERA_MODEL_AI_THINKER);

// AutoConnect portal. It contains the WebServer from ESP32 Arduino Core.
AutoConnect portal;
AutoConnectConfig config;

// AutoConnectAux page handler, it starts streaming by adding the ESP32WebCam
// streaming endpoint to the src attribute of the img tag on the AutoConnectAux page.
String viewer(AutoConnectAux& aux, PageArgument &args) {
  AutoConnectAux& viewer = *portal.aux("/");
  // Set the Streaming server host, port, and endpoint
  viewer["viewport"].value = WiFi.localIP().toString() + ":" + String(webcam.getServerPort())
                           + String(webcam.getStreamPath());
  return String();
}

void setup() {
  delay(1000);
  Serial.begin(115200);
  Serial.println();

  // Start Image sensor
  if (webcam.sensorInit() != ESP_OK) {
    Serial.println("Camera initialize failed");
  }

  // Allow automatic re-connection as long as the WiFi connection is established.
  config.autoReconnect = true;
  config.reconnectInterval = 1;
  portal.config(config);

  // Start the portal, it will launch the WebServer for the portal from inside of AutoConnect.
  if (portal.begin()) {
    portal.load(CAMERA_VIEWER);
    portal.on("/", viewer);
    // Start ESP32 Camera Web Server
    if (webcam.startCameraServer() == ESP_OK) {
      Serial.printf("ESP32WebCam server %s port %u ready\n", WiFi.localIP().toString().c_str(),
        webcam.getServerPort());
    }
    else {
      Serial.println("ESP32WebCam server start failed");
    }
  }
}

void loop() {
  portal.handleClient();
}

If your ESP32-CAM module still has no connection with any access point, a captive portal will open. Use your cellphone to connect the ESP32-CAM to the access point. When ESP32-CAM successfully connects to the access point, you will see the IP address on the serial monitor. You visit the IP address from your browser, you can see the image captured by the ESP32-CAM.

Streaming stops caused by ERR_CONNECTION_RESET

Sometimes the browser will throw the above error and the streaming will stop. In the simple sketch above, which does not include the transmission error recovery process, the TCP packet transmission is incomplete due to a weak WiFi signal or other reasons, and the browser will stop loading the image. Send errors can be recovered by incorporating an event handler into the img tag, and an example of its implementation is shown later in this chapter.

Program structure

The sketch of AutoConnect using ESP32WebCam and ESP32Cam classes is divided into several components, which will take a similar form in any sketch application. Their logical components are as follows:

  1. Include ESP32WebCam.h header file.

    #include "ESP32WebCam.h"
    

  2. AutoConnectAux defines a custom web page in JSON description. It includes an img tag that displays the captured image. The src attribute of the img tag is not hard-coded and can be dynamically set in a custom web page handler to make the sketch more applicable to various situations.

    {
      "name": "viewport",
      "type": "ACText",
      "format": "<img src='http://%s'>",
      "posterior": "none"
    }
    

  3. Insert AutoConnectElement in the JSON description of your custom web page with JavaScript enclosed in <script>~</script> in HTML to stop streaming on page transition.

    window.addEventListener('pagehide', function () {
      window.stop();
    });
    

    Why window.stop() is needed

    That's because image streaming is achieved by continuous loading of Motion JPEG using HTTP multipart/x-mixed-replace keep-alive stream. With this type of MIME content, the server will continue to push the content unless the client explicitly notifies the server of the end of the session. The method of notifying the end of the session varies depending on the client browser, and by issuing window.stop(), the difference in the behavior of each browser is absorbed.

  4. Declare ESP32WebCam instance. It accompanies the parameters with the appropriate model specifiers.

    ESP32WebCam webcam(ESP32Cam::CAMERA_MODEL_AI_THINKER);
    
    For details on identifiers that can be specified as image sensor models, please refer to the APIs described below.

  5. Declare AutoConnect instance. If your sketch requires a native web page that is not an AutoConnectAux, you can declare a WebServer instance at the same place to make it easier to call from functions in your sketch.

    AutoConnect portal;
    

  6. Declare AutoConnectConfig to control WiFi connection behavior if necessary.

    AutoConnectConfig config;
    

  7. Prepare an AutoConnectAux custom page handler for the declared above AutoConnectAux JSON. Typically, this handler is responsible for handling the ESP32Cam class via the endpoint interface provided by the ESP32Cam class. In the above sketch, we have only given the endpoint (i.e. http://{WiFi.localIP}:3000/_stream) for streaming by the ESP32WebCam class as the src attribute of the img tag identified id=viewport, since we are focusing on the minimum necessary processing. ESP32WebCam class will deliver the captured image with just this operation.

    AutoConnectAux& viewer = *portal.aux("/");
    viewer["viewport"].value = WiFi.localIP().toString() + ":" + String(webcam.getServerPort())
                             + String(webcam.getStreamPath());
    
    For more information about ESP32Cam capability and ESP32WebCam endpoints, please refer to the Endpoint interfaces described below.

    Using AutoConnectText with format string

    In the sketch above, the format attribute of AutoConnectText is used to set the src attribute of the img tag. The AutoConnectText format attribute produces the same output as a C-style printf(format, value), depending on the string that can be derived from the value.

    printf("<img src='http://%s'>", "localhost:3000/_stream");
    

  8. Start the sketch and initialize the camera using ESP32WebCam::sensorInit. ESP_OK will returned on success to initialize the image sensor.

    ESP32WebCam webcam(ESP32Cam::CAMERA_MODEL_AI_THINKER);
    
    if (webcam.sensorInit() != ESP_OK) {
      Serial.println("Camera initialize failed");
    }
    

  9. Configure WiFi state control to maintain connection. Usually, AutoConnectConfig::autoReconnect will keep WiFi connection stateful.

    config.autoReconnect = true;
    config.reconnectInterval = 1;
    portal.config(config);
    

  10. Start the portal, and load the view page.

    portal.begin();
    portal.load(CAMERA_VIEWER);
    

  11. Register the view page handler and start the streaming server using ESP32WebCam::startCameraServer. ESP_OK will returned on start the streaming server successfully.

    portal.on("/", viewer);
    if (webcam.startCameraServer() == ESP_OK) {
      Serial.printf("ESP32WebCam server ready: %s\n", WiFi.localIP().toString().c_str());
    }
    else {
      Serial.println("ESP32WebCam server start failed");
    }
    

  12. Loop for portal.handleClient().

The app_httpd.cpp, which is the core of CameraWebServer.ino's functionality, has a mixture of an interface with the ESP32 Camera Driver and remote control over the network via an HTTP server. While it is highly functional, but it will cause a decline in versatility. ESP32WebCam and ESP32Cam separate the mixed functionality of app_httpd.cpp into two classes, each with a single role. This makes them versatile and simple to use. And they can coexist with AutoConnect.

If you only need to stream from the image sensor, you can simplify the sketch structure as in the example above. The simplicity of the sketch is mainly due to the usefulness of the ESP32WebCam and ESP32Cam classes. In driving the ESP32 Camera Driver on the ESP32-CAM module, the sketch interfaces with the ESP32WebCam class and processes the ESP32Cam class through the ESP32WebCam endpoint interface.

ESP32-CAM.ino sketch structure

ESP32WebCam Class and ESP32Cam Class

The ESP32WebCam class has an endpoint interface to allow the sketch to manipulate the image sensor over the network. The sketch can use HTTP GET method to capture images, stream the captured images, and save them to SD card. It also starts its own HTTP server task internally, and this HTTP server runs as a separate task from the WebServer hosted by AutoConnect.

The ESP32Cam class is a wrapper that governs the native interface with the ESP32 Camera Driver which is a component of ESP-IDF. It can initialize the sensor, set the sensor characteristics, save and load the settings, and save the captured images to the SD card.

In the case of accessing image sensors located across a network, the sketch will usually have a UI to remotely control the ESP32-CAM. If the UI is intended to be a web interface, the sketch will use a request handler that is compatible with the ESP32 WebServer hosted by AutoConnect to serve the manipulation web page. That page can be an AutoConnectAux-based custom web page, or it can be the RequestHanlder callback that can respond to the ESP32 WebServer class. In any case, those UI pages can remotely access the image sensor of the ESP32-CAM module through the HTTP endpoint interface deployed at a specific URL of the HTTP server launched by the ESP32WebCam class, and do the required processing.

ESP32WebCam features:

  • Run the HTTP server as a background task.
  • Stream Motion JPEG via HTTP multipart/x-mixed-replace MIME.
  • Serves a captured image via HTTP.
  • Instruct the ESP32Cam to save the captured image to the SD card via HTTP.

Of these processing requests, the ESP32Cam class is responsible for the ones that actually need to interface with the camera driver. (However, reading from the frame buffer is excluded. ESP32WebCam reads image data directly from the frame buffer of the image sensor without ESP32Cam.) The ESP32Cam class manipulates sensor characteristics, including setting image frame properties, image format settings, and exposure, gain, white balance, and band filter settings. It also saves the captured image to an SD card wired to the ESP32-CAM.

ESP32Cam features:

  • Directs and acquires sensor settings.
  • Save and load the sensor settings to the flash memory on the ESP32 module.
  • Save the captured image to the SD card which is wired to ESP32 module.
  • Save captured images to SD card periodically using an ESP32 built-in hardware timer.

ESP32WebCam Class APIs

Constructor

ESP32WebCam(const uint16_t port = ESP32CAM_DEFAULT_HTTPPORT)
ESP32WebCam(const ESP32Cam::CameraId model, const uint16_t port = ESP32CAM_DEFAULT_HTTPPORT)

Instantiate ESP32WebCam. The constructor also instantiates ESP32Cam, so there is no need to explicitly declare the ESP32Cam class in the sketch. At the time of declaring the constructor, the camera is not initialized and the HTTP server is not started. Each of them requires a separate dedicated function to be called.

Parameters
portPort number of the HTTP server that ESP32WebCam starts. Default port number defined by ESP32CAM_DEFAULT_HTTPPORT macro directive in ESP32WebCam.h
modelSpecifies the model of the onboard image sensor. The image sensor models that can be specified are as follows:

  • ESP32Cam::CAMERA_MODEL_WROVER_KIT
  • ESP32Cam::CAMERA_MODEL_ESP_EYE
  • ESP32Cam::CAMERA_MODEL_M5STACK_NO_PSRAM
  • ESP32Cam::CAMERA_MODEL_M5STACK_PSRAM
  • ESP32Cam::CAMERA_MODEL_M5STACK_V2_PSRAM
  • ESP32Cam::CAMERA_MODEL_M5STACK_WIDE
  • ESP32Cam::CAMERA_MODEL_M5STACK_ESP32CAM
  • ESP32Cam::CAMERA_MODEL_M5STACK_UNITCAM
  • ESP32Cam::CAMERA_MODEL_AI_THINKER
  • ESP32Cam::CAMERA_MODEL_TTGO_T_JOURNAL

getCapturePath

const char* getCapturePath(void)

Get a path containing the first '/' of the currently valid endpoint URL to capture.

Return value
A path of capturing URL. Default path defined by ESP32CAM_DEFAULT_PATH_CAPTURE macro directive in ESP32WebCam.h.

getPromptPath

const char* getPromptPath(void)

Get a path containing the first '/' of the currently valid endpoint URL to prompt.

Return value
A path of prompting URL. Default path defined by ESP32CAM_DEFAULT_PATH_PROMPT macro directive in ESP32WebCam.h.

getServerHandle

httpd_handle_t getServerHandle(void)

Returns the handle of the HTTP server started by ESP32WebCam.

Return value
Returns the httpd_handle_t value of an HTTP server started by ESP32WebCam. If the HTTP server task is not running, nullptr is returned.

getServerPort

uint16_t getServerPort(void)

Returns the port number that the HTTP server on listens to.

Return value
Returns a port number of an HTTP server started by ESP32WebCam. Default port number defined by ESP32CAM_DEFAULT_HTTPPORT macro directive in ESP32WebCam.h

getStreamPath

const char* getStreamPath(void)

Get a path containing the first '/' of the currently valid endpoint URL to streaming.

Return value
A path of streaming URL. Default path defined by ESP32CAM_DEFAULT_PATH_STREAM macro directive in ESP32WebCam.h.

isServerStarted

bool isServerStarted(void)

Returns a boolean value indicating whether the HTTP server task is running or not.

Return value
trueThe HTTP Server tasks is running.
falseThe HTTP server task has not been started.

sensor

ESP32Cam& sensor(void)

Returns a reference to ESP32Cam, which is instantiated internally by ESP32WebCam constructor.

Return value
A reference to ESP32Cam instance. The image sensor is not initialized just by calling the ESP32WebCam constructor. To initialize the sensor, you need to call the sensorInit() function.

ESP32WebCam webcam();
webcam.sensorInit();

sensorInit

esp_err_t sensorInit(void)
esp_err_t sensorInit(const ESP32Cam::CameraId model)

Initialize the image sensor via the ESP32Cam class. The sketch needs to initialize the sensor with the sensorInit function prior to all processing of the image sensor.

Parameters
modelSpecifies the model of the onboard image sensor. The image sensor models that can be specified are same as the constructor parameter.
Return value
ESP_OKAn image sensor successfully initialized.
ESP_ERR_CAMERA_NOT_SUPPORTEDSpecified model is not supported.
ESP_ERR_CAMERA_NOT_DETECTEDAn image sensor not detected.
ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZEFrame identifier is invalid.
ESP_ERR_CAMERA_FAILED_TO_SET_OUT_FORMATOutput image format is invalid.
ESP_FAILOther error occurred.

setCapturePath

void setCapturePath(const char* path)

Reconfigure the already defined path of the endpoint for capture.

Parameters
pathSpecifies the path of the capture endpoint to be set newly, as a string starting with '/'. If this path is not specified, the default path defined by ESP32CAM_DEFAULT_PATH_CAPTURE macro directive will be assumed.

setPromptPath

void setPromptPath(const char* path)

Reconfigure the already defined path of the endpoint for prompt.

Parameters
pathSpecifies the path of the prompt endpoint to be set newly, as a string starting with '/'. If this path is not specified, the default path defined by ESP32CAM_DEFAULT_PATH_PROMPT macro directive will be assumed.

setServerPort

void setServerPort(const uint16_t port)

Reconfigure the already defined port number of an HTTP server.

Parameters
portSpecifies port number of an HTTP Server. Default port number defined by ESP32CAM_DEFAULT_HTTPPORT macro directive will be assumed.

setStreamPath

void setStreamPath(const char* path)

Reconfigure the already defined path of the endpoint for stream.

Parameters
pathSpecifies the path of the stream endpoint to be set newly, as a string starting with '/'. If this path is not specified, the default path defined by ESP32CAM_DEFAULT_PATH_STREAM macro directive will be assumed.

startCameraServer

esp_err_t startCameraServer(const char* streamPath)
esp_err_t startCameraServer(const char* streamPath, const char* capturePath, const char* promptPath)
esp_err_t startCameraServer(const char* streamPath, const char* capturePath, const char* promptPath, const uint16_t port)
esp_err_t startCameraServer(const char* streamPath, const uint16_t port)
esp_err_t startCameraServer(const uint16_t port)
esp_err_t startCameraServer(void)

Begins the HTTP server task, and start the endpoint service. By starting the HTTP server task, the endpoint interface provided by ESP32WebCam will be available.

Parameters
streamPathSpecifies the path of the stream endpoint. Default stream path is defined by ESP32CAM_DEFAULT_PATH_STREAM macro directive in ESP32WebCam.h header file.
capturePathSpecifies the path of the capture endpoint. Default capture path is defined by ESP32CAM_DEFAULT_PATH_CAPTURE macro directive in ESP32WebCam.h header file.
promptPathSpecifies the path of the prompt endpoint. Default prompt path is defined by ESP32CAM_DEFAULT_PATH_PROMPT macro directive in ESP32WebCam.h header file.
portSpecifies port number on which the HTTP server listens. Default port number is 3000 which defined by ESP32CAM_DEFAULT_HTTPPORT macro directive in ESP32WebCam.h header file.
Return value
ESP_OKAn HTTP server task successfully started.
ESP_ERR_HTTPD_HANDLERS_FULLAll slots for registering URI handlers have been consumed.
ESP_ERR_HTTPD_ALLOC_MEMFailed to dynamically allocate memory for resource.
ESP_ERR_HTTPD_TASKFailed to launch server task/thread.
ESP_FAILOther error occurred.

HTTP server task stack size

ESP32WebCam allocates 8KB of stack when it starts the HTTP server task. This stack size is larger than the size allocated by the default HTTPD_DEFAULT_CONFIG in ESP-IDF. This is to include the stack consumed by the file system of the SD card triggered by the timer shot. This stack size can be changed as needed, and the default value is defined in the ESP32Cam.h header file as ESP32CAM_TIMERTASK_STACKSIZE.

stopCameraServer

void stopCameraServer(void)

Stop an HTTP server task and free resources.

ESP32WebCam Endpoint Interfaces

ESP32WebCam has endpoint interfaces for simple manipulation of image sensors over the network via an internally launched HTTP server, which follows the traditional HTTP request and response, not WebAPI or REST. It supports the HTTP GET1 method and will be available after the HTTP server is started by the ESP32WebCam::startCameraServer function.

If you are using Visual Studio Code as your build system for Arduino sketch, you can easily experiment with the ESP32WebCam endpoint interface using the VSCode extension. REST Client is an excellent VSCode extension that allows you to send HTTP requests directly from within the editor. The following screenshot shows the result of sending an HTTP request directly to the capture endpoint of ESP32WebCam using the REST Client on a VSCode with the PlatformIO build system.

Captured by REST-Client

The top left editor pane is the sketch code described above, and the bottom pane is the serial monitor output of the sketch. The pane between the top and bottom panes is the REST Client. Run the sketch, and when the serial monitor shows a message that ESP32Cam has started the HTTP server, use the REST client to send an HTTP GET request as GET http://{HOST}:{PORT}/_capture (In the screenshot above, the request is sent to http://192.168.1.19:3000/_capture) to the capture endpoint.2 You will see the response of the image captured by ESP32-CAM in the right pane.

The default settings for the endpoint interface provided by ESP32WebCam are as follows:

Endpoint Default path Function Default value defined in ESP32WebCam.h
Capture /_capture Responds as a captured image ESP32CAM_DEFAULT_PATH_CAPTURE
Prompt /_prompt Save and load the captured image, Save the sensor settings ESP32CAM_DEFAULT_PATH_PROMPT
Stream /_stream Stream image ESP32CAM_DEFAULT_PATH_STREAM

Capture

GET http://{HOST}:{PORT}{PATH}

The capture endpoint responds captured image with the image/jpeg mime format.

Parameters
HOSTHost address of ESP32-CAM.
PORTPort number of HTTP server listening on. Default port number is 3000 which defined by ESP32CAM_DEFAULT_HTTPPORT macro directive in ESP32WebCam.h header file.
PATHA path for the capture endpoint.
Response code
200Content body contains captured image data.

Prompt

GET http://{HOST}:{PORT}{PATH}?{QUERY}

You can use the prompt endpoint to save the captured image to the SD card at that moment or in a timer cycle, save the sensor settings, and load them into the flash memory built into the ESP32 module. The instructions for the prompt action performed by ESP32WebCam are specified as the query string with "key=value" form for the parameters of the GET request.

Parameters
HOSTHost address of ESP32-CAM.
PORTPort number of HTTP server listening on. Default port number is 3000 which defined by ESP32CAM_DEFAULT_HTTPPORT macro directive in ESP32WebCam.h header file.
PATHA path for the capture endpoint.
QUERYThe QUERY that Prompt can accept are different for each feature. The query formats that can be specified and the corresponding functions are shown below.
Response code
202Request accepted.
400Query string has syntax error, or Fatal error occurred. Content body has detailed error code.

The following features are currently supported by the prompt endpoint:

Specifying by query string Function Behavior
mf=oneshot[&fs={sd|mmc}][&filename=<FILENAME>] One-shot Take a one-shot image and save it to the SD card.
mf=timershot[&fs={sd|mmc}][&filename=<FILENAME>][&period=<INTERVAL>] Timer-shot Repeatedly takes a one-shot image at specified an INTERVAL of seconds and saves it to the SD card.
mf=distimer Disable timer Suspend timer for Timer-shot
mf=entimer Enable timer Resume timer for Timer-shot
mf=load Load settings Load the image sensor settings from the NVS
mf=save Save settings Save the image sensor settings to the NVS

The query formats that can be specified and their corresponding functions are described below.

Functions: Specifies with the mf= query.
oneshotCapture an image at the requested timing and save them to the SD card. Species either sd or mmc for the fs argument. If the fs argument does not exist, mmc is assumed.
Saves the captured image with the file name specified by the filename argument; if the filename argument does not exist, it assumes a file name consisting of a prefix and a timestamp. In that case, the fixed string defined by the ESP32CAM_GLOBAL_IDENTIFIER macro directive in ESP32Cam.h is used as the prefix.
timershotRepeatedly takes a one-shot image at specified an INTERVAL of seconds with period argument and saves it to the SD card. Species either sd or mmc for the fs argument. If the fs argument does not exist, mmc is assumed.
Saves the captured image to a file whose name consists of the prefix and timestamp suffix specified by the filename argument. If the filename argument does not exist, the prefix will be assumed a fixed string defined by the ESP32CAM_GLOBAL_IDENTIFIER macro directive in ESP32Cam.h header file.
distimerTemporarily stops the timer for the timershot. This can be resumed with entimer.
entimerResumes a timer-shot that was temporarily stopped by distimer.
loadLoad the image sensor settings from NVS.
saveSave the image sensor settings to NVS.

Whether it is SD or MMC depends on the hardware

The ESP32 Arduino SD library supports two types of SD cards with different interfaces. Which type of SD card is used depends on the ESP32 module and needs to be chosen appropriately. In the case of the Ai-Thinker ESP32-CAM 3, the ESP32 is wired to the SD slot with each HS2 signal. Hence, We can see from the schematic that it is using MMC.

Stream

GET http://{HOST}:{PORT}{PATH}

The stream endpoint responds captured image with the image/jpeg mime format with multipart/x-mixed-replace HTTP header.

Parameters
HOSTHost address of ESP32-CAM.
PORTPort number of HTTP server listening on. Default port number is 3000 which defined by ESP32CAM_DEFAULT_HTTPPORT macro directive in ESP32WebCam.h header file.
PATHA path for the stream endpoint.
Response code
200Content body contains captured image data with multipart boundary.

ESP32Cam Class APIs

Constructor

ESP32Cam()
ESP32Cam(const CameraId model)

Instantiate ESP32Cam. The image sensor is not initialized just by calling the constructor. To initialize the sensor, you need to call the init function.

Parameters
modelSpecifies the model of the onboard image sensor. The image sensor models that can be specified are as follows:

  • ESP32Cam::CAMERA_MODEL_WROVER_KIT
  • ESP32Cam::CAMERA_MODEL_ESP_EYE
  • ESP32Cam::CAMERA_MODEL_M5STACK_NO_PSRAM
  • ESP32Cam::CAMERA_MODEL_M5STACK_PSRAM
  • ESP32Cam::CAMERA_MODEL_M5STACK_V2_PSRAM
  • ESP32Cam::CAMERA_MODEL_M5STACK_WIDE
  • ESP32Cam::CAMERA_MODEL_M5STACK_ESP32CAM
  • ESP32Cam::CAMERA_MODEL_M5STACK_UNITCAM
  • ESP32Cam::CAMERA_MODEL_AI_THINKER
  • ESP32Cam::CAMERA_MODEL_TTGO_T_JOURNAL

getStatus

esp_err_t getStatus(camera_status_t* status)

Get the camera_status_t data structure from the image sensor.

Parameters
statusPointer to the buffer to store the acquired camera_status_t structure.
Return value
ESP_OKcamera_status_t is read successfully.
ESP_FAILImage sensor is not initialized.

getFramesize

framesize_t getFramesize(void)

Get the current configuration of the image sensor frame size.

Return value
framesize_tThe framesize_t enumeration value.

getFrameHeight

uint16_t  getFrameHeight(void)

Returns the height of the current image frame in pixels.

Return value
uint16_tHeight of the image frame.

getFrameWidth

uint16_t  getFrameWidth(void)

Returns the width of the current image frame in pixels.

Return value
uint16_tWidth of the image frame.

init

esp_err_t init(void)
esp_err_t init(const CameraId model)

Initialize the image sensor.

Parameters
modelSpecifies the model of the onboard image sensor. The image sensor models that can be specified are as follows:

  • ESP32Cam::CAMERA_MODEL_WROVER_KIT
  • ESP32Cam::CAMERA_MODEL_ESP_EYE
  • ESP32Cam::CAMERA_MODEL_M5STACK_NO_PSRAM
  • ESP32Cam::CAMERA_MODEL_M5STACK_PSRAM
  • ESP32Cam::CAMERA_MODEL_M5STACK_V2_PSRAM
  • ESP32Cam::CAMERA_MODEL_M5STACK_WIDE
  • ESP32Cam::CAMERA_MODEL_M5STACK_ESP32CAM
  • ESP32Cam::CAMERA_MODEL_M5STACK_UNITCAM
  • ESP32Cam::CAMERA_MODEL_AI_THINKER
  • ESP32Cam::CAMERA_MODEL_TTGO_T_JOURNAL

loadSettings

esp_err_t loadSettings(const char* key = nullptr)

Load the image sensor settings from NVS in the ESP32 flash.

Parameters
keySpecifies NVS key name. If key is nullptr or not specified, default key which defined by ESP32CAM_NVS_KEYNAME macro directive in ESP32Cam.h header file will be assumed.
Return value
ESP_OKThe image sensor settings has been successfully loaded.

saveSettings

esp_err_t saveSettings(const char* key = nullptr)

Save the current image sensor settings to NVS in the ESP32 flash.

Parameters
keySpecifies NVS key name. If key is nullptr or not specified, default key which defined by ESP32CAM_NVS_KEYNAME macro directive in ESP32Cam.h header file will be assumed.
Return value
ESP_OKThe image sensor settings has been successfully saved.

setStatus

esp_err_t setStatus(const camera_status_t& status)

Set the content of camera_status_t structure to the image sensor.

Parameters
statusReference of the camera_status_t structure.
Return value
ESP_OKcamera_status_t has been set successfully.
ESP_FAILImage sensor is not initialized.

setFramesize

esp_err_t setFramesize(const framesize_t framesize)

Set the image sensor frame size.

Parameters
framesizeThe framesize_t enumeration value to be set.
Return value
ESP_OKFramesize has been set.
ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZEImage sensor is not initialized, the framesize is invalid, or the pixel format is not JPEG.

setImageFormat

esp_err_t setImageFormat(const pixformat_t format)

Set the image format.

Parameters
formatThe pixformat_t enumeration value to be set.
Return value
ESP_OKFormat has been set.
ESP_ERR_CAMERA_FAILED_TO_SET_OUT_FORMATSpecified format is invalid.
ESP_FAILImage sensor is not initialized.

oneShot

esp_err_t oneShot(fs::SDFS& sd, const char* filename = nullptr)
esp_err_t oneShot(fs::SDMMCFS& mmc, const char* filename = nullptr)

Take a one-shot image and save it to the SD card or MMC. This function writes to a file compliant with the ESP32 Arduino SD library. Either fs::SDFS or fs::SDMMCFS can be specified for the file system that represents sd or mmc.

Parameters
sdSpecifies the SD file system when the SD card is wired with SPI interface. In usually, you can use a SD variable that is instantiated and exported globally by the ESP32 Arduino core.
mmcSpecifies the SD_MMC file system when the SD card is wired with HS2 interface. In usually, you can use a SD_MMC variable that is instantiated and exported globally by the ESP32 Arduino core.
filenameSpecifies the file name when saving the captured image to the SD card. if the filename does not exist, it assumes a file name consisting of a prefix and a timestamp. In that case, the fixed string defined by the ESP32CAM_GLOBAL_IDENTIFIER macro directive in ESP32Cam.h is used as the prefix.
Return value
ESP_OKFormat has been set.
ESP_ERR_NOT_FOUNDSD card is not mounted.
ESP_FAILOther error occurred.

timerShot

esp_err_t timerShot(const unsigned long period, fs::SDFS& sd, const char* filePrefix = nullptr)
esp_err_t timerShot(const unsigned long period, fs::SDMMCFS& mmc, const char* filePrefix = nullptr)

Repeatedly takes a one-shot image at specified an interval of seconds with period parameter and saves it to the SD card or MMC. This function writes to a file compliant with the ESP32 Arduino SD library. Either fs::SDFS or fs::SDMMCFS can be specified for the file system that represents sd or mmc.

Parameters
periodSpecifies the shooting interval time in second unit.
sdSpecifies the SD file system when the SD card is wired with SPI interface. In usually, you can use a SD variable that is instantiated and exported globally by the ESP32 Arduino core.
mmcSpecifies the SD_MMC file system when the SD card is wired with HS2 interface. In usually, you can use a SD_MMC variable that is instantiated and exported globally by the ESP32 Arduino core.
filePrefixSpecifies the prefix of file name when saving the captured image to the SD card. This function saves files each time whose name consists of the prefix and timestamp suffix specified by the filePrefix parameter. If the filePrefix does not exist, it assumes a fixed string defined by the ESP32CAM_GLOBAL_IDENTIFIER macro directive in ESP32Cam.h for the prefix.
Return value
ESP_OKFormat has been set.
ESP_ERR_NOT_FOUNDSD card is not mounted.
ESP_FAILOther error occurred.

disableTimerShot

void disableTimerShot(void)

Temporarily stops the timerShot. To restart it, call enableTimerShot.

enableTimerShot

void enableTimerShot(void)

Restarts the timerShot that was temporarily stopped by disableTimerShot.

deq

void deq(void)

Release a semaphore.

enq

portBASE_TYPE enq(TickType_t ms)

Take a semaphore to prevent resource collisions with the image sensor. ESP32Cam uses a semaphore for each of oneShot and timerShot to prevent image sensor resources from colliding while performing each other's tasks. The enq function reserves a semaphore to wait for a subsequent oneShot or timerShot task.

Parameters
msSpecifies the maximum waiting time in milliseconds for a semaphore to be released. If portMAX_DELAY is specified, it will wait indefinitely for the semaphore to be released.
Return value
pdTRUESemaphore was reserved.
!pdTRUESemaphore was not released within the specified ms time.

WebCamServer like as CameraWebServer

The WebCamServer.ino sketch combines AutoConnectAux's custom web pages with native HTML pages. The image viewer is placed on the native HTML page using the img tag, and the slide-in navigation panel is incorporated using CSS. AutoConnect is only directly involved in the image sensor setup page, which is JSON defined in CAMERA_SETUP_PAGE. The setSensor function in the sketch is a handler for a custom web page for CAMERA_SETUP_PAGE, and its role is to communicate the sensor settings to the ESP32 camera driver via ESP32Cam.

webcamview_open webcamview_set

In the WebCamServer.ino sketch, most of the front-end is taken care of by the UI, which is a web page written in HTML. The slide-in menu allows navigation to stream images, capture still images, save a one-shot image to the SD card, and the timer-shot. Image streaming and capture are achieved by giving the URLs of the Stream endpoint and Capture endpoint in the src attribute of the img tag in the HTML using JavaScript DOM interface.

<body>
  <li id="onair" onclick="stream(!isStreaming())">Start Streaming</li>
  <img id="img-frame" />
</body>
const onAir = document.getElementById('onair');
const imgFrame = document.getElementById('img-frame');

function isStreaming() {
  status.innerText = null;
  return onAir.innerText.startsWith("Stop");
}

function stream(onOff) {
  if (onOff && !isStreaming()) {
    window.stop();
    imgFrame.src = streamUrl;
    onAir.innerText = onAir.innerText.replace("Start", "Stop");
    content.focus();
  }
  else if (!onOff && isStreaming()) {
    window.stop();
    imgFrame.src = noa;
    onAir.innerText = onAir.innerText.replace("Stop", "Start");
  }
}

Also, One-shot and timer-shot also use JavaScript Fetch API to send a query string compliant with each function to the Prompt endpoint.

<li id="oneshot" onclick="oneshot()">One-Shot</li>
<li><label for="period">Period [s]</label><input type="number" name="peirod" id="period" min="1" value="1" pattern="\d*"/></li>
<li><input type="button" value="ARM" onclick="arm()"/></li>
var promptUrl = endpoint(host, promptPath, port);

function endpoint(host, path, port) {
  var url = new URL(path, "http://" + host);
  url.port = port;
  return url;
}

function prompt(url) {
  var res;
  stream(false);
  fetch(url)
    .then(response => {
      res = "status:" + response.status + " ";
      if (!response.ok) {
        return response.text().then(text => {
          throw new Error(text);
        });
      }
      else {
        status.style.color = '#297acc';
        status.innerText = res + response.statusText;
      }
    })
    .catch(err => {
      var desc = err.message;
      if (err.message.indexOf("0x0103", 1) > 0) {
        desc = "SD not mounted";
      }
      if (err.message.indexOf("0x0105", 1) > 0) {
        desc = "SD open failed";
      }
      status.style.color = '#cc2929';
      status.innerText = res + desc;
    });
}

function oneshot() {
  promptUrl.search = "?mf=oneshot&fs=mmc";
  prompt(promptUrl);
}

function arm() {
  promptUrl.search = "?mf=timershot&fs=mmc&period=" + document.getElementById('period').value;
  prompt(promptUrl);
}

The following diagram shows the program structure of the WebCamServer.ino sketch. Its structure is somewhat more complex than the simple sketch presented at the beginning of this chapter because of the native HTML intervening.

WebCamServer structure


  1. ESP32WebCam endpoint interface supports only HTTP GET method, it cannot respond to other HTTP methods such as POST. 

  2. Do not use the REST Client to send requests to the stream endpoints, the REST Client does not fully support multipart/x-mixed-replace mime. 

  3. When using MMC on AI-Thinker ES32-CAM, the LED flash on the module blinks every time the SD is accessed, because the HS2 DATA1 signal is wired to the driver transistor of the LED FLASH. I can't envision why HS2 DATA1 signal was chosen to drive the LED.