Projet caméra ArducamOV5642 / ESP32 / nodered

Bonjour à tous,

J'aimerais apporter à mon projet de maison connecté ou se trouve déjà fonctionnel plusieurs sondes de température / météo / pilotage électrique d'éléments 220V via l'interface suivante :

  • sondes connectées à des ESP32.
  • ESP32 qui communiquent avec nodered en MQTT lui même installé sur une RaspberryPi.

J'aimerai avec mes enfants installer deux caméras dans deux nids de mésange bleue afin de suivre l'évolution des pontes n'importe quand au printemps.

Dans l'idée, je voulais connecter la caméra à un ESP32 pour qu'il fournisse le flux vidéo à mon nodered.

Voici la caméra en question qui est en ma possession :

J'ai commencé à branché la caméra et j'ai suivi le lien GitHub suivant :

https://github.com/ArduCAM/ArduCAM_ESP32S_UNO

J'ai un problème d'installation de la carte supplémentaire : ArduCAM_ESP32S_UNO:esp32

Lorsque j'intègre l'adresse suivante dans les préférences de carte supplémentaire de l'ide arduino, je veux installer la carte supplémentaire dans le gestionnaire de carte, j'obtiens l'erreur suivante dans le moniteur série :

Tool ArduCAM_ESP32S_UNO:xtensa-esp32-elf-gcc@1.22.0-80-g6c4433a-5.2.0 already installed
Tool ArduCAM_ESP32S_UNO:esptool@2.3.1 already installed
Tool ArduCAM_ESP32S_UNO:mkspiffs@0.2.3 already installed
Téléchargement des paquets
ArduCAM_ESP32S_UNO:esp32@2.0.0
Installing platform ArduCAM_ESP32S_UNO:esp32@2.0.0
Failed to install platform: ArduCAM_ESP32S_UNO:esp32.
Error: 13 INTERNAL: Cannot install platform: installing platform ArduCAM_ESP32S_UNO:esp32@2.0.0: testing local archive integrity: testing archive size: fetched archive size differs from size specified in index: 30810480 != 30814208

Du coup, je n'arrive pas à avoir les exemples disponibles.

Pouvez vous m'aider sur ce projet ?

Merci par avance,

Ludo

quelle adresse ?
quelle version de l'IDE ?

https://www.arducam.com/downloads/ESP32_UNO/package_ArduCAM_ESP32S_UNO_index.json

Version IDE : 2.0.3

et vous avez quoi comme arduino, la carte dédiée dont ils parlent ?

Non, j'ai un ESP32 comme celui la :

Il y a déjà une issue d'ouverte sur ce sujet depuis un an.

On ne peut pas dire que le développeur soit très réactif....

dans ce cas pourquoi voulez vous installez la "board" correspondant à l'ArduCAM_ESP32S_UNO ?

peut-être qu'il suffit de prendre la bibliothèque adaptée à votre arducam 0V5642 ( Arduino/ArduCAM at master · ArduCAM/Arduino · GitHub)

il ya un exemple sur ESP8266

Peut on utiliser cette caméra pour l'utiliser en streaming sur une adresse web ? ( Comme une vidéo ip ) ?

Je pense que la possibilité ne dépend pas de la caméra, mais du programme qui la gère.

Arducam n'est pas très répandu ici, regarde déjà ce qu'il est possible de faire avec une ESP32-CAM de chez AiThinker.
Un bon site :

Ce n’est pas trivial si la caméra ne sort que des photos

Il y a des exemples cela dit si vous cherchez arducam live stream

Oui, c'est effectivement se qui m'intéresse en type de programme par contre, je ne peux pas l'adapter sur un ESP32 car les bibliothèque ESP8266WIFI.h n'est pas trouvable pour mon ESP32.

Une idée sur la manière d'adapter le programme suivant sur un ESP32 ?

// Mini serveur de caméra ArduCAM ESP8266-12E
//
// Ce programme montre comment utiliser une caméra ArduCAM Mini 2MP avec un module ESP8266-12E.
// Une ArduCAM Mini OV2640 2MP a été utilisée avec ce programme.
//
// Le programme dispose d'une interface web qui va permettre :
// - stockage et visualisation des fichiers jpg capturés
// - visionner une vidéo diffusée en direct
// - changer la résolution
//
// Les fichiers jpeg capturés sont stockés dans la mémoire intégrée de l'ESP8266-12E.
//
// Les fonctionnalités de capture et de streaming sont accessibles directement via le navigateur en utilisant le format :
// http://IPaddress/capture - pour une capture fixe
// http://IPaddress/stream - pour le streaming vidéo
//
// Les images fixes capturées ou la vidéo diffusée sont accessibles sous forme d'image HTML :
// <img src="http://adresseIP/capture">
//        ou
// <img src="http://adresseIP/flux">
//
//
// Schéma de câblage pour connecter ArduCAM à ESP8266-12E
//
//     ArduCAM mini   ->    ESP8266-12E
//         CS         ->        D0
//        MOSI        ->        D7
//        MISC        ->        D6
//         SCK        ->        D5
//         GND        ->       GND
//         VCC        ->       3V3
//         SDA        ->        D2
//         SCL        ->        D1


#include <FS.h> // FOR SPIFFS
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <Wire.h>
#include <ArduCAM.h>
#include <SPI.h>
#include "memorysaver.h"
#if !(defined ESP8266 )
#error Please select the ArduCAM ESP8266 UNO board in the Tools/Board
#endif

//This demo can only work on OV2640_MINI_2MP or ARDUCAM_SHIELD_V2 platform.
#if !(defined (OV2640_MINI_2MP)||(defined (ARDUCAM_SHIELD_V2) && defined (OV2640_CAM)))
#error Please select the hardware platform and camera module in the ../libraries/ArduCAM/memorysaver.h file
#endif

// set GPIO16 as the slave select :
const int CS = 16;

// if the video is chopped or distored, try using a lower value for the buffer
// lower values will have fewer frames per second while streaming
static const size_t bufferSize = 4096; // 4096; //2048; //1024;

static const int fileSpaceOffset = 700000;

static const int wifiType = 0; // 0:Station  1:AP

//AP mode configuration
const char *AP_ssid = "arducam_esp8266";
//Default is no password.If you want to set password,put your password here
const char *AP_password = "APpassword";

//Station mode you should put your ssid and password
const char *ssid = "yourWiFiSSID"; // Put your SSID here
const char *password = "yourWiFiPassword"; // Put your PASSWORD here

static IPAddress ip(192, 168, 1, 203); // static IP used for browser access: http://IPaddress
static IPAddress gateway(192, 168, 1, 1);
static IPAddress subnet(255, 255, 255, 0);

const String fName = "res.txt";

int fileTotalKB = 0;
int fileUsedKB = 0; int fileCount = 0;
String errMsg = "";
int imgMode = 1; // 0: stream  1: capture
int resolution = 3;
// resolutions:
// 0 = 160x120
// 1 = 176x144
// 2 = 320x240
// 3 = 352x288
// 4 = 640x480
// 5 = 800x600
// 6 = 1024x768
// 7 = 1280x1024
// 8 = 1600x1200

ESP8266WebServer server(80);

ArduCAM myCAM(OV2640, CS);

/////////////////////////////////////////////////
//   Updates Properties file with resolution  ///
/////////////////////////////////////////////////
void updateDataFile()
{

  File f = SPIFFS.open(fName, "w");
  if (!f) {
    Serial.println("prop file open failed");
  }
  else
  {
    Serial.println("====== Writing to prop file =========");

    f.println(resolution);
    Serial.println("Data file updated");
    f.close();
  }

}

///////////////////////////////////////////
//    Saves captured image to memory     //
///////////////////////////////////////////
void myCAMSaveToSPIFFS() {

  // as file space is used, capturing images will get slower. At a certain point, the images will become distored
  // or they will not save at all due to lack of space. To avoid this we set a limit and allow some free space to remain
  if ((fileTotalKB - fileUsedKB) < fileSpaceOffset)
  {
    String maxStr = "====== Maximum Data Storage Reached =========";
    Serial.println(maxStr);
    errMsg = maxStr;
    return;
  }

  String str;
  byte buf[256];
  static int i = 0;

  static int n = 0;
  uint8_t temp, temp_last;

  //  File file;
  //Flush the FIFO
  myCAM.flush_fifo();
  //Clear the capture done flag
  myCAM.clear_fifo_flag();
  //Start capture
  myCAM.start_capture();

  while (!myCAM.get_bit(ARDUCHIP_TRIG , CAP_DONE_MASK));
  Serial.println("File Capture Done!");

  fileCount++;

  str = "/pics/" + String(fileCount)  + ".jpg";

  File f = SPIFFS.open(str, "w");
  if (!f) {
    Serial.println("prop file open failed");
  }
  else
  {
    Serial.println(str);
  }


  i = 0;
  myCAM.CS_LOW();
  myCAM.set_fifo_burst();
#if !(defined (ARDUCAM_SHIELD_V2) && defined (OV2640_CAM))
  SPI.transfer(0xFF);
#endif
  //Read JPEG data from FIFO
  while ( (temp != 0xD9) | (temp_last != 0xFF)) {
    temp_last = temp;
    temp = SPI.transfer(0x00);

    //Write image data to buffer if not full
    if ( i < 256)
      buf[i++] = temp;
    else {
      //Write 256 bytes image data to file
      myCAM.CS_HIGH();
      f.write(buf , 256);
      i = 0;
      buf[i++] = temp;
      myCAM.CS_LOW();
      myCAM.set_fifo_burst();
    }
    //delay(0);
  }

  //Write the remain bytes in the buffer
  if (i > 0) {
    myCAM.CS_HIGH();
    f.write(buf, i);
  }
  //Close the file
  f.close();
  Serial.println("CAM Save Done!");
}


//////////////////////////////////////////////////////////////////////////////////////////////////
//    Retrieves a stored jpg file and sends to browser based on url: http://IPaddress/1.jpg     //
//////////////////////////////////////////////////////////////////////////////////////////////////
bool loadFromSpiffs(String path) {
  String dataType = "text/plain";
  if (path.endsWith("/")) path += "index.htm";

  if (path.endsWith(".src")) path = path.substring(0, path.lastIndexOf("."));
  //  else if (path.endsWith(".htm")) dataType = "text/html";
  //  else if (path.endsWith(".css")) dataType = "text/css";
  //  else if (path.endsWith(".js")) dataType = "application/javascript";
  //  else if (path.endsWith(".png")) dataType = "image/png";
  //  else if (path.endsWith(".gif")) dataType = "image/gif";
  else if (path.endsWith(".jpg")) dataType = "image/jpeg";
  //  else if (path.endsWith(".ico")) dataType = "image/x-icon";
  //  else if (path.endsWith(".xml")) dataType = "text/xml";
  //  else if (path.endsWith(".pdf")) dataType = "application/pdf";
  //  else if (path.endsWith(".zip")) dataType = "application/zip";
  File dataFile = SPIFFS.open(path.c_str(), "r");
  if (server.hasArg("download")) dataType = "application/octet-stream";

  if (server.streamFile(dataFile, dataType) != dataFile.size()) {
  }

  dataFile.close();
  return true;
}

/////////////////////////////////////////////////////////////
//  sets the HTML used for the resoultions drop down       //
/////////////////////////////////////////////////////////////
String getDropDown()
{
  String webString = "";
  webString += "<select name=\"rez\">\n";
  webString += "   <option value=\"0\" ";
  if (resolution == 0)
    webString += " selected=\"seleted\" ";
  webString += ">160x120</option>\n";

  webString += "   <option value=\"1\" ";
  if (resolution == 1)
    webString += " selected=\"seleted\" ";
  webString += ">176x144</option>\n";

  webString += "   <option value=\"2\" ";
  if (resolution == 2)
    webString += " selected=\"seleted\" ";
  webString += ">320x240</option>\n";

  webString += "   <option value=\"3\" ";
  if (resolution == 3)
    webString += " selected=\"seleted\" ";
  webString += ">352x288</option>\n";

  webString += "   <option value=\"4\" ";
  if (resolution == 4)
    webString += " selected=\"seleted\" ";
  webString += ">640x480</option>\n";

  webString += "   <option value=\"5\" ";
  if (resolution == 5)
    webString += " selected=\"seleted\" ";
  webString += ">800x600</option>\n";

  webString += "   <option value=\"6\" ";
  if (resolution == 6)
    webString += " selected=\"seleted\" ";
  webString += ">1024x768</option>\n";

  webString += "   <option value=\"7\" ";
  if (resolution == 7)
    webString += " selected=\"seleted\" ";
  webString += ">1280x1024</option>\n";

  webString += "   <option value=\"8\" ";
  if (resolution == 8)
    webString += " selected=\"seleted\" ";
  webString += ">1600x1200</option>\n";

  webString += "  </select>\n";

  return webString;
}


////////////////////////////////////
// capture initialization         //
////////////////////////////////////
void start_capture() {
  myCAM.clear_fifo_flag();
  myCAM.start_capture();
}

/////////////////////////////////////////////
// capture still image and send to client  //
/////////////////////////////////////////////
void camCapture(ArduCAM myCAM) {

  WiFiClient client = server.client();

  size_t len = myCAM.read_fifo_length();
  if (len >= 0x07ffff) {
    Serial.println("Over size.");
    return;
  } else if (len == 0 ) {
    Serial.println("Size is 0.");
    return;
  }

  myCAM.CS_LOW();
  myCAM.set_fifo_burst();
#if !(defined (ARDUCAM_SHIELD_V2) && defined (OV2640_CAM))
  SPI.transfer(0xFF);
#endif

  if (!client.connected()) return;

  /*
    String response = "HTTP/1.1 200 OK\r\n";
    response += "Content-Type: image/jpeg\r\n";
    response += "Content-Length: " + String(len) + "\r\n\r\n";
    server.sendContent(response);
  */

  static uint8_t buffer[bufferSize] = {0xFF};

  while (len) {
    size_t will_copy = (len < bufferSize) ? len : bufferSize;
    SPI.transferBytes(&buffer[0], &buffer[0], will_copy);
    if (!client.connected()) break;
    client.write(&buffer[0], will_copy);
    len -= will_copy;
  }

  myCAM.CS_HIGH();
}


/////////////////////////////////////////////
// initiate capture and record time used   //
/////////////////////////////////////////////
void serverCapture() {


  start_capture();
  Serial.println("CAM Capturing");

  int total_time = 0;

  total_time = millis();
  while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
  total_time = millis() - total_time;
  Serial.print("capture total_time used (in miliseconds):");
  Serial.println(total_time, DEC);

  total_time = 0;

  Serial.println("CAM Capture Done!");
  total_time = millis();
  camCapture(myCAM);
  total_time = millis() - total_time;
  Serial.print("send total_time used (in miliseconds):");
  Serial.println(total_time, DEC);
  Serial.println("CAM send Done!");
}

/////////////////////////////
// stream video to client  //
/////////////////////////////
void serverStream() {
  WiFiClient client = server.client();

  String response = "HTTP/1.1 200 OK\r\n";
  response += "Content-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n";
  server.sendContent(response);

  while (client.connected()) {

    start_capture();

    while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));

    size_t len = myCAM.read_fifo_length();
    if (len >= 0x07ffff) {
      Serial.println("Over size.");
      continue;
    } else if (len == 0 ) {
      Serial.println("Size is 0.");
      continue;
    }

    myCAM.CS_LOW();
    myCAM.set_fifo_burst();
#if !(defined (ARDUCAM_SHIELD_V2) && defined (OV2640_CAM))
    SPI.transfer(0xFF);
#endif
    if (!client.connected()) break;
    response = "--frame\r\n";
    response += "Content-Type: image/jpeg\r\n\r\n";
    server.sendContent(response);

    static uint8_t buffer[bufferSize] = {0xFF};

    while (len) {
      size_t will_copy = (len < bufferSize) ? len : bufferSize;
      SPI.transferBytes(&buffer[0], &buffer[0], will_copy);
      if (!client.connected()) break;
      client.write(&buffer[0], will_copy);
      len -= will_copy;
    }
    myCAM.CS_HIGH();

    if (!client.connected()) break;
  }
}

////////////////////////////////////////////////////////////////
//  Default web handler used when client access web server    //
////////////////////////////////////////////////////////////////
void handleNotFound() {

  String ipStr = WiFi.localIP().toString();
  if (wifiType == 1) // AP mode = 1
  {
    ipStr = WiFi.softAPIP().toString();
  }


  Serial.print("server uri: " ); Serial.println(server.uri());
  // if url contains request for stored image: http://IPaddress/pics/2.jpg
  if (server.uri().indexOf(".jpg") != -1 )
  {
    loadFromSpiffs(server.uri());
    return;
  }

  //// default HTML
  String message = "<html><head>\n";
  message += "</head><body>\n";
  message += "<form action=\"http://" + ipStr + "/submit\" method=\"POST\">";
  message += "<h1>ESP8266-12E Arducam Mini</h1>\n";
  if (errMsg != "")
    message += "<div style=\"color:red\">" + errMsg + "</div>";


  if (imgMode == 0) // stream mode
  {
    message += "<div><h2>Video Streaming</h2></div> \n";
    message += "<div><img id=\"ArduCam\" src=\"http://" + ipStr + "/stream\" ></div>\n";
    imgMode = 1; // set back to capture mode so it doesn't get stuck in streaming mode

  }
  else
  {
    message += "<div>";
    message += getDropDown();

    message += " <input type=\"radio\" id=\"strm\" name=\"imgMode\" value=\"stream\" ";

    if (imgMode == 0)
      message += " checked ";
    message += "> Stream \n";

    message += " <input type=\"radio\" id=\"capt\" name=\"imgMode\" value=\"capture\"  ";
    if (imgMode == 1)
      message += " checked ";
    message += "> Capture \n";

    message += "&nbsp; <input type='submit' value='Submit'  >\n";
    message += " &nbsp;  <a style=\"font-size:12px; font-weight:bold;\" href=\"http://" + ipStr + "\">Refresh</a>";
    message += " &nbsp; &nbsp; <a style=\"font-size:12px; font-weight:bold;\" onclick=\"return confirm('Are you sure? This will delete all stored images.')\" ";
    message += " href=\"http://" + ipStr + "/clear\">Clear Data</a>\n";

    message += "</div>\n";


    ///////////////////////////////
    FSInfo fs_info;
    SPIFFS.info(fs_info);

    fileTotalKB = (int)fs_info.totalBytes;
    fileUsedKB = (int)fs_info.usedBytes;


    if (fileCount > 0)
    {
      int percentUsed = ((float)fileUsedKB / (float)(fileTotalKB - fileSpaceOffset)) * 100;
      String colorStr = "green";
      if (percentUsed > 90)
        colorStr = "red";

      message += "<div style=\"width:450px; background-color:darkgray; padding:1px;\">";
      message += "<div style=\"position:absolute; color:white; padding-top:2px; font-size:11px;\"> &nbsp; space used: " + String(percentUsed) + "%</div>";
      message += "<div style=\"width:" + String(percentUsed) + "%; height:16px; background-color: " + colorStr + ";\"></div></div>\n";

    }

    message += "<table><tr>";
    int colCnt = 0;
    for (int i = 1; i <= fileCount; i++)
    {
      message += "<td><a href=\"/pics/" + String(i) + ".jpg\">" + i + ".jpg</a></td>\n";

      colCnt++;
      if (colCnt >= 10) //  columns
      {
        message += "</tr><tr>";
        colCnt = 0;
      }
    }
    message += "</tr></table>\n";




    //useful for debugging max data storage
    /*
      message += "<table><tr><td>Total Bytes: </td><td style=\"text-align:right;\">";
      message += fileTotalKB;
      message += "</td></tr><tr><td>Used Bytes: </td><td style=\"text-align:right;\">";
      message += fileUsedKB;
      message += "</td></tr><tr><td>Remaing Bytes: </td><td style=\"text-align:right;\">";
      message += (fileTotalKB - fileUsedKB);
      message += "</td></tr></table>\n";
    */
    /*
      float flashChipSize = (float)ESP.getFlashChipSize() / 1024.0 / 1024.0;
      message += "<br>chipSize: ";
      message += flashChipSize;
    */

    message += "<div><img id=\"ArduCam\" src=\"http://" + ipStr + "/capture\" ></div>\n";


  }

  message += "</form> \n";
  message += "</body></html>\n";

  server.send(200, "text/html", message);

}

///////////////////////////////////////////////////////////////////////////////////
//    used when form is submitted and at setup to set the camera resolution      //
///////////////////////////////////////////////////////////////////////////////////
void setCamResolution(int reso)
{
  switch (reso)
  {
    case 0:
      myCAM.OV2640_set_JPEG_size(OV2640_160x120);
      resolution = 0;
      break;

    case 1:
      myCAM.OV2640_set_JPEG_size(OV2640_176x144);
      resolution = 1;
      break;

    case 2:
      myCAM.OV2640_set_JPEG_size(OV2640_320x240);
      resolution = 2;
      break;

    case 3:
      myCAM.OV2640_set_JPEG_size(OV2640_352x288);
      resolution = 3;
      break;

    case 4:
      myCAM.OV2640_set_JPEG_size(OV2640_640x480);
      resolution = 4;
      break;

    case 5:
      myCAM.OV2640_set_JPEG_size(OV2640_800x600);
      resolution = 5;
      break;

    case 6:
      myCAM.OV2640_set_JPEG_size(OV2640_1024x768);
      resolution = 6;
      break;

    case 7:
      myCAM.OV2640_set_JPEG_size(OV2640_1280x1024);
      resolution = 7;
      break;

    case 8:
      myCAM.OV2640_set_JPEG_size(OV2640_1600x1200);
      resolution = 8;
      break;

  }
}

///////////////////////////////////////////////////////
//   deletes all files in the /pics directory        //
///////////////////////////////////////////////////////
void clearData()
{
  errMsg = "======  Data Storage Cleared =========";
  Dir dir = SPIFFS.openDir("/pics");
  while (dir.next()) {
    SPIFFS.remove(dir.fileName());
  }

  fileCount = 0;
  fileTotalKB = 0;
  fileUsedKB = 0;

  handleNotFound();
}


/////////////////////////////////////
//  handles form submission        //
/////////////////////////////////////
void handleSubmit()
{
  errMsg = "";
  Serial.println( "--- Form Submited ---");
  Serial.println( "Server args " + server.args());

  if (server.args() > 0 ) {
    for ( uint8_t i = 0; i < server.args(); i++ ) {

      // can be useful to determine the values from a form post.
      Serial.println( "Server arg " + server.arg(i));
      Serial.println( "Server argName " + server.argName(i) );
      if (server.argName(i) == "imgMode")
      {
        Serial.println(" Image Mode: " + server.arg(i));

        if (server.arg(i) == "stream")
        {
          imgMode = 0;
        }
        else
        {
          imgMode = 1; // capture mode
        }
      }

      if (server.argName(i) == "rez") {

        if (server.arg(i).toInt() != resolution)
        {

          setCamResolution(server.arg(i).toInt());

          updateDataFile();

          //// IMPORTANT: removing or reducing the delay can result in dark images
          delay(1500); // add a delay to allow the white balance to adjust to new resolution
        }
      }
    }
  }

  if (imgMode == 1) // capture
  {
    myCAMSaveToSPIFFS();
  }

  handleNotFound();

}

////////////////////////////////
//    main setup function     //
////////////////////////////////
void setup() {

  SPIFFS.begin();
  delay(10);

  // SPIFFS.format(); // uncomment to completely clear data including properties file

  // check for properties file
  File f = SPIFFS.open(fName, "r");

  if (!f) {
    // no file exists so lets format and create a properties file
    Serial.println("Please wait 30 secs for SPIFFS to be formatted");

    SPIFFS.format();

    Serial.println("Spiffs formatted");

    f = SPIFFS.open(fName, "w");
    if (!f) {
      Serial.println("properties file open failed");
    }
    else
    {
      // write the defaults to the properties file
      Serial.println("====== Writing to properties file =========");

      f.println(resolution);

      f.close();
    }

  }
  else
  {
    // if the properties file exists on startup,  read it and set the defaults
    Serial.println("Properties file exists. Reading.");

    while (f.available()) {

      // read line by line from the file
      String str = f.readStringUntil('\n');

      Serial.println(str);

      resolution = str.toInt();

    }

    f.close();
  }


  uint8_t vid, pid;
  uint8_t temp;

#if defined(__SAM3X8E__)
  Wire1.begin();
#else
  Wire.begin();
#endif

  Serial.begin(115200);
  Serial.println("ArduCAM Start!");

  // set the CS as an output:
  pinMode(CS, OUTPUT);

  // initialize SPI:
  SPI.begin();
  SPI.setFrequency(4000000); //4MHz

  //Check if the ArduCAM SPI bus is OK
  myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
  temp = myCAM.read_reg(ARDUCHIP_TEST1);
  if (temp != 0x55) {
    Serial.println("SPI1 interface Error!");
  }

  //Check if the camera module type is OV2640
  myCAM.wrSensorReg8_8(0xff, 0x01);
  myCAM.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
  myCAM.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid);
  if ((vid != 0x26 ) && (( pid != 0x41 ) || ( pid != 0x42 )))
    Serial.println("Can't find OV2640 module! pid: " + String(pid));
  else
    Serial.println("OV2640 detected.");


  //Change to JPEG capture mode and initialize the OV2640 module
  myCAM.set_format(JPEG);
  myCAM.InitCAM();

  setCamResolution(resolution);

  myCAM.clear_fifo_flag();

  if (wifiType == 0) {
    if (!strcmp(ssid, "SSID")) {
      Serial.println("Please set your SSID");
    }
    if (!strcmp(password, "PASSWORD")) {
      Serial.println("Please set your PASSWORD");
    }
    // Connect to WiFi network
    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.mode(WIFI_STA);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }

    WiFi.config(ip, gateway, subnet); // remove this line to use DHCP

    Serial.println("WiFi connected");
    Serial.println("");
    Serial.print("ip: ");
    Serial.println(WiFi.localIP());
  } else if (wifiType == 1) {
    Serial.println();
    Serial.println();
    Serial.print("Share AP: ");
    Serial.println(AP_ssid);
    Serial.print("The password is: ");
    Serial.println(AP_password);

    WiFi.mode(WIFI_AP);
    WiFi.softAP(AP_ssid, AP_password);
    Serial.println("");
    Serial.println("AP ip");
    Serial.println(WiFi.softAPIP());
  }

  // setup handlers
  server.on("/capture", HTTP_GET, serverCapture);
  server.on("/stream", HTTP_GET, serverStream);
  server.on("/submit", handleSubmit);
  server.on("/clear", clearData);
  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println("Server started");


  Dir dir = SPIFFS.openDir("/pics");
  while (dir.next()) {
    fileCount++;
  }

  FSInfo fs_info;
  SPIFFS.info(fs_info);

  fileTotalKB = (int)fs_info.totalBytes;
  fileUsedKB = (int)fs_info.usedBytes;

}

/////////////////////////////
//    Main loop function   //
/////////////////////////////
void loop() {
  server.handleClient();
}


mettez ça au début du code

#ifdef ESP32
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif

ça va choisir la bonne bibliothèque en fonction de votre plateforme

Ça marche pour le wifi mais ç'a m’indique la même chose pour :

Compilation error: ESP8266WebServer.h: No such file or directory

mettez cela alors :slight_smile:

#ifdef ESP32
#include <WiFi.h>
#include <WebServer.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#endif

mais il se peut que ce ne soit pas suffisant

Je tente ça demain, merci beaucoup pour l'aide !

Bonjour,

Petit message pour des infos sur mon projet.
J'ai réussi à faire fonctionner ce code suivant en me servant de l'IDE 1.8 :

// Démo ArduCAM Mini (C)2017 Lee
  // Web : http://www.ArduCAM.com
  // Ce programme est une démonstration de l'utilisation de la plupart des fonctions
  // de la bibliothèque avec caméra ArduCAM ESP32 2MP/5MP.
  // Cette démo a été réalisée pour la caméra ArduCAM ESP32 2MP/5MP.
  // Il peut prendre des photos et les envoyer sur le Web.
  // Il peut prendre des photos en continu sous forme de flux vidéo et les envoyer sur le Web.
  // L'esquisse de démonstration effectuera les tâches suivantes :
  // 1. Réglez l'appareil photo sur le mode de sortie JPEG.
  // 2. si le serveur reçoit "adresse IP/capture", il peut prendre une photo et l'envoyer sur le Web.
  // 3.si le serveur reçoit "adresse IP/flux", il peut prendre des photos en continu en tant que vidéo
  //streaming et envoi sur le Web.
  
  // Ce programme nécessite la bibliothèque ArduCAM V4.0.0 (ou ultérieure) et la caméra ArduCAM ESP32 2MP/5MP
  // et utilisez le compilateur Arduino IDE 1.8.1 ou supérieur
  
  #include <WiFi.h>
  #include <Wire.h>
  #include <ESP32WebServer.h>
  #include <ArduCAM.h>
  #include <SPI.h>
  #include "memorysaver.h"
  
  #if !(defined ESP32 )
  #error Please select the ArduCAM ESP32 UNO board in the Tools/Board
  #endif

  //Cette démo ne peut fonctionner que sur la plateforme OV2640_MINI_2MP ou ARDUCAM_SHIELD_V2.

  #if !(defined (OV2640_MINI_2MP)|| defined (OV2640_MINI_2MP_PLUS)||defined (OV5640_MINI_5MP_PLUS) || defined (OV5642_MINI_5MP_PLUS) \
      || defined (OV5642_MINI_5MP) || defined (OV5642_MINI_5MP_BIT_ROTATION_FIXED) \
      ||(defined (ARDUCAM_SHIELD_V2) && (defined (OV2640_CAM) || defined (OV5640_CAM) || defined (OV5642_CAM))))
  #error Please select the hardware platform and camera module in the ../libraries/ArduCAM/memorysaver.h file
  #endif
  
  // définit GPIO17 comme esclave select :

  const int CS = 17;
  const int CAM_POWER_ON = D10;
  #if defined (OV2640_MINI_2MP)|| defined (OV2640_MINI_2MP_PLUS) || defined (OV2640_CAM)
    ArduCAM myCAM(OV2640, CS);
  #elif defined (OV5640_MINI_5MP_PLUS) || defined (OV5640_CAM)
    ArduCAM myCAM(OV5640, CS);
  #elif defined (OV5642_MINI_5MP_PLUS) || defined (OV5642_MINI_5MP) || defined (OV5642_MINI_5MP_BIT_ROTATION_FIXED) ||(defined (OV5642_CAM))
    ArduCAM myCAM(OV5642, CS);
  #endif

 // vous pouvez modifier la valeur de wifiType pour sélectionner le mode Station ou AP.
  // La valeur par défaut est le mode AP.

  int wifiType = 1; // 0:Station  1:AP
  
  //Configuration du mode point d'accès
  // La valeur par défaut est arducam_esp8266. Si vous le souhaitez, vous pouvez remplacer AP_aaid par votre nom préféré

  const char *AP_ssid = "arducam_esp32"; 

  // La valeur par défaut n'est pas un mot de passe. Si vous souhaitez définir un mot de passe, mettez votre mot de passe ici

  const char *AP_password = NULL;
  
  // En mode station, vous devez mettre votre ssid et votre mot de passe

  const char *ssid = "******"; // Mettez votre SSID ici
  const char *password = "*******"; // Mettez votre MOT DE PASSE ici
  
  static const size_t bufferSize = 2048;
  static uint8_t buffer[bufferSize] = {0xFF};
  uint8_t temp = 0, temp_last = 0;
  int i = 0;
  bool is_header = false;
  
  ESP32WebServer server(80);
  
  void start_capture(){
    myCAM.clear_fifo_flag();
    myCAM.start_capture();
  }
  
  void camCapture(ArduCAM myCAM){
  WiFiClient client = server.client();
  uint32_t len  = myCAM.read_fifo_length();
  if (len >= MAX_FIFO_SIZE) //8M
  //Lire les données JPEG du FIFO
  {
    Serial.println(F("Over size."));
  }
  if (len == 0 ) //0 kb
  {
    Serial.println(F("Size is 0."));
  }
  myCAM.CS_LOW();
  myCAM.set_fifo_burst(); 
  if (!client.connected()) return;
  String response = "HTTP/1.1 200 OK\r\n";
  response += "Content-Type: image/jpeg\r\n";
  response += "Content-len: " + String(len) + "\r\n\r\n";
  server.sendContent(response);
  i = 0;
  while ( len-- )
  {
  temp_last = temp;
  temp =  SPI.transfer(0x00);
  
  if ( (temp == 0xD9) && (temp_last == 0xFF) ) // Si trouver la fin, pause pendant,
  {
  buffer[i++] = temp;  // enregistre le dernier 0XD9     
  //Écrit les octets restants dans le tampon
  if (!client.connected()) break;
  client.write(&buffer[0], i);
  is_header = false;
  i = 0;
  myCAM.CS_HIGH();
  break; 
  }  
  if (is_header == true)
  { 
  // Écrit les données de l'image dans le tampon s'il n'est pas plein
  if (i < bufferSize)
  buffer[i++] = temp;
  else
  {
  // Écrit bufferSize octets de données d'image dans le fichier
  if (!client.connected()) break;
  client.write(&buffer[0], bufferSize);
  i = 0;
  buffer[i++] = temp;
  }        
  }
  else if ((temp == 0xD8) & (temp_last == 0xFF))
  {
  is_header = true;
  buffer[i++] = temp_last;
  buffer[i++] = temp;   
  } 
  } 
  }
  
  void serverCapture(){
    delay(1000);
  start_capture();
  Serial.println(F("CAM Capturing"));
  
  int total_time = 0;
  
  total_time = millis();
  while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
  total_time = millis() - total_time;
  Serial.print(F("capture total_time used (in miliseconds):"));
  Serial.println(total_time, DEC);
  
  total_time = 0;
  
  Serial.println(F("CAM Capture Done."));
  total_time = millis();
  camCapture(myCAM);
  total_time = millis() - total_time;
  Serial.print(F("send total_time used (in miliseconds):"));
  Serial.println(total_time, DEC);
  Serial.println(F("CAM send Done."));
  }
  
  void serverStream(){
  WiFiClient client = server.client();
  
  String response = "HTTP/1.1 200 OK\r\n";
  response += "Content-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n";
  server.sendContent(response);
  
  while (1){
  start_capture();
  while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
  size_t len = myCAM.read_fifo_length();
  if (len >= MAX_FIFO_SIZE) //8M
  {
  Serial.println(F("Over size."));
  continue;
  }
  if (len == 0 ) //0 kb
  {
  Serial.println(F("Size is 0."));
  continue;
  } 
  myCAM.CS_LOW();
  myCAM.set_fifo_burst();
  if (!client.connected()) break;
  response = "--frame\r\n";
  response += "Content-Type: image/jpeg\r\n\r\n";
  server.sendContent(response); 
  while ( len-- )
  {
  temp_last = temp;
  temp =  SPI.transfer(0x00);
  
  //Lire les données JPEG du FIFO
  if ( (temp == 0xD9) && (temp_last == 0xFF) ) // Si trouver la fin, pause pendant,
  {
  buffer[i++] = temp;  // enregistre le dernier 0XD9    
  //Écrit les octets restants dans le tampon
  myCAM.CS_HIGH();; 
  if (!client.connected()) break;
  client.write(&buffer[0], i);
  is_header = false;
  i = 0;
  }  
  if (is_header == true)
  { 
// Écrit les données de l'image dans le tampon s'il n'est pas plein
  if (i < bufferSize)
  buffer[i++] = temp;
  else
  {
  // Écrit bufferSize octets de données d'image dans le fichier
  myCAM.CS_HIGH(); 
  if (!client.connected()) break;
  client.write(&buffer[0], bufferSize);
  i = 0;
  buffer[i++] = temp;
  myCAM.CS_LOW();
  myCAM.set_fifo_burst();
  }        
  }
  else if ((temp == 0xD8) & (temp_last == 0xFF))
  {
  is_header = true;
  buffer[i++] = temp_last;
  buffer[i++] = temp;   
  } 
  }
  if (!client.connected()) break;
  }
  }
  void handleNotFound(){
  String message = "Server is running!\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  server.send(200, "text/plain", message);
  Serial.println(message);
  
  
  
  if (server.hasArg("ql")){
  int ql = server.arg("ql").toInt();
  #if defined (OV2640_MINI_2MP) || defined (OV2640_MINI_2MP_PLUS) || defined (OV2640_CAM)
  myCAM.OV2640_set_JPEG_size(ql);
  #elif defined (OV5640_MINI_5MP_PLUS) || defined (OV5640_CAM)  
  myCAM.OV5640_set_JPEG_size(ql);
  #elif defined (OV5642_MINI_5MP_PLUS) || defined (OV5642_MINI_5MP_BIT_ROTATION_FIXED) ||(defined (OV5642_CAM))
  myCAM.OV5642_set_JPEG_size(ql);
  #endif
  
  Serial.println("QL change to: " + server.arg("ql"));
  }
  }
  void setup() {
  uint8_t vid, pid;
  uint8_t temp;
    //définir le CS comme sortie :
    pinMode(CS,OUTPUT);
    pinMode(CAM_POWER_ON , OUTPUT);
    digitalWrite(CAM_POWER_ON, HIGH);
  #if defined(__SAM3X8E__)
  Wire1.begin();
  #else
  Wire.begin();
  #endif
  Serial.begin(115200);
  Serial.println(F("ArduCAM Start!"));  
  
  // initialise SPI :
  SPI.begin();
  SPI.setFrequency(4000000); //4MHz
  
  //Réinitialiser le CPLD
  myCAM.write_reg(0x07, 0x80);
  delay(100);
  myCAM.write_reg(0x07, 0x00);
  delay(100);
  //Vérifier si le bus ArduCAM SPI est OK
  myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
  temp = myCAM.read_reg(ARDUCHIP_TEST1);
  if (temp != 0x55){
  Serial.println(temp, HEX);
  Serial.println(F("SPI1 interface Error!"));
  while(1);
  }
  
  //Vérifier si le bus ArduCAM SPI est OK
  myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
  temp = myCAM.read_reg(ARDUCHIP_TEST1);
  if (temp != 0x55){
  Serial.println(F("SPI1 interface Error!"));
  while(1);
  }

  #if defined (OV2640_MINI_2MP)|| defined (OV2640_MINI_2MP_PLUS) || defined (OV2640_CAM)
  //Vérifier si le type de module de caméra est OV2640
  myCAM.wrSensorReg8_8(0xff, 0x01);
  myCAM.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
  myCAM.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid);
  if ((vid != 0x26 ) && (( pid != 0x41 ) || ( pid != 0x42 )))
  Serial.println(F("Can't find OV2640 module!"));
  else
  Serial.println(F("OV2640 detected."));
  #elif defined (OV5640_MINI_5MP_PLUS) || defined (OV5640_CAM)
  //Vérifier si le type de module de caméra est OV5640
  myCAM.wrSensorReg16_8(0xff, 0x01);
  myCAM.rdSensorReg16_8(OV5640_CHIPID_HIGH, &vid);
  myCAM.rdSensorReg16_8(OV5640_CHIPID_LOW, &pid);
  if((vid != 0x56) || (pid != 0x40))
  Serial.println(F("Can't find OV5640 module!"));
  else
  Serial.println(F("OV5640 detected."));
  #elif defined (OV5642_MINI_5MP_PLUS) || defined (OV5642_MINI_5MP) || defined (OV5642_MINI_5MP_BIT_ROTATION_FIXED) ||(defined (OV5642_CAM))
  //Vérifier si le type de module de caméra est OV5642
  myCAM.wrSensorReg16_8(0xff, 0x01);
  myCAM.rdSensorReg16_8(OV5642_CHIPID_HIGH, &vid);
  myCAM.rdSensorReg16_8(OV5642_CHIPID_LOW, &pid);
  if((vid != 0x56) || (pid != 0x42)){
  Serial.println(F("Can't find OV5642 module!"));
  }
  else
  Serial.println(F("OV5642 detected."));
  #endif
  
  
  //Passez en mode de capture JPEG et initialisez le module OV2640
  myCAM.set_format(JPEG);
  myCAM.InitCAM();
  #if defined (OV2640_MINI_2MP)|| defined (OV2640_MINI_2MP_PLUS) || defined (OV2640_CAM)
  myCAM.OV2640_set_JPEG_size(OV2640_320x240);
  #elif defined (OV5640_MINI_5MP_PLUS) || defined (OV5640_CAM)
  myCAM.write_reg(ARDUCHIP_TIM, VSYNC_LEVEL_MASK);   //VSYNC is active HIGH
  myCAM.OV5640_set_JPEG_size(OV5640_320x240);
  #elif defined (OV5642_MINI_5MP_PLUS) || defined (OV5642_MINI_5MP) || defined (OV5642_MINI_5MP_BIT_ROTATION_FIXED) ||(defined (OV5642_CAM))
  myCAM.write_reg(ARDUCHIP_TIM, VSYNC_LEVEL_MASK);   //VSYNC is active HIGH
  myCAM.OV5640_set_JPEG_size(OV5642_320x240);  
  #endif
  
  myCAM.clear_fifo_flag();
  if (wifiType == 0){
  if(!strcmp(ssid,"SSID")){
  Serial.println(F("Please set your SSID"));
  while(1);
  }
  if(!strcmp(password,"PASSWORD")){
  Serial.println(F("Please set your PASSWORD"));
  while(1);
  }
 // Se connecter au réseau Wi-Fi
  Serial.println();
  Serial.println();
  Serial.print(F("Connecting to "));
  Serial.println(ssid);
  
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(F("."));
  }
  Serial.println(F("WiFi connected"));
  Serial.println("");
  Serial.println(WiFi.localIP());
  }else if (wifiType == 1){
  Serial.println();
  Serial.println();
  Serial.print(F("Share AP: "));
  Serial.println(AP_ssid);
  Serial.print(F("The password is: "));
  Serial.println(AP_password);
  
  WiFi.mode(WIFI_AP);
  WiFi.softAP(AP_ssid, AP_password);
  Serial.println("");
  Serial.println(WiFi.softAPIP());
  }
  
 // Démarre le serveur
  server.on("/capture", HTTP_GET, serverCapture);
  server.on("/stream", HTTP_GET, serverStream);
  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println(F("Server started"));
  }
  void loop() {
      server.handleClient(); 
    }

J'arrive à avoir un flux vidéo / photo avec option de résolution comme la photo suivante :

7-300x202

Il s'agit d'une URL local sur mon PC ( chemin de fichier ) qui récupère les données du flux vidéo via une adresse IP locale ( 192.168.1.26 dans mon cas )
Lorsque je tappe dans mon navigateur : http://192.168.1.26:80, je n'obtiens que l'état du serveur mais pas de flux d'image.

Ma question est la suivante :

Je cherche à afficher ce flux vidéo sur une URL web afin d'y avoir accès de partour et l'intégrer facilement dans un dashboard nodered.
Avez vous une idée de comment m'y prendre ?

Merci,
Ludo

Ce n’est pas un souci de votre arduino mais un besoin de configuration de votre réseau personnel à la maison pour qu’une requête sur votre adresse WAN sur un certain port que vous décideriez soit routé vers L’ESP. De plus votre IP perso n’étant sans doute pas fixe il faudra jouer avec du dns dynamique.

Notez que cela veut dire que vous faites un trou dans l’intégrité et la sécurité de votre réseau personnel et si ce que je mentionne ci dessus est incompréhensible pour vous alors il faut étudier un peu plus les réseaux, DNS, DMZ etc avant de le faire.

Notez aussi que votre petit ESP ne peut pas supporter de nombreuses connexions simultanées pour ce streaming.. il y a des replicateurs de flux c’est ce que fait Twitch par exemple

LA sécurité n'est pas géante pour ce réseau chez moi.
j'ai fixé l'ip et voila se que j'obtiens dans mon navigateur :
Capture

vous voulez dire que votre Box donnera toujours cette adresse à l'ESP ? C'est bien mais ce n'est pas suffisant...

192.168.1.26 ne ressemble pas à votre adresse WAN, c'est une adresse sur votre réseau local

Si vous avez configuré votre box pour ouvrir un port (par exemple 8080) pour aller sur votre ESP (192.168.1.26:80 si 192.168.1.26 est l'adresse de l'ESP sur le réseau local avec une IP fixe) et que vous voulez tester le routage il faut se connecter sur l'adresse WAN (celle de votre box vue de l'extérieure - vous pouvez la connaitre par exemple en visitant Quel Est Mon IP) et depuis un appareil non connecté à votre réseau interne (par exemple coupez le wifi de votre smartphone et passez en 4G/5G) et dans la navigateur tapez http://x.y.z.t:8080 (où /x.y.z.t est votre adresse WAN)

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.