Esp32 cam avec Pir et sauvegarde sur carte sd

Bonjour les arduinottes,

J'ai en projet de faire une caméra photo pour mon taf.

Je souhaiterais que mon esp32 cam soit en point d'accès, quel soit relié avec un capteur de mouvement et que mon esp32 puisse enregistrer une photo sur la carte sd.

Pour le point d'accès c'est ok, mais en fouillant sur le net j'ai trouvé des sketchs pour le capteur de mouvement et photo.

Ma question est si je combine les sketchs ensemble cela fonctionnera ?

Merci pour vos retour et s'il y existe un sketch tous fait je suis preneur.

le plus simple c'est d'essayer :slight_smile:
(il n'y a pas de raison a priori pour que ça ne fonctionne pas du moment que vous combiniez les codes correctement)

vous avez lu cela ? ESP32-CAM Take Photo and Display in Web Server | Random Nerd Tutorials

Je l'ai fait moi-même et j'ai publié ma solution sur GitHub mais uniquement en anglais. Vous devrez donc peut-être le traduire vous-même.

Peut-être que cela correspond à vos besoins.

(@TriB merci du partage, j'ai édité votre post, merci d'utiliser le français uniquement dans le sous forum francophone)

Bonjour et merci pour votre lien et magnifique travail.
Je souhaiterais mettre la carte de développement al thinker pour l'alimentation.
Mettre mon esp32 en point d’accès avec detecteur PIR pour la prise de photo automatique et avec la possibilité de visualiser les photos depuis une interface web simple et un bouton supprimer.

Cela devrait être possible avec mon code.
Il y a une case à cocher sur l'interface Web pour faire fonctionner l'ESP comme point d'accès.
L'utilisation de la carte de programmation et la connexion USB pour l'alimentation sont également possibles.

merci pour ton retour mais vu l’énorme connaissance sur la prog Arduino que je n'ai pas il me sera très difficile de faire les modifications nécessaire sur ton code.
Par contre j'ai trouvé un code plus simple que je vais tenter de bricoler pour mettre l'esp32 en point d’accès.

/*
   ESP32-CAM PIR WIFI
   Capteur de mouvement PIR branché à une ESP32-CAM.
   Lorsqu'un mouvement est détectée, des photos sont prises.
   Le contenu de la carte SD peut être consulté par WIFI.
   
   Plus d'infos sur le blog:
   https://electroniqueamateur.blogspot.com/2020/07/esp32-cam-et-capteur-infrarouge-passif.html
*/


#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include "FS.h"       // manipulation de fichiers
#include "SD_MMC.h"   // carte SD
#include "esp_camera.h" // caméra!

// écrivez le nom et le mot de passe de votre réseau WIFI
const char* ssid = "**********";
const char* password = "**********";

WebServer server(80);

static bool cartePresente = false;

int numero_fichier = 0; // numéro de la photo (nom du fichier)

int brochePIR = 13; // capteur PIR branché à la broche GPIO13.


// prise de la photo et création du fichier jpeg

void enregistrer_photo (void)
{
  char adresse[20] = ""; // chemin d'accès du fichier .jpeg
  camera_fb_t * fb = NULL; // frame buffer

  // prise de la photo
  fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Echec de la prise de photo.");
    return;
  }

  numero_fichier = numero_fichier + 1;

  // enregitrement du fichier sur la carte SD

  sprintf (adresse, "/%d.jpg", numero_fichier);

  fs::FS &fs = SD_MMC;
  File file = fs.open(adresse, FILE_WRITE);

  if (!file) {
    Serial.println("Echec lors de la creation du fichier.");
  }
  else {
    file.write(fb->buf, fb->len); // payload (image), payload length
    Serial.printf("Fichier enregistre: %s\n", adresse);
  }
  file.close();
  esp_camera_fb_return(fb);

}

void returnOK() {
  server.send(200, "text/plain", "");
}

void returnFail(String msg) {
  server.send(500, "text/plain", msg + "\r\n");
}

// Affichage d'un fichier présent sur la carte
bool loadFromSdCard(String path) {
  String dataType = "text/plain";

  if (path == "/") {
    printDirectory();
  }
  else {

    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";
    }

    fs::FS &fs = SD_MMC;

    File dataFile = fs.open(path.c_str());

    if (!dataFile) {
      return false;
    }

    if (server.hasArg("download")) {
      dataType = "application/octet-stream";
    }

    if (server.streamFile(dataFile, dataType) != dataFile.size()) {
      Serial.println("Sent less data than expected!");
    }

    dataFile.close();

  }
  return true;
}


// utilisé lors de la suppression d'un fichier
void deleteRecursive(String path) {

  fs::FS &fs = SD_MMC;
  File file = fs.open((char *)path.c_str());
  if (!file.isDirectory()) {
    file.close();
    fs.remove((char *)path.c_str());
    return;
  }

  file.rewindDirectory();
  while (true) {
    File entry = file.openNextFile();
    if (!entry) {
      break;
    }
    String entryPath = path + "/" + entry.name();
    if (entry.isDirectory()) {
      entry.close();
      deleteRecursive(entryPath);
    } else {
      entry.close();
      fs.remove((char *)entryPath.c_str());
    }
    yield();
  }

  fs.rmdir((char *)path.c_str());
  file.close();
}

// suppression d'un fichier

void handleDelete() {

  fs::FS &fs = SD_MMC;

  if (server.args() == 0) {
    return returnFail("Mauvais arguments?");
  }
  String path = server.arg(0);
  if (path == "/" || !fs.exists((char *)path.c_str())) {
    returnFail("BAD PATH");
    return;
  }
  deleteRecursive(path);

  // on affiche un message de confirmation
  server.setContentLength(CONTENT_LENGTH_UNKNOWN);

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

  WiFiClient client = server.client();

  server.sendContent("<h1>Le fichier a &eacute;t&eacute; supprim&eacute;</h1>");
  server.sendContent("<p><a href = / > Retour &agrave; la liste des fichiers </a></p>");

}

// Affichage du contenu de la carte
void printDirectory() {

  fs::FS &fs = SD_MMC;
  String path = "/";

  File dir = fs.open((char *)path.c_str());
  path = String();
  if (!dir.isDirectory()) {
    dir.close();
    return returnFail("PAS UN REPERTOIRE");
  }
  dir.rewindDirectory();
  server.setContentLength(CONTENT_LENGTH_UNKNOWN);

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

  WiFiClient client = server.client();

  server.sendContent("<h1>Contenu de la carte SD</h1>");

  for (int cnt = 0; true; ++cnt) {
    File entry = dir.openNextFile();
    if (!entry) {
      break;
    }

    String output;

    output += "<a href = ";
    output += entry.name();
    output += "> ";
    output += entry.name();

    // on ajoute un bouton delete:
    output += "</a> &nbsp; &nbsp;  &nbsp; &nbsp; <a href = /delete?url=";
    output += entry.name();
    output += "> [Supprimer] </a> <br>";

    server.sendContent(output);
    entry.close();
  }
  dir.close();
}

// on tente d'afficher le fichier demandé. Sinon, message d'erreur
void handleNotFound() {
  if (cartePresente && loadFromSdCard(server.uri())) {
    return;
  }
  String message = "Carte SD non detectee ou action imprevue\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " NAME:" + server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  Serial.print(message);
}

void setup(void) {

  // définition des broches de la caméra pour le modèle AI Thinker - ESP32-CAM
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = 5;
  config.pin_d1 = 18;
  config.pin_d2 = 19;
  config.pin_d3 = 21;
  config.pin_d4 = 36;
  config.pin_d5 = 39;
  config.pin_d6 = 34;
  config.pin_d7 = 35;
  config.pin_xclk = 0;
  config.pin_pclk = 22;
  config.pin_vsync = 25;
  config.pin_href = 23;
  config.pin_sscb_sda = 26;
  config.pin_sscb_scl = 27;
  config.pin_pwdn = 32;
  config.pin_reset = -1;

  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;  //YUV422|GRAYSCALE|RGB565|JPEG
  config.frame_size = FRAMESIZE_VGA;  // QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
  config.jpeg_quality = 10;  // 0-63 ; plus bas = meilleure qualité
  config.fb_count = 2; // nombre de frame buffers

  // initialisation de la caméra
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Echec de l'initialisation de la camera, erreur 0x%x", err);
    return;
  }

  sensor_t * s = esp_camera_sensor_get();

  // connexion au WIFI

  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connexion au reseau Wifi ");
  Serial.println(ssid);

  uint8_t i = 0;
  while (WiFi.status() != WL_CONNECTED && i++ < 20) {//wait 10 seconds
    delay(500);
  }
  if (i == 21) {
    Serial.print("Impossible de se connecter au reseau ");
    Serial.println(ssid);
    while (1) {
      delay(500);
    }
  }
  Serial.print("Connecte a l'adresse IP: ");
  Serial.println(WiFi.localIP());

  // initialisation du web server
  server.on("/delete", HTTP_GET, handleDelete);
  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println("Serveur HTTP en fonction.");

  // initialisation de la carte micro SD
  // en mode 1 bit: plus lent, mais libère des broches
  if (SD_MMC.begin("/sdcard", true)) {
    uint8_t cardType = SD_MMC.cardType();
    if (cardType != CARD_NONE) {
      Serial.println("Carte SD Initialisee.");
      cartePresente = true;
    }
  }

  pinMode(brochePIR, INPUT);
}

void loop(void) {
  server.handleClient();

  if (digitalRead(brochePIR)) {
    enregistrer_photo();
    Serial.print("Nouvelle photo!  ");
    Serial.println(numero_fichier);
    delay(300);
  }

}

dans le ligne WiFi.mode(WIFI_STA); je doit le remplacé par WiFi.mode(WIFI_AP); pour que l'esp soit en point d'accès?

En faisant des testes avec cette modification je ne vois pas mon reseau.

Je vais modifier la ligne:

Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connexion au reseau Wifi ");
  Serial.println(ssid);

Et la remplacé par :

Serial.begin(115200);
    Serial.println("\n[*] Creating AP");
    WiFi.mode(WIFI_AP);
    WiFi.softAP(ssid, password);
    Serial.print("[+] AP Created with IP Gateway ");
    Serial.println(WiFi.softAPIP());

Après modification et reset de l'esp et affichage du moniteur série celui-ci tourne en boucle et le réseau ne s'affiche pas.

Voici les modifications apporté au code initial:



/*
   ESP32-CAM PIR WIFI
   Capteur de mouvement PIR branché à une ESP32-CAM.
   Lorsqu'un mouvement est détectée, des photos sont prises.
   Le contenu de la carte SD peut être consulté par WIFI.
   
   Plus d'infos sur le blog:
   https://electroniqueamateur.blogspot.com/2020/07/esp32-cam-et-capteur-infrarouge-passif.html
*/


#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include "FS.h"       // manipulation de fichiers
#include "SD_MMC.h"   // carte SD
#include "esp_camera.h" // caméra!

// écrivez le nom et le mot de passe de votre réseau WIFI
const char* ssid     = "Jetevois";
const char* password = "300480Dav,";

WebServer server(80);

static bool cartePresente = true;

int numero_fichier = 0; // numéro de la photo (nom du fichier)

int brochePIR = 13; // capteur PIR branché à la broche GPIO13.


// prise de la photo et création du fichier jpeg

void enregistrer_photo (void)
{
  char adresse[20] = ""; // chemin d'accès du fichier .jpeg
  camera_fb_t * fb = NULL; // frame buffer

  // prise de la photo
  fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Echec de la prise de photo.");
    return;
  }

  numero_fichier = numero_fichier + 1;

  // enregitrement du fichier sur la carte SD

  sprintf (adresse, "/%d.jpg", numero_fichier);

  fs::FS &fs = SD_MMC;
  File file = fs.open(adresse, FILE_WRITE);

  if (!file) {
    Serial.println("Echec lors de la creation du fichier.");
  }
  else {
    file.write(fb->buf, fb->len); // payload (image), payload length
    Serial.printf("Fichier enregistre: %s\n", adresse);
  }
  file.close();
  esp_camera_fb_return(fb);

}

void returnOK() {
  server.send(200, "text/plain", "");
}

void returnFail(String msg) {
  server.send(500, "text/plain", msg + "\r\n");
}

// Affichage d'un fichier présent sur la carte
bool loadFromSdCard(String path) {
  String dataType = "text/plain";

  if (path == "/") {
    printDirectory();
  }
  else {

    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";
    }

    fs::FS &fs = SD_MMC;

    File dataFile = fs.open(path.c_str());

    if (!dataFile) {
      return false;
    }

    if (server.hasArg("download")) {
      dataType = "application/octet-stream";
    }

    if (server.streamFile(dataFile, dataType) != dataFile.size()) {
      Serial.println("Sent less data than expected!");
    }

    dataFile.close();

  }
  return true;
}


// utilisé lors de la suppression d'un fichier
void deleteRecursive(String path) {

  fs::FS &fs = SD_MMC;
  File file = fs.open((char *)path.c_str());
  if (!file.isDirectory()) {
    file.close();
    fs.remove((char *)path.c_str());
    return;
  }

  file.rewindDirectory();
  while (true) {
    File entry = file.openNextFile();
    if (!entry) {
      break;
    }
    String entryPath = path + "/" + entry.name();
    if (entry.isDirectory()) {
      entry.close();
      deleteRecursive(entryPath);
    } else {
      entry.close();
      fs.remove((char *)entryPath.c_str());
    }
    yield();
  }

  fs.rmdir((char *)path.c_str());
  file.close();
}

// suppression d'un fichier

void handleDelete() {

  fs::FS &fs = SD_MMC;

  if (server.args() == 0) {
    return returnFail("Mauvais arguments?");
  }
  String path = server.arg(0);
  if (path == "/" || !fs.exists((char *)path.c_str())) {
    returnFail("BAD PATH");
    return;
  }
  deleteRecursive(path);

  // on affiche un message de confirmation
  server.setContentLength(CONTENT_LENGTH_UNKNOWN);

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

  WiFiClient client = server.client();

  server.sendContent("<h1>Le fichier a &eacute;t&eacute; supprim&eacute;</h1>");
  server.sendContent("<p><a href = / > Retour &agrave; la liste des fichiers </a></p>");

}

// Affichage du contenu de la carte
void printDirectory() {

  fs::FS &fs = SD_MMC;
  String path = "/";

  File dir = fs.open((char *)path.c_str());
  path = String();
  if (!dir.isDirectory()) {
    dir.close();
    return returnFail("PAS UN REPERTOIRE");
  }
  dir.rewindDirectory();
  server.setContentLength(CONTENT_LENGTH_UNKNOWN);

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

  WiFiClient client = server.client();

  server.sendContent("<h1>Contenu de la carte SD</h1>");

  for (int cnt = 0; true; ++cnt) {
    File entry = dir.openNextFile();
    if (!entry) {
      break;
    }

    String output;

    output += "<a href = ";
    output += entry.name();
    output += "> ";
    output += entry.name();

    // on ajoute un bouton delete:
    output += "</a> &nbsp; &nbsp;  &nbsp; &nbsp; <a href = /delete?url=";
    output += entry.name();
    output += "> [Supprimer] </a> <br>";

    server.sendContent(output);
    entry.close();
  }
  dir.close();
}

// on tente d'afficher le fichier demandé. Sinon, message d'erreur
void handleNotFound() {
  if (cartePresente && loadFromSdCard(server.uri())) {
    return;
  }
  String message = "Carte SD non detectee ou action imprevue\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " NAME:" + server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  Serial.print(message);
}

void setup(void) {

  // définition des broches de la caméra pour le modèle AI Thinker - ESP32-CAM
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = 5;
  config.pin_d1 = 18;
  config.pin_d2 = 19;
  config.pin_d3 = 21;
  config.pin_d4 = 36;
  config.pin_d5 = 39;
  config.pin_d6 = 34;
  config.pin_d7 = 35;
  config.pin_xclk = 0;
  config.pin_pclk = 22;
  config.pin_vsync = 25;
  config.pin_href = 23;
  config.pin_sscb_sda = 26;
  config.pin_sscb_scl = 27;
  config.pin_pwdn = 32;
  config.pin_reset = -1;

  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;  //YUV422|GRAYSCALE|RGB565|JPEG
  config.frame_size = FRAMESIZE_VGA;  // QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
  config.jpeg_quality = 10;  // 0-63 ; plus bas = meilleure qualité
  config.fb_count = 2; // nombre de frame buffers

  // initialisation de la caméra
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Echec de l'initialisation de la camera, erreur 0x%x", err);
    return;
  }

  sensor_t * s = esp_camera_sensor_get();

  // connexion au WIFI

  Serial.begin(115200);
    Serial.println("\n[*] Creating AP");
    WiFi.mode(WIFI_AP);
    WiFi.softAP(ssid, password);
    Serial.print("[+] AP Created with IP Gateway ");
    Serial.println(WiFi.softAPIP());

  uint8_t i = 0;
  while (WiFi.status() != WL_CONNECTED && i++ < 20) {//wait 10 seconds
    delay(500);
  }
  if (i == 21) {
    Serial.print("Impossible de se connecter au reseau ");
    Serial.println(ssid);
    while (1) {
      delay(500);
    }
  }
  Serial.print("Connecte a l'adresse IP: ");
  Serial.println(WiFi.localIP());

  // initialisation du web server
  server.on("/delete", HTTP_GET, handleDelete);
  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println("Serveur HTTP en fonction.");

  // initialisation de la carte micro SD
  // en mode 1 bit: plus lent, mais libère des broches
  if (SD_MMC.begin("/sdcard", true)) {
    uint8_t cardType = SD_MMC.cardType();
    if (cardType != CARD_NONE) {
      Serial.println("Carte SD Initialisee.");
      cartePresente = true;
    }
  }

  pinMode(brochePIR, INPUT);
}

void loop(void) {
  server.handleClient();

  if (digitalRead(brochePIR)) {
    enregistrer_photo();
    Serial.print("Nouvelle photo!  ");
    Serial.println(numero_fichier);
    delay(300);
  }

}

Pour info, j'ai soudé des fils sur l'esp pour connecter le PIR, un fils sur la broche d13 relié sur le out du pir, un sur le gnd et un autre sur vcc
Merci d'avance pour votre aide

Lorsque tu crées un réseau WIFI en AP, l'adresse IP est consultable par WiFi.softAPIP().

Ce code n'a pas sa place ici.
Il ne sert à rien de savoir si WiFi.status() retourne WL_CONNECTED ou pas, étant donné que l'ESP32 ne cherche pas à se connecter à un réseau existant, puisque tu le configures en AP. De même WiFi.localIP() retournera systématiquement 0.0.0.0, pour la même raison.

Si tu copies/colles un code sans comprendre ce qu'il fait, cela ne sert pas à grand chose.

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