DIY Projects

5 tips for ESP32-CAM. Fixed IP address. AP mode. Image rotation 90°. Automatic recovery WiFi connection. HTML code storage

esp32-cam 5 tips wifi connexion html ip

The CameraWebServer sample for the ESP32-CAM delivered with the ESP32 library is great for testing and discovering the functionality of the camera. The code is quite difficult to understand (especially when starting out) and especially to modify when you want to develop a small DIY surveillance camera. I am offering you for this new project an ultra-simplified version of the code that integrates the main functions that you requested in the comments, namely how to assign a fixed IP address to the ESP32-CAM, how to start in AP mode (Access Point ), how to restart automatically in case of loss of WiFi connection or unavailability of the network, how to rotate the image by 90°

 

In this project, I offer you an ultra-simplified version of the code and the main functions requested in the comments.

You can go directly to the paragraph by following the link

  1. How to assign (fix) the IP address of the ESP32-CAM?
  2. How to start the ESP32-CAM in Access Point (AP) mode?
  3. How to make an automatic reconnection in case of loss or unavailability of the WiFi network?
  4. Simplified code with an HTML interface
  5. How to store the HTML code of the interface as a long string on the Flash memory of the ESP32
  6. How to rotate the image 90°?
  7. Complete code of the ESP32-CAM project

The code was developed with a generic AI Thinker type ESP32-CAM board. However, it should work perfectly identically on M5Stack and TTGO cards in particular.

For a video surveillance application, there are OV2640 modules with a fisheye type optic that can reach up to 160° (instead of 78° as standard) which is better suited.

Note concerning the WiFiManager and esp_http_server.h libraries

The ideal would be to be able to enter the parameters of connection to the WiFi network when commissioning the ESP32-CAM camera.

A version of the WiFiManager library is under development and is available for the ESP32.

Unfortunately the WiFiManager library conflicts with the esp_http_server.h library of the ESP-IDF SDK used in this project.

1. Assign (set) the IP address of the ESP32-CAM

The ESP32-CAM is automatically assigned an IP address when it connects to the WiFi network for the first time. Most routers / internet boxes keep this address on the one hand for optimization, on the other hand to make our life easier. In case of failure or replacement of equipment (router, internet box), the IP address will change, which can be a problem for a surveillance camera!

ESP32-CAM is first and foremost an ESP32 development board. The camera module uses several pins of the ESP32 to send the video stream. The code is absolutely identical to what we have already done in this tutorial.

To assign the IP address of the ESP32-CAM module, all you have to do is define the connection parameters before calling the WiFi.begin() method. Here is a sample configuration. The ESP32-CAM will have the fixed IP address 192.168.1.80 on the local network. The internet box (or the router is at the address 192.168.1.1). All you have to do is adapt the parameters to your network configuration.

#define USE_FIXED_IP false
// The IP address you want to assign to the ESP32-CAM. Be careful not to use an existing address!
IPAddress local_IP(192, 168, 1, 80);
// Address of the router or internet box
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 0, 0);
IPAddress primaryDNS(8, 8, 8, 8);   //optional
IPAddress secondaryDNS(8, 8, 4, 4); //optional

To assign the fixed IP address, it will suffice to pass constant USE_FIXED_IP to true in the source code of the project.

Start the ESP32-CAM in Access Point (AP) mode

AP mode for Access Point allows you to connect directly to the ESP32-CAM. The camera is not connected to the local WiFi network, nor to the internet. It is in a way a private mode of operation.

There is almost nothing to do to activate AP mode. To connect to the WiFi network, we use the WiFi.begin () method . To start the ESP32 in AP mode, just run the WiFi.softAP (ap_ssid, ap_password) method instead. The method parameters are as follows:

  • ap_ssid   network name, 63 characters max.
  • ap_password password with at least 8 characters. NULL for free access. not recommended !!!
  • channel (optional) Wi-Fi channel, between 1 and 13
  • ssid_hidden (optional) 0 = broadcast network name, 1 = hide network name SSID
  • max_connection maximum number of clients simultaneously connected to the ESP32-CAM. 4 at most.

To activate AP mode, all you have to do is set the constant AP_MODE to true in the project code

Automatic re-connection in case of loss or unavailability of the WiFi network

Recurring problem with the ESP32-CAM, automatic re-connection in case of loss of connection to the WiFi network. It is essential to have an automatic reconnection function especially when using the ESP32-CAM as a surveillance camera.

Rather than restarting the ESP32 using the ESP.restart () method, I recommend instead putting the ESP32 in deep sleep for a period of time. Unlike the ESP8266, there is nothing to provide on the hardware side to activate the deep-sleep mode of the ESP32. 2 lines of code are enough!

void restartESP32Cam()
{
  esp_sleep_enable_timer_wakeup(uS_TO_S_FACTOR * TIME_TO_SLEEP);
  esp_deep_sleep_start();
}

You will find a lot of other information on sleeping ESP32 modules (and de facto ESP32-CAM) by reading this detailed article.

Then, all you have to do is count the number of failed connection attempts at startup and call the restartESP32Cam method when a threshold is exceeded.

WiFi.begin(ssid, password);
while ( WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
      wifi_counter++;

      if ( wifi_counter > wifi_try ) {
        restartESP32Cam();
      }
}

Once started, it will suffice to test at each passage through the loop that the connection is still available and to call standby if this is not the case.

void loop() {
  if ( WiFi.status() != WL_CONNECTED ) {
    // We just lost the WiFi connection
    restartESP32Cam();
  }

  delay(10);
}

And there you have it, now the ESP32-CAM knows how to reconnect automatically in the event of loss of connection to the WiFi network. If your ESP32-CAM is running on battery, it will not be drained. It will just be necessary to decide the time during which the ESP32-CAM is put to sleep (deep-sleep). The ideal would be to have a backup system based on LoRa in order to detect a loss of WiFi connection. This is the principle used in particular by Verisure, which has a Sigfox channel for its alarm system in the event of a power cut.

Simplified HTML interface code

You’ve probably seen that the HTML interface code for the CameraWebServer sample is compressed in GZIP format in the camera_index.h file.

Here is a small excerpt out of curiosity

//File: index_ov2640.html.gz, Size: 4316
#define index_ov2640_html_gz_len 4316
const uint8_t index_ov2640_html_gz[] = {
 0x1F, 0x8B, 0x08, 0x08, 0x50, 0x5C, 0xAE, 0x5C, 0x00, 0x03, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F,
 0x6F, 0x76, 0x32, 0x36, 0x34, 0x30, 0x2E, 0x68, 0x74, 0x6D, 0x6C, 0x00, 0xE5, 0x5D, 0x7B, 0x73,
 0xD3, 0xC6, 0x16, 0xFF, 0x9F, 0x4F, 0x21, 0x04, 0x25, 0xF6, 0x34, 0x76, 0x6C, 0xC7, 0x84, 0xE0,
....
}

This is a great idea because it is not necessary to upload separately the HTML interface that we normally have to place in the data folder of the Arduino project.

Here are two articles that explain how to embed HTML, CSS, JS files into an ESP32 or ESP8266 project (it works the same).

The problem when you start is that you cannot modify this file, or even be inspired by it to develop your own interface.

Here is an ultra-simplified version that you can use in your projects. It streams MJPEG video stream smoothly to any browser. You will also find two buttons that allow you to rotate the image left or right 90° each time.

We would try to use a string to store the HTML code of the page but it is very quickly difficult to manage and write. Take a look at this HTML code snippet for example. We must add at the end of each line the code \ n to wrap around and put in quotes each line … debugging hours!

const char http_index_hml[] = "<!doctype html>\n"
"<html>\n"
"    <head>\n"
"        <meta charset=\"utf-8\">\n"
"        <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n"
...

Store the HTML code of the interface in a PROGMEM R variable “=== () ===”

Instead, we will use the C++ R operator which allows you to store any string. The R stands for “Treat anything between these delimiters as a raw string”. Everything is explained in detail here.

The HTML interface code will therefore be stored between two delimiters like this.

R"delimiter(html code of the page)delimiter"

The string between the two delimiters can be any length and contain any character. What is important is to have the same delimiter before and after the string .

As the HTML code can be very long, it is best to put it in flash memory rather than SRAM, where it would normally go. We can do this using the PROGMEM keyword which is a variable modifier (documentation).

Here is the source code for the easier to handle HTML page. You can even use an HTML code generator and then paste it into your code to go even faster!

const char index_html[] PROGMEM = R"=====(
<!DOCTYPE HTML><html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    .row {
      display: flex;
    }
    .leftcol {
      flex: 30%;
    }
    .rightcol {
      flex: 70%;
    }
  </style>
</head>
<body>
  <div class="row">
    <div class="leftcol">
      <h2>ESP32-CAM Stream Server</h2>
      <p>
        <h4>Rotate Image</h4> 
        <button onclick="rotateLeft()">«</button>
        <button onclick="rotateRight()">»</button>
      </p>
      <p>Use only HTML + CSS</p>
    </div>
    <div class="rightcol">
      <img id="stream" style="width:400px" src='https://%s/stream'/>
    </div>
  </div>
</body>
<script>
  var deg = 0;
  function rotateLeft() {
    deg -= 90;
    console.log("Rotate image to left");
    document.getElementById("stream").style.transform = 'rotate(' + deg + 'deg)';
  }function rotateRight() {
    deg += 90;
    console.log("Rotate image to right");
    document.getElementById("stream").style.transform = 'rotate(' + deg + 'deg)';
  }
</script>
</html>)=====";

Here are some articles to help you design your HTML interfaces.

How to rotate the image 90°

There is no native function to directly rotate the image. We simply have the set_vflip and set_hmirror methods which respectively allow to invert the image vertically (vflip) or horizontally (hmirror).

The only way to rotate the image and therefore to predict the angle directly at the level of the assembly or to make a “software” rotation.

On an internet browser, it is very easy, you can be inspired by the method on a home automation software. It suffices to do a rotate type transformation on the image. You simply indicate the desired angle in degrees. Everything happens on the browser side, there is no interaction with the Arduino code of the ESP32 project.

document.getElementById("stream").style.transform = 'rotate(' + deg + 'deg)';

Complete project code

Here is the full source code for the example which you can also grab directly from GitHub . The project can be compiled using the Arduino IDE or PlatformIO.

Read this article to get started with your ESP32-CAM and PlatformIO project

The source code can be used as a basis for the development of your own surveillance camera for example. To compile with the Arduino IDE, rename the main.cpp file to main.ino for example.

The code base is identical to the CameraWebServer example. It uses the standard esp_http_server.h library of the ESP-IDF SDK. Two ports are used. Port 80 to manage the interface with the user. Port 81 on which the video stream is sent in MJPEG format.

  • main.cpp
  • camera_pin.h
  • platformio.ini
/* Five ESP32-CAM tips. Simplified version of HTML and C ++ code
   Fixed IP address. AP mode. Image rotation 90°. Automatic recovery WiFi connection. HTML code storage
  
   5 astuces pour ESP32-CAM. Version simplifiée du code HTML et C++ 
   Adresse IP fixe. Mode AP. Rotation image 90°. Récupération automatique connexion WiFi. stockage du code HTML
  
   Licence : see licence file
 */
#include <Arduino.h>
#include "esp_camera.h"
#include <WiFi.h>
#include "esp_http_server.h"

// Select camera model
//#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_ESP_EYE
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE
#define CAMERA_MODEL_AI_THINKER

#include "camera_pins.h"

/**********************************************************************/
/*                         PARAMETRES WIFI                            */
/**********************************************************************/
const char* ssid = "enter_your_ssid";
const char* password = "enter_your_password";
// Activate AP mode AP (Access point). User need to connect directly to ESP32 wifi network to access video stream
#define AP_MODE false
const char* ap_ssid = "esp32-cam";
const char * ap_password = "12345678"; // Mini. 8 
char / ************************************************ *********************** / 
/ * USE FIXED IP * / 
/ ********** *************************************************** ********** / 
#define USE_FIXED_IP true 
// Set your Static IP address. Do not use existing IP address (other computer, TV box, printer, smartphone) 
// The IP address you want to assign to the ESP32-CAM. Be careful not to use an existing address! 
IPAddress local_IP (192, 168, 1, 80); 
// Set your Gateway IP address 
// Address of the router or internet box
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 0, 0);
IPAddress primaryDNS(8, 8, 8, 8);   //optional
IPAddress secondaryDNS(8, 8, 4, 4); //optional
/**********************************************************************/
/*  PARAMETRE DE REDEMARRAGE SI LE RESEAU WIFI N'EST PAS DISPONIBLE   */
/**********************************************************************/
int wifi_counter = 0;
#define wifi_try 10
#define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  30          /* Time ESP32 will go to sleep (in seconds) */
/**********************************************************************/
/*                             PROTOTYPES                             */
/**********************************************************************/
void restartESP32Cam();
void startCameraServer();
/**********************************************************************/
/*                WEB SERVER + STREAM SERVER                          */
/*                SERVEUR WEB + SERVEUR VIDEO                         */
/**********************************************************************/
#define PART_BOUNDARY "123456789000000000000987654321"
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";

httpd_handle_t stream_httpd = NULL;
httpd_handle_t camera_httpd = NULL;

// Stream sever port number
// Numéro du port du server vidéo
int port_number; 

const char index_html[] PROGMEM = R"=====(
<!DOCTYPE HTML><html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    .row {
      display: flex;
    }
    .leftcol {
      flex: 30%;
    }
    .rightcol {
      flex: 70%;
    }
    .button {
      width: 60px;
      height: 40px;
      color: white;
      font-size: 22px;
      background-color: #1acc59;
      border-color: transparent;
      border-radius: 8px
    }
  </style>
</head>
<body>
    <h2>ESP32-CAM Stream Server</h2>
    <div style="width:400px ; height:450px">
      <img id="stream" style="margin-top: 50px; width:400px" src="https://%s/stream"></img>
    </div>
    <div>
        <h4>Rotate Image</h4> 
        <button class="button" onclick="rotateLeft()">«</button>
        <button class="button" onclick="rotateRight()">»</button>
    </div>    
</body>
<script>
  var deg = 0;
  function rotateLeft() {
    deg -= 90;
    if ( deg <0 ) deg = 360;
    console.log("Rotate image to left");
    document.getElementById("stream").style.transform = 'rotate(' + deg + 'deg)';
  }function rotateRight() {
    deg += 90;
    if ( deg > 360 ) deg = 0;
    console.log("Rotate image to right");
    document.getElementById("stream").style.transform = 'rotate(' + deg + 'deg)';
  }
</script>
</html>)=====";
/*********************************************/
/*        GENERATE MJPEG STREAM              */
/*        GENERE LE FLUX VIDEO MJPEG         */
/*********************************************/
static esp_err_t stream_handler(httpd_req_t *req) {
  camera_fb_t * fb = NULL;
  esp_err_t res = ESP_OK;
  size_t _jpg_buf_len = 0;
  uint8_t * _jpg_buf = NULL;
  char * part_buf[64];

  static int64_t last_frame = 0;
  if (!last_frame) {
    last_frame = esp_timer_get_time();
  }

  res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
  if (res != ESP_OK) {
    return res;
  }
  httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");

  while (true) {
    fb = esp_camera_fb_get();
    if (!fb) {
      // Echec de la capture de camera
      Serial.println("JPEG capture failed"); 
      res = ESP_FAIL;
    } else {
      if (fb->width > 400) {
        if (fb->format != PIXFORMAT_JPEG) {
          bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
          esp_camera_fb_return(fb);
          fb = NULL;
          if (!jpeg_converted) {
            // Echec de la compression JPEG
            Serial.println("JPEG compression failed"); 
            res = ESP_FAIL;
          }
        } else {
          _jpg_buf_len = fb->len;
          _jpg_buf = fb->buf;
        }
      }
    }
    if (res == ESP_OK) {
      size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
      res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
    }
    if (res == ESP_OK) {
      res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
    }
    if (res == ESP_OK) {
      res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
    }
    if (fb) {
      esp_camera_fb_return(fb);
      fb = NULL;
      _jpg_buf = NULL;
    } else if (_jpg_buf) {
      free(_jpg_buf);
      _jpg_buf = NULL;
    }
    if (res != ESP_OK) {
      break;
    }
  }
  last_frame = 0;
  return res;
}

/*******************************************************/
/*         HTML PAGE BUILDER                           */
/*******************************************************/
static esp_err_t web_handler(httpd_req_t *req) {
  httpd_resp_set_type(req, "text/html");
  httpd_resp_set_hdr(req, "Content-Encoding", "identity");

  int indexhtmlsize = sizeof(index_html) + 50;
  char indexpage[indexhtmlsize] = "";
  //strcat(indexpage, index_html);
  char streamip[20] = "";
  
  if ( AP_MODE ) {
    // In AP Mode, IP is always 192.168.4.1
    // In AP mode (direct connection to ESP32-CAM), the IP is always 192.168.4.1 
    sprintf (streamip, "192.168.4.1:%d", port_number); 
  } else { 
    sprintf (streamip, "% d.% d.% d.% d:% d", WiFi.localIP () [0], WiFi.localIP () [1], WiFi.localIP () [2] , WiFi.localIP () [3], port_number); 
  } 
  // Replace stream url inside HTML page code 
  // Replaces the address of the video stream in the code of the HTML page 
  sprintf (indexpage, index_html, streamip); 
  int pagezize = strlen (indexpage); 

  // Return HTML page source code 
  // Return the source code of the HTML page 
  return httpd_resp_send (req, (const char *) indexpage, pagezize); 
}

/***********************************************************/
/*        START WEB SERVER AND VIDEO STREAM                */
/***********************************************************/
void startCameraServer() {
  httpd_config_t config = HTTPD_DEFAULT_CONFIG();

  httpd_uri_t index_uri = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = web_handler,
    .user_ctx  = NULL
  };

  httpd_uri_t stream_uri = {
    .uri       = "/stream",
    .method    = HTTP_GET,
    .handler   = stream_handler,
    .user_ctx  = NULL
  };

  // Démarre le serveur web de l'interface HTML accessible depuis le navigateur internet
  Serial.printf("Web server started on port: '%d'\n", config.server_port);
  if (httpd_start(&camera_httpd, &config) == ESP_OK) {
    httpd_register_uri_handler(camera_httpd, &index_uri);
  }

  config.server_port += 1;
  config.ctrl_port += 1;
  // Démarre le flux vidéo
  Serial.printf("Stream server started on port: '%d'\n", config.server_port);
  if (httpd_start(&stream_httpd, &config) == ESP_OK) {
    httpd_register_uri_handler(stream_httpd, &stream_uri);
  }

  port_number = config.server_port;
}


void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println();
  
  // Configure camera Pins
  // Configure les broches de la caméra
  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;
  
  // Init with high specs to pre-allocate larger buffers
  /* ESP32-CAM AVAILABLE RESOLUTIONS
    FRAMESIZE_QQVGA,    // 160x120
    FRAMESIZE_QQVGA2,   // 128x160
    FRAMESIZE_QCIF,     // 176x144
    FRAMESIZE_HQVGA,    // 240x176
    FRAMESIZE_QVGA,     // 320x240
    FRAMESIZE_CIF,      // 400x296
    FRAMESIZE_VGA,      // 640x480
    FRAMESIZE_SVGA,     // 800x600
    FRAMESIZE_XGA,      // 1024x768
    FRAMESIZE_SXGA,     // 1280x1024
    FRAMESIZE_UXGA,     // 1600x1200
    FRAMESIZE_QXGA,     // 2048*1536
  */
  if(psramFound()){
    config.frame_size = FRAMESIZE_UXGA; //FRAMESIZE_UXGA; // 1600x1200
    config.jpeg_quality = 10;
    config.fb_count = 1; // Si > 1, active le bus I2S
  } else {
    config.frame_size = FRAMESIZE_SVGA; // 800x600 
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }
#if defined(CAMERA_MODEL_ESP_EYE)
  pinMode(13, INPUT_PULLUP);
  pinMode(14, INPUT_PULLUP);
#endif

  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  if ( AP_MODE ) {
    // In AP mode, we connect directly to the WiFi network of the ESP32 at the address http://192.168.4.1
    /* ACCESS POINT PARAMETERS
      ap_ssid (defined earlier): maximum of 63 characters
      ap_password (defined earlier): minimum of 8 characters; set to NULL if you want the access point to be open
      channel: Wi-Fi channel, number between 1 to 13
      ssid_hidden: (0 = broadcast SSID, 1 = hide SSID) 
      max_connection: maximum simultaneous connected clients, max. 4 
      -------- 
      ap_ssid (already defined): 63 characters max. 
      ap_password (already defint): at least 8 characters. NULL for free access. not recommended !!! 
      channel: Wi-Fi channel, number between 1 and 13 
      ssid_hidden: 0 = broadcast the network name, 1 = hide the network name SSID 
      max_connection: maximum number of clients connected simultaneously to the ESP32-CAM. 4 max. 
    * / 
    WiFi.softAP (ap_ssid, ap_password); 
  } else {   
    if (USE_FIXED_IP) { 
      if (! WiFi.config (local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
        Serial.println("STA Failed to configure");
      }
    }
    WiFi.begin(ssid, password);
    while ( WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
      wifi_counter++;

      if ( wifi_counter > wifi_try ) {
        restartESP32Cam();
      }
    }
    Serial.println("");
    Serial.println("WiFi connected");
  }

  // The camera is ready, open your browser at the following address
  Serial.print("Camera Ready! Open your browser at 'http://");
  
  Serial.print(WiFi.localIP());
  Serial.println("");
  
  long logrssi = 0 ;
  for (size_t i = 0; i < 10; i++)
  {
    long rssi = WiFi.RSSI();
    logrssi = logrssi + rssi;
    Serial.printf("measured rssi = %ddb \n", WiFi.RSSI());
    delay(200);
  }
  
  Serial.printf("Mean rssi = %0.1d \n", logrssi / 10);
  
  
  //Serial.println(rssi);

  // Start web server and MJPEG stream
  // Démarrer le serveur web et le flux vidéo MJPEG
  startCameraServer();

}

void loop() {
  if ( WiFi.status() != WL_CONNECTED ) {
    // We just lost WiFi connexion!
    // On vient de perdre la connexion WiFi
    restartESP32Cam();
  }

  delay(10);
}

// Auto re-connect WiFi network after a moment 
// Automatically 
retrieve WiFi connection if unable to connect or if connection is lost void restartESP32Cam() 
{ 
  Serial.println ("Impossible to connect WiFi network or connection lost! I sleep a moment and I retry later, sorry "); 
  // Activate ESP32 deep sleep mode 
  // Put the ESP32 in deep-sleep mode so as not to drain the battery or consume unnecessarily 
  esp_sleep_enable_timer_wakeup (uS_TO_S_FACTOR * TIME_TO_SLEEP); 
  esp_deep_sleep_start (); 
}

#if defined(CAMERA_MODEL_WROVER_KIT)
#define PWDN_GPIO_NUM    -1
#define RESET_GPIO_NUM   -1
#define XCLK_GPIO_NUM    21
#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      19
#define Y4_GPIO_NUM      18
#define Y3_GPIO_NUM       5
#define Y2_GPIO_NUM       4
#define VSYNC_GPIO_NUM   25
#define HREF_GPIO_NUM    23
#define PCLK_GPIO_NUM    22

#elif defined(CAMERA_MODEL_ESP_EYE)
#define PWDN_GPIO_NUM    -1
#define RESET_GPIO_NUM   -1
#define XCLK_GPIO_NUM    4
#define SIOD_GPIO_NUM    18
#define SIOC_GPIO_NUM    23

#define Y9_GPIO_NUM      36
#define Y8_GPIO_NUM      37
#define Y7_GPIO_NUM      38
#define Y6_GPIO_NUM      39
#define Y5_GPIO_NUM      35
#define Y4_GPIO_NUM      14
#define Y3_GPIO_NUM      13
#define Y2_GPIO_NUM      34
#define VSYNC_GPIO_NUM   5
#define HREF_GPIO_NUM    27
#define PCLK_GPIO_NUM    25

#elif defined(CAMERA_MODEL_M5STACK_PSRAM)
#define PWDN_GPIO_NUM     -1
#define RESET_GPIO_NUM    15
#define XCLK_GPIO_NUM     27
#define SIOD_GPIO_NUM     25
#define SIOC_GPIO_NUM     23

#define Y9_GPIO_NUM       19
#define Y8_GPIO_NUM       36
#define Y7_GPIO_NUM       18
#define Y6_GPIO_NUM       39
#define Y5_GPIO_NUM        5
#define Y4_GPIO_NUM       34
#define Y3_GPIO_NUM       35
#define Y2_GPIO_NUM       32
#define VSYNC_GPIO_NUM    22
#define HREF_GPIO_NUM     26
#define PCLK_GPIO_NUM     21

#elif defined(CAMERA_MODEL_M5STACK_WIDE)
#define PWDN_GPIO_NUM     -1
#define RESET_GPIO_NUM    15
#define XCLK_GPIO_NUM     27
#define SIOD_GPIO_NUM     22
#define SIOC_GPIO_NUM     23

#define Y9_GPIO_NUM       19
#define Y8_GPIO_NUM       36
#define Y7_GPIO_NUM       18
#define Y6_GPIO_NUM       39
#define Y5_GPIO_NUM        5
#define Y4_GPIO_NUM       34
#define Y3_GPIO_NUM       35
#define Y2_GPIO_NUM       32
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     26
#define PCLK_GPIO_NUM     21

#elif defined(CAMERA_MODEL_AI_THINKER)
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

#else
#error "Camera model not selected"
#endif

[env:esp32cam]
platform = espressif32
board = esp32cam
framework = arduino
monitor_speed = 115200

The code was developed with a generic AI Thinker type ESP32-CAM board. However, it should work perfectly identically on M5Stack and TTGO cards in particular.

Generic ESP32-CAM Modules

TTGO T-Camera with PIR motion detector

TTGO T-Camera Plus with 1.8 “color TFT display

TTGO T-Journal with SMA connector for external antenna and OLED display

See other ESP32-CAM modules

Updates

2021/01/18 Publication of the article

Version française

Click to rate this post!
[Total: 0 Average: 0]
Exit mobile version