Bonjour, je vais vous parler de la réalisation d'une caméra de surveillance avec l'aide d'un module ESP32-CAM. Cette caméra vous permettra de recevoir des mails avec une capture d'image lorsque que le capteur PIR est activé.

Voici en quelques lignes les fonctionnalitée principales:

 

- Streaming vidéo en rtsp grâce à la bibliothèque Micro-RTSP de geeksville. Possibilité d'activer un accès web

- Possibilité de connecter la caméra à Surveillance station d'un NAS Synology.

- Interface Web de paramétrage.

- Envoi de mails horodatés d'alerte avec une capture d'image lors d'une détection par le capteur PIR. Grâce à la bibliothèque ESP32-MAIL-CLIENT de Mobizt

- Détection jour/nuit.

-Relais static Omron 2 ampéres, pour une lampe de courtoisie.

- Interface web update.

Cet objet permet une bonne approche dans le domaine de l'image, du service web embarqué, de l'envoi d'email, l'utilisation d'un serveur NTP  et le système de mise à jour en ligne.

Vous trouverez dans la suite de cet article toutes les informations nécessaires à sa réalisation. Il faudra retoucher un réglage dans l librairie Micro-RTSP pour fiabiliser le fonctionnement.

La fluidité reste à améliorer ainsi que le boitage, si vous avez une solution merci à vous de la partager ;-) 

Ici le dossier complet à jour:

 

Sommaire

 

1-Utilisation et configuration

2-Les caractéristiques techniques

3-Le matériel utilisé

4-Le schéma électrique et son PCB

5-Les fichiers 3D pour le boîtage.

6-Les codes de programmations


 

1-Utilisation et configuration:

Lorsque la caméra ne peut pas se connecter à un réseau elle ouvre un portail d'accès. Cela va vous permettre de configurer vos paramètres wifi. Il vous suffira de vous connecter sur le SSID InnoGreenTech puis d'accéder à la page du portail de configuration, http://192.168.4.1/indexhtml

Notez soigneusement l'adresse MAC de l'appareil, cela vous permettra de retrouver son adresse IP avec un scanner comme celui de colasoft par exemple: https://www.colasoft.com/mac_scanner/ 

présentation du SSID innogreentech

  Portail de configuration wifi

Je vous conseille de lui réserver une adresse grâce à votre serveur DHCP, ainsi la caméra récupérera toujours la même adresse.. Vous pouvez accéder à sa page d'accueil à l'adresse htpp://xxx.xxx.xxx.xxx/index.html.

Vous y trouverez un menu pour mettre à jour l'appareil ou configurer l'envoi des mails.  Le menue permet aussi d'accéder à la mise à jour de la caméra.

Page d'accueil de la Caméra ESP32-cam

La page de configuration des mails se divise en deux parties. La première permet de configurer le serveur d'envoi, la seconde les informations, tel que l'objet et le nom de l'expéditeur.

Il faut ensuite  redémarrer la caméra pour que les modifications soient actives.

Réglage des mails

 Pour simplifier la mise à jour de la caméra, j'ai implémenté un service OTA, pour qu'il fonctionne il faut compiler le programme avec une partition OTA. Pour générer le fichier .bin il suffit d'exporter les binaires compilées depuis l'onglet croquis. Vous   retrouverez le fichier dans votre répertoir de travail.

 Une fenêtre d'identification est demandée avant de pouvoir faire la mise jour. Les identifiants sont inscrits en dur dans le programme (admin,admin). Ensuite vous n'avez plus qu'à choisir le fichier.

logging pour update Formulaire de téléchargement du fichier update

Vous pouvez tester votre configuration sur la page d'accueil.

 2-Les caractéristiques techniques :

-Streaming RTSP pour vidéo surveillance

-Possibilité d'un accé web à la caméra: https://github.com/geeksville/Micro-RTSP/blob/master/examples/ESP32-devcam.ino

 

 

3-Le matériel utilisé :

ESP32 CAM

-Un module d'alimentation  5 Volts 800 ma:

Alimentation 800ma

 -Une photorésistance 

LDR 1000x750

 -un capteur Pir HC-SR501

HC SR501

 -Un optocoupleur

PC817

 -Deux fusibles de protection

Fuse 2amp-Deux résistances de 220 Ohms et une de 5000 Ohms

-Six bornes de connexion au pas de 5,08 mm

Bornier

 

 4-Schémas et PCB :

        Le schéma et le PCB sont réalisés avec Kicad, http://www.kicad-pcb.org :

        - vous pouvez télécharger, le projet c'est ici: Projet Kicad de la caméra ESP32-CAM

PCB

Schema

Si tout comme moi vous utilisez la gravure pour votre PCB je vous joins les GCODE. Attention il y a une inversion entre le + et le moins de l'alimentation.

Je réalise le GCODE grace à FlatCAM, http://flatcam.org/ : Ici les fichiers GCODE pour votre CNC

gravure pcb

 

5-Le boîtage en impression 3D :

 

 boitier camera

 

 

6-Les codes de programmation  :

    .frame_size = FRAMESIZE_XGA, // needs 96K or even smaller FRAMESIZE_SVGA - can work if using only 1 fb
    //.frame_size = FRAMESIZE_SVGA,
    .jpeg_quality = 10, //0-63 lower numbers are higher quality
    .fb_count = 2// if more than one i2s runs in continous mode.  Use only with jpeg

 

Ici le programme principal avec son setup, j'espère que les commentaires sauront vous aider à sa compréhension

/************************************************************************************
    
    <ESP32-CAM contrl. This a camera with a PIR sensor. It can detect body and send a email>
    Copyright (C) <2019>  <Fabrice BAUDIN>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

    Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.

****************************************************************************************/


#include "OV2640.h"
#include <WiFi.h>
#include <WebServer.h>
#include <WiFiClient.h>
#include <TimeLib.h>
#include <NtpClientLib.h>
#include <ESP32_MailClient.h>
#include "SimStreamer.h"
#include "OV2640Streamer.h"
#include "CRtspSession.h"
#include "soc/soc.h"           // Disable brownour problems
#include "soc/rtc_cntl_reg.h"  // Disable brownour problems*





#include <EEPROM.h> // Gestion de la mémoire de type eeprom pour la sauvegarde des choix
#include <Update.h>



/* define memory adress */

#define ALARME_EEPROM   0   // Addresse de mémorisations des alarmes
#define NAME_MODULE     1   //Name of module
#define ADRESS_SERVER   22  // adress of server php
#define PORT_SERVER     43  // Port of server
#define PERIOD          50  // Period to send datas in seconds
#define MEM_SSID        70
#define MEM_PASSWORD    170


int           period;                // period to sent datas
char          name_module[20];       // name of module
String        ref_module = "camera";          // référence du module
String        version_module = "V1";      // version of module
char          ip_server[15];         // adress ip of the module
int unsigned  port_server;           // port of server
String        local_mac;             // adress mac of the module
String        local_ip;              // adress ip of module

byte movement = 0;
byte activation_alarmes = 0; // Mot utilisé pour l'activation des alarmes
byte alarmes_actives = 1;   // Drapeau d'une alarme active
byte enableServer = 1 ;     // Use to control if the parameters are good
String reception;             // Variable pour la réception sur le port série
int code;                     // Variable code pour l'échange d'information

int nbenvois = 0;         //nombre d'envoi de mail





unsigned long  lastmessage;         // heures d'envoi des derniers relevés
unsigned long  millisecondes;       // Intervalle des relevés en millisecondes
//int nb_cycle_lost_wifi=0;

String ssid = "";
String password = "";

/* Set web server */

WebServer server(80);

/* Set update server */

const char* update_path = "/firmware";
const char* update_username = "admin";
const char* update_password = "admin";


/* Set mail server */
#define MEM_USER_MAIL 200
#define MEM_PASSWORD_MAIL 260
#define MEM_SMTP_MAIL     320
#define MEM_PORT_MAIL     380
#define MEM_SENDER_MAIL   390
#define MEM_RECIPIENTS_MAIL 450
#define MEM_SUBJECT_MAIL  580
#define MEM_USER          640

SMTPData smtpData;

char user_mail[60] = "";
char user[60] = "";
char password_mail[60] = "";
char recipients_mail[230] = "";
char recipient_mail[60] = "";
char message_mail[500] = "";
char sender_mail[60] = "";
char smtp_mail[60] = "";
char port_mail[10] = "";
char subject_mail[60] = "";
int  portint;
int  freint;

void sendCallback(SendStatus info);

/*set cam*/

OV2640 cam;

/* set rtspServer */
WiFiServer rtspServer(8554);

/*Set PWM Light */
const int freq = 5000;
const int ledChannel = 0;
const int finess = 8;
const int light = 4;




void setup()
{

  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
  // configure LED PWM functionalitites
  ledcSetup(ledChannel, freq, finess);

  // attach the channel to the GPIO to be controlled
  ledcAttachPin(light, ledChannel);

  pinMode(13, INPUT);
  pinMode(14, INPUT);
  pinMode(2, OUTPUT);
  //attachInterrupt(13, move_detect, RISING);




  EEPROM.begin(1024);                              // allocations  de 512 adresses Mémoires

  activation_alarmes = EEPROM.read(ALARME_EEPROM); // lecture du réglage des alarmes

  /* read connection configuration */

  char carac = '1'; // Name of module
  int a = 0;
  while (!(carac == '\0') && a < 20) {
    carac = char (EEPROM.read(NAME_MODULE + a));
    reception += carac;
    a++;
  }
  if (reception == '\0' || a == 20) {
    reception = F("InnoGreenTech");
  }
  int c = reception.length() + 1;                               // longueur de la chaîne de caractéres
  reception.toCharArray(name_module, c);

  reception = "";  // read memory ip adress server
  carac = '1';
  a = 0;
  while (!(carac == '\0') && a < 20) {
    carac = char (EEPROM.read(ADRESS_SERVER + a));
    reception += carac;
    a++;
  }
  if (reception == '\0' || a == 20) {
    reception = F("InnoGreenTech");
    enableServer = 0;
  }
  c = reception.length() + 1;
  reception.toCharArray(ip_server, c);

  byte mem[2];
  for (int a = 0; a < 3; a++) {
    mem[a] = EEPROM.read(PORT_SERVER + a); // load the port server
  }
  port_server = mem[0] | mem[1] << 8;


  for (int a = 0; a < 3; a++) {
    mem[a] = EEPROM.read(PERIOD + a); // load the time period
  }
  period = mem[0] | mem[1] << 8;
  millisecondes = period * 1000;


  carac = '1';
  a = 0;
  while (!(carac == '\0') && a < 100) {
    carac = char (EEPROM.read(MEM_SSID + a));  //récupération du lien d'information
    if (!(carac == '\0')) {
      ssid += carac;
    } a++;
  }
  if (ssid == '\0' || a > 50) {
    ssid = F("");
  }

  carac = '1';
  a = 0;
  while (!(carac == '\0') && a < 100) {
    carac = char (EEPROM.read(MEM_PASSWORD + a));  //récupération du lien d'information
    if (!(carac == '\0')) {
      password += carac;
    } a++;
  }
  if (password == '\0' || a > 50) {
    password = F("");
  }

  /* read mail configuration */

  reception = "";
  carac = '1';
  a = 0;
  while (!(carac == '\0') && a < 60) {
    carac = char (EEPROM.read(MEM_SENDER_MAIL + a));
    reception += carac;
    a++;
  }
  if (reception == '\0' || a == 60) {
    reception = F("Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.");
  }
  c = reception.length() + 1;
  reception.toCharArray(user_mail, c);

  reception = "";
  carac = '1';
  a = 0;
  while (!(carac == '\0') && a < 60) {
    carac = char (EEPROM.read(MEM_USER + a));
    reception += carac;
    a++;
  }
  if (reception == '\0' || a == 60) {
    reception = F("InnoGreenTech");
  }
  c = reception.length() + 1;
  reception.toCharArray(user, c);

  reception = "";
  carac = '1';
  a = 0;
  while (!(carac == '\0') && a < 60) {
    carac = char (EEPROM.read(MEM_PASSWORD_MAIL + a));
    reception += carac;
    a++;
  }
  if (reception == '\0' || a == 60) {
    reception = F("****");
  }
  c = reception.length() + 1;
  reception.toCharArray(password_mail, c);

  reception = "";
  carac = '1';
  a = 0;
  while (!(carac == '\0') && a < 60) {
    carac = char (EEPROM.read(MEM_SMTP_MAIL + a));
    reception += carac;
    a++;
  }
  if (reception == '\0' || a == 60) {
    reception = F("smtp.fr");
  }
  c = reception.length() + 1;
  reception.toCharArray(smtp_mail, c);

  reception = "";
  carac = '1';
  a = 0;
  while (!(carac == '\0') && a < 230) {
    carac = char (EEPROM.read(MEM_RECIPIENTS_MAIL + a));  //
    reception += carac;
    a++;
  }
  if (reception == '\0' || a == 230) {
    reception = F("Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.");
  }
  c = reception.length() + 1;
  reception.toCharArray(recipients_mail, c);


  reception = "";
  carac = '1';
  a = 0;
  while (!(carac == '\0') && a < 60) {
    carac = char (EEPROM.read(MEM_SENDER_MAIL + a));  //
    reception += carac;
    a++;
  }
  if (reception == '\0' || a == 60) {
    reception = F("Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.");
  }
  c = reception.length() + 1;
  reception.toCharArray(sender_mail, c);


  reception = "";
  carac = '1';
  a = 0;
  while (!(carac == '\0') && a < 60) {
    carac = char (EEPROM.read(MEM_SUBJECT_MAIL + a));
    reception += carac;
    a++;
  }
  if (reception == '\0' || a == 60) {
    reception = F("Présence détectée"); //
  }
  c = reception.length() + 1;
  reception.toCharArray(subject_mail, c);

  reception = "";
  carac = '1';
  a = 0;
  while (!(carac == '\0') && a < 4) {
    carac = char (EEPROM.read(MEM_PORT_MAIL + a));
    reception += carac;
    a++;
  }
  if (reception == '\0' || a == 4) {
    reception = F("587");
  }
  c = reception.length() + 1;
  reception.toCharArray(port_mail, c);
  portint = reception.toInt();


  Serial.begin(115200);
  while (!Serial)
  {
    ;
  }
  /*

    /* Start cam */
  cam.init(esp32cam_aithinker_config);



  /*Connexion wifi*/

  WiFi.mode(WIFI_STA);

  c = ssid.length() + 1;
  char char_ssid[50];
  ssid.toCharArray(char_ssid, c);

  c = password.length() + 1;
  char char_password[50];
  password.toCharArray(char_password, c);

  WiFi.begin(char_ssid, char_password);

  unsigned long time_out_connection = millis();
  while (WiFi.status() != WL_CONNECTED)
  {
    if (millis() - time_out_connection > 20000)
    {
      Serial.println F("");
      Serial.println F ("connection Wifi fail !");

      break;
    }
    delay(100);
    Serial.print('-');
  }

  if ( WiFi.status() != WL_CONNECTED) // Portail de connexion
  {
    Serial.println F ("Open setting gate !");
    WiFi.disconnect();
    WiFi.mode(WIFI_AP);
    delay(200);
    WiFi.softAP("InnoGreenTech", "innogreentech");
    server.on ( "/index.html", handleRoot );    // go to set up wifi page
    delay(100);
    server.on ("/style.css", cssRoot);
    local_mac = WiFi.macAddress();
    delay(100);
    server.begin();

  }

  else

  {

    Serial.print ( "IP address: " ); Serial.println ( WiFi.localIP() );


    /*Configuration de la synchronisation de l'heure */

    NTP.begin("pool.ntp.org", 1, true);  //configuration de la récupération de la date,  Serveur+1 heure, Heure été/hivers
    NTP.setInterval(3600);                // Toute les heures

    delay(2000);


    /*informations du module*/

    local_ip = WiFi.localIP().toString().c_str();
    local_mac = WiFi.macAddress(); 
    ref_module = "camera";
    version_module = "V1";

    Serial.print(F("référence:")); Serial.println(ref_module);
    Serial.print(F("Version:")); Serial.println(version_module);
    Serial.print(F("Adresse IP:")); Serial.println(local_ip);
    Serial.print(F("Adresse MAC:")); Serial.println(local_mac);
    Serial.println(WiFi.gatewayIP());
    Serial.println(WiFi.dnsIP(1));

    /* Configuration du serveur Web */

    server.on ( "/index.html", indexRoot );    // Renvoi à la page de index
    delay(100);
    server.on ( "/", indexRoot );    // Renvoi à la page de index
    delay(100);
    //server.on ( "/add_module.csv", add_module );    // Page to add or modify  module by php server
    //delay(100);
    server.on ( "/set_mail.html", set_mail );    // Page to set mail configuration
    delay(100);
    server.on ("/style.css", cssRoot);     // envoi au fichier de configuration de style
    delay(100);

    /*return index page which is stored in serverIndex */
    server.on("/firmware", HTTP_GET, update_login);
    server.on("/serverIndex", HTTP_GET, update_index);

    /*handling uploading firmware file */

    server.on("/update", HTTP_POST, update_error, update_file);
    server.begin();
    rtspServer.begin();

  }
}
CStreamer *streamer;
CRtspSession *session;
WiFiClient client;

void loop()
{



  server.handleClient();

  /* Gest detection movement*/
  if (digitalRead(14) and (digitalRead(13) | digitalRead(2) ))
  {
    ledcWrite(ledChannel, 5);
    digitalWrite(2, 1);
  }
  else {
    ledcWrite(ledChannel, 0);
    digitalWrite(2, 0);
  }
  if (!digitalRead(14))
  {
    alarmes_actives = 0;
  }
  if (digitalRead(14) == 1 and alarmes_actives == 0 and activation_alarmes == 1)
  {
    delay(1000);
    Serial.println("Envoi d'une image");
    alarmes_actives = 1;
    send_mail();
  }





  uint32_t msecPerFrame = 200;
  static uint32_t lastimage = millis();

  // If we have an active client connection, just service that until gone
  // (FIXME - support multiple simultaneous clients)
  if (session) {
    session->handleRequests(0); // we don't use a timeout here,
    // instead we send only if we have new enough frames

    uint32_t now = millis();
    if (now > lastimage + msecPerFrame || now < lastimage) { // handle clock rollover
      session->broadcastCurrentFrame(now);
      lastimage = now;

      // check if we are overrunning our max frame rate
      now = millis();
      if (now > lastimage + msecPerFrame)
        printf("warning exceeding max frame rate of %d ms\n", now - lastimage);
    }

    if (session->m_stopped) {
      delete session;
      delete streamer;
      session = NULL;
      streamer = NULL;
    }
  }
  else {
    client = rtspServer.accept();

    if (client) {
      //streamer = new SimStreamer(&client, true);             // our streamer for UDP/TCP based RTP transport
      streamer = new OV2640Streamer(&client, cam);             // our streamer for UDP/TCP based RTP transport
      session = new CRtspSession(&client, streamer); // our threads RTSP session and state
    }
  }

}

void move_detect() 
{
             movement=1;

}

      Ici le css utilisé pour les pages web de configuration de la caméra:

void cssRoot(){
   server.send ( 200, "text/css", cssPage() );   // envoi de la page
  }

String cssPage(){

String page =F("body{display: flex;flex-direction: row;font-family: Arial,sans-serif;color: rgb(72,11,08);}");
       page +=F("h1{text-align: center;font-size: 1.5em; font-weight: bold;}");
       page +=F("h2{text-align: center;font-size: 0.9em;font-weight: bold;}");
       page +=F("h3{text-align: center;font-size: 0.8em;font-weight: bold;}");
       page +=F("#menu li{display: block;}");
       page +=F("#menu{display: flex;flex-direction: column;align-content: space-between;}");
       page +=F("nav li{background-color: rgb(211,218,234);padding: 3px;margin: 5px;border-radius: 10px;box-shadow: 6PX 6PX 6PX silver;}");
       page +=F("nav a{font-size: 1.5em;font-weight: bold;text-decoration: none;color: rgb(72,11,08);}");
       page +=F("#page{width:88%;display: flex;flex-direction: column;}");
       page +=F("header{padding: 2%;margin: 1%;background-color: rgb(211,218,234);border-radius: 10px;box-shadow: 6PX 6PX 6PX silver;}");
       page +=F("#corp{ display: flex;flex-direction: row;flex-wrap: wrap;}");
       page +=F("footer a{color: rgb(148,58,61);}");     
       page +=F("section {width:44%; display: block; background-color:rgb(211,218,234);; padding:2%;margin:1%; border-radius:10px; box-shadow:6PX 6PX 6PX silver;}");
       page +=F("footer{margin:auto;}");     
       page +=F("ul{list-style-type: none;}");
       page +=F("form{text-align: center;}");
       page +=F("@media all and  (orientation: portrait){body{flex-direction: column;} #corp{flex-direction:column;} section{width: 94%;} #menu{display: flex;flex-direction: row;flex-wrap: wrap;justify-content: space-around;}}");
       //page +=F("@media all and  (max-device-width: 480px){body{flex-direction: column;} #corp{flex-direction:column;} section{width: 94%;} #menu{display: flex;flex-direction: row;flex-wrap: wrap;justify-content: space-around;}}");

return page;

}

           Page d'accueil du service web:

void indexRoot(){
              if ( server.hasArg("envoi")) 
              {      
                send_mail();
              } 
               server.send ( 200, "text/html", indexPage() );   // envoi de la page
                }
  


String indexPage(){
                    String page =F("<!DOCTYPE html> <html lang=fr-FR> <head> <meta charset='utf-8'><link rel='stylesheet'type='text/css'href='style.css'><title>Caméra de surveillance</title></head>");
                           page +=F("<body>");
                           page +=F("<nav> <ul id='menu'><li><a href='index.html'> Accueil </a></li><li><a href='firmware'> Update </a></li><li><a href='set_mail.html'> Mails </a> </li></ul></nav>");
                           page +=F("<div id='page'>");
                           page +=F("<header><h1>Caméra de surveillance </h1></header>");
                           page +=F("<div id='corp'>");
                           page +=F("<section id='datedujour'><h2>");
                           page +=NTP.getDateStr();
                           page +=F("</h2><h3>");
                           page +=NTP.getTimeStr();
                           page +=F("</h3>");
                           page +=F("<ul><li>Serveur:");
                           page +=ip_server;
                           page +=F("</li><li> Port serveur:");
                           page +=port_server;
                           page +=F("</li><li> Adresse MAC:");
                           page +=local_mac;
                           page +=F("</li><li> Version:");
                           page +=version_module;
                           page +=F("</li></ul></section>");
                           page +=F("<section id='capteur1'><h2> Envoi capture par mail</h2><ul>");
                           page +=F("<li><form method='get'><input type='hidden' name='envoi' value='1'/><input type='submit' value='capture'/>");                      
                           page +=F("</form></li></ul></section>");
                           page +=F("</div>");
                           page +=F("<footer><a href='http://www.Innogreentech.fr'>InnoGreenTech </a><a href='mailto: Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.'>Contactez moi</a></footer>");
                           page +=F("</div></body></html>");                  
                           return page;
                          }

         Partie du programme permettant d'envoyer un email:

void send_mail(){

      /*set configuration of mail*/

      smtpData.setLogin(smtp_mail,portint,user_mail,password_mail);
      smtpData.setSender(user,user_mail);
      smtpData.setPriority("High");
      smtpData.setSubject(subject_mail);
      
      
      /*Create the Body of the mail*/

      String corp=F("<!DOCTYPE html><html><head><meta charset=''utf-8'/></head><body>");
      corp +=F("<p>Bonjour</p>");
      corp +=F("<p>Une présence a été détectée :</p>");
      corp +=F("<ul>");
      corp +=F("<li>Date: "); corp +=NTP.getDateStr();corp +=F(" </li>");
      corp +=F("<li>Heure: "); corp +=NTP.getTimeStr();corp +=F(" </li>");
      corp +=F("</ul>");
      corp+=F("<p>Cordialement</p>");
      corp+=F("<a href='http://www.innogreentech.fr'>InnoGreenTech</a></body></html>"); 
      int y = corp.length() + 1;
      corp.toCharArray(message_mail,y);

      smtpData.setMessage(message_mail,true);

     /* Add every recipients */ 

      char c='1';  
      int a=0;
      int b=0;
      while (!( c=='\0')&&a<250){
                                c=recipients_mail[a];
                                if (c==';'||c=='\0'){
                                    recipient_mail[b]='\0';
                                    smtpData.addRecipient(recipient_mail);
                                    b=0;
                                    }
                                else {   
                                    recipient_mail[b]=c;
                                    b++;
                                     }                       
                                a++;                                         
                                }
      
    /* Add picture of the camera */ 

      cam.run();
     smtpData.addAttachData("capture.jpeg", "image/jpeg", cam.getfb(), cam.getSize());

   /*send email and clear memory*/
      smtpData.setSendCallback(sendCallback);
      if (!MailClient.sendMail(smtpData))
      Serial.println("Error sending Email, " + MailClient.smtpErrorReason());
      smtpData.empty();


}
void sendCallback(SendStatus msg)
{
  //Print the current status
  Serial.println(msg.info());

  //Do something when complete
  if (msg.success())
  {
    Serial.println("----------------");
  }
}

  

        Portail de configuration wifi InnoGreenTech

void handleRoot(){ 

      /* Pour réglage SSID */
      
      if ( server.hasArg("SSID") ) {       // si reception 
      ssid=server.arg("SSID");
      int c = ssid.length() + 1;         // longueur de la chaîne de caractéres
      for (int i = 0; i < c; i++) { 
                                  EEPROM.write((i+MEM_SSID),ssid[i]);  // Réglage du pointeur sur l'adresse mémoire
                                  }                       
      } 

      /*if ( server.hasArg("set_temp") ) {       // si reception 
      ssid=server.arg("seuil");
      int c = ssid.length() + 1;         // longueur de la chaîne de caractéres
      for (int i = 0; i < c; i++) { 
                                  EEPROM.write((i+MEM_SET_TEMP),ssid[i]);  // Réglage du pointeur sur l'adresse mémoire
                                  }                    
      } */
      
      if ( server.hasArg("PASSWORD") ) {       // si reception 
      password=server.arg("PASSWORD");
      int c = password.length() + 1;         // longueur de la chaîne de caractéres
      for (int i = 0; i < c; i++) { 
                                  EEPROM.write((i+MEM_PASSWORD),password[i]);  // Réglage du pointeur sur l'adresse mémoire
                                  }
             EEPROM.commit();     // Enregistrement dnas la mémoire flash
             delay (500);
             ESP.restart();
                                                               
      } 
      
               
       server.send ( 200, "text/html", page_handleroot() );   // envoi de la page
    }
  


String page_handleroot(){
  String page =F("<!DOCTYPE html> <html lang=fr-FR> <head> <meta charset='utf-8'><link rel='stylesheet'type='text/css'href='style.css'><title>Afficheur</title></head>"); 
         page +=F("<body>");
         
        

         page +=F("<section id='configuration'>");
         page +=F("<h2> Configuration de la connexion wifi</h2>"); 
         page +=F("<form method='get' accept='' >");

         page +=F("<p>adresse MAC: ");
         page +=local_mac;
         page +=F("<p/>");
         
         page +=F("<br/>");
         page +=F("<br/>");
                  
         page += F("<label>SSID: </label><br/>");
         page += F("<input type='texte' name='SSID' id='SSID' maxlength='45' value='");page +=ssid; page +=F("' />");
         
         page +=F("<br/>");
         page +=F("<br/>");
                  
         page += F("<label>Password: <br/></label>");
         page += F("<input type='password' name='PASSWORD' id='PASSWORD' maxlength='45' />");
         
         page +=F("<br/>");
         page +=F("<br/>"); 
                 
                
         page += F("<input type='submit'  value='Envoi'>");
         page += F("</p>");
         page += F("</form>");
         page += F("</section>");
     
         
         page +=F("</div>");
         page +=F("<footer><a href='http://www.innogreentech.fr'>InnoGreenTech</a><br/><a href='mailto: Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.'>Contactez moi</a></footer>");
         page +=F("</div></body></html>");

return page;
}

        Page de configuration de l'envoi de mail.

void set_mail() {

  /* active alarm mail */
  
  if ( server.hasArg("MAIL") ) {       
      reception=server.arg("MAIL");
      if (reception.equals("1")) {activation_alarmes=1;}
      else {activation_alarmes=0;}                 
      EEPROM.write(ALARME_EEPROM, activation_alarmes);
  }

  
  /* mail sender setting */
  
  if ( server.hasArg("MAILEXP") ) {       
    reception = server.arg("MAILEXP");
    int c = reception.length() + 1; 
    reception.toCharArray(sender_mail, c);        
    for (int i = 0; i < c; i++) { 
                                   EEPROM.write((i+MEM_SENDER_MAIL),sender_mail[i]);
                                  }
  }


  /* Password mail setting */
  
  if ( server.hasArg("PW") ) {              
     reception= server.arg("PW");
     int c = reception.length() + 1;         
     reception.toCharArray(password_mail, c);
     for (int i = 0; i < c; i++) { 
                                  EEPROM.write((i+MEM_PASSWORD_MAIL),password_mail[i]);
                                  }
    }

  /* SMTP mail setting */

  if ( server.hasArg("SMTP") ) {       
     reception= server.arg("SMTP");
     int c = reception.length() + 1;        
     reception.toCharArray(smtp_mail, c);
     for (int i = 0; i < c; i++) { 
                                  EEPROM.write((i+MEM_SMTP_MAIL),smtp_mail[i]); 
                                  }
  }

  /* PORT mail setting */

  if ( server.hasArg("PORT") ) {      
    reception = server.arg("PORT");
    int c = reception.length() + 1; 
    reception.toCharArray(port_mail, c);
    portint=reception.toInt();            
    for (int i = 0; i < c; i++) { 
                                   EEPROM.write((i+MEM_PORT_MAIL),port_mail[i]);  
                                  }
    EEPROM.commit();
  }

    /* User mail setting */
  
  if ( server.hasArg("USER") ) {       
     reception= server.arg("USER");
     int c = reception.length() + 1;         
     reception.toCharArray(user, c);
     for (int i = 0; i < c; i++) { 
                                  EEPROM.write((i+MEM_USER_MAIL),user[i]);
                                  }
    }
    
  /* Recipients setting */
  
  if ( server.hasArg("MAILDEST") ) {       // si reception
    reception = server.arg("MAILDEST");
    int c = reception.length() + 1; 
    reception.toCharArray(recipients_mail, c);        
    for (int i = 0; i < c; i++) { 
                                   EEPROM.write((i+MEM_RECIPIENTS_MAIL),recipients_mail[i]);
                                  }
  }

  /* Subject setting */
  
  if ( server.hasArg("MAILOBJ") ) {       
    reception = server.arg("MAILOBJ");
    int c = reception.length() + 1; 
    reception.toCharArray(subject_mail, c);        
    for (int i = 0; i < c; i++) { 
                                   EEPROM.write((i+MEM_SUBJECT_MAIL),subject_mail[i]);
                                  }

    EEPROM.commit();     // Enregistrement
    }


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




String mailPage() {
  String  page =F("<!DOCTYPE html> <html lang=fr-FR> <head> <meta charset='utf-8'><link rel='stylesheet'type='text/css'href='style.css'><title>Caméra de surveillance</title></head>");
          page += F("<body>");
          page += F("<nav><ul id='menu'><li><a href='index.html'> Accueil </a></li><li><a href='firmware'> Update </a> </li><li><a href='set_mail'> Mails </a> </li></ul></nav>");
          page += F("<div id='page'><header><h1>Réglage des mails</h1></header>");
          page += F("<div id='corp'><section id='serveur'><h2> Serveur d'envoi</h2><form method='post' accept='' ><p>");
          page += F("<label>Activation des alarmes</label>");
          page += F("<input type='radio' name='MAIL'  value='1' required />");
          page += F("<br/>");
          page += F("<br/>");
          page += F("<label>Désactivations des alarmes</label>");
          page += F("<input type='radio' name='MAIL'  value='0' />");
          page += F("<br/>");
          page += F("<br/>");
          page += F("<label>Mail boîte d'envoi</label>");
          page += F("<input type='mail' name='MAILEXP' id='MAILEXP' value='");page +=user_mail; page +=F("' maxlength='60'/>");
          page += F("<br/>");
          page += F("<br/>");
          page += F("<label>Mots de passe:</label>");
          page += F("<input type='password' name='PW' id='PW' maxlength='60'required/>");
          page += F("<br/>");
          page += F("<br/>");
          page += F("<label>Serveur SMTP:</label>");
          page += F("<input type='text' name='SMTP'value='");page +=smtp_mail; page +=F("' id='SMTP'maxlength='60'/>");
          page += F("<br/>");
          page += F("<br/>");
          page += F("<label>Port:</label>");
          page += F("<input type='number' name='PORT' id='PORT' max='1000' value=' ");page +=port_mail; page +=F("'/>");
          page += F("<br/>");
          page += F("<br/>");
          page += F("<input type='submit'  value='Envoi'>");
          page += F("</p>");
          page += F("</form>");
          page += F("</section>");
          page += F("<section id='Destinataire'>");
          page += F("<h2> Destinataires:</h2>");
          page += F("<form method='post' accept='' >");
          page += F("<p>");
          page += F("<label>Nom de l'expéditeur:</label>");
          page += F("<input type='text' name='USER' id='USER' value='");page +=user; page +=F(" ' maxlength='60' />");
          page += F("<br/>");
          page += F("<br/>");
          page += F("<label>Destinataires:</label>");
          page += F("<input type='mail' name='MAILDEST' id='MAILDEST' value='");page +=recipients_mail; page +=F(" ' maxlength='230' />");
          page += F("<br/>");
          page += F("<br/>");
          page += F("<label>Objet:</label>");
          page += F("<input type='mail' name='MAILOBJ' id='MAILOBJ' value='");page +=subject_mail; page +=F(" ' maxlength='60' />");
          page += F("<br/>");
          page += F("<br/>");
          page += F("<input type='submit'  value='Envoi'>");
          page += F("</p>");
          page += F("</form>");
          page += F("</section>");
          page += F("</div>");
          page += F("<footer>");
          page += F("<a href='http://www.innogreentech.fr'>InnoGreenTech </a>");
          page += F("<a href='mailto: Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.'>Contactez moi</a>");
          page += F("</footer>");
          page += F("</div>");
          page += F("</body>");
          page += F("</html>");


  return page;
}

       Programme  pour mettre à jour le module ESP32

void update_login()
{
  const char* loginIndex = 
 "<form name='loginForm'>"
    "<table width='20%' bgcolor='A09F9F' align='center'>"
        "<tr>"
            "<td colspan=2>"
                "<center><font size=4><b>ESP32 Login Page</b></font></center>"
                "<br>"
            "</td>"
            "<br>"
            "<br>"
        "</tr>"
        "<td>Username:</td>"
        "<td><input type='text' size=25 name='userid'><br></td>"
        "</tr>"
        "<br>"
        "<br>"
        "<tr>"
            "<td>Password:</td>"
            "<td><input type='Password' size=25 name='pwd'><br></td>"
            "<br>"
            "<br>"
        "</tr>"
        "<tr>"
            "<td><input type='submit' onclick='check(this.form)' value='Login'></td>"
        "</tr>"
    "</table>"
"</form>"
"<script>"
    "function check(form)"
    "{"
    "if(form.userid.value=='admin' && form.pwd.value=='admin')"
    "{"
    "window.open('/serverIndex')"
    "}"
    "else"
    "{"
    " alert('Error Password or Username')/*displays error message*/"
    "}"
    "}"
"</script>";

server.sendHeader("Connection", "close");
server.send ( 200, "text/html", loginIndex );
}
/*
 * Server Index Page
 */
void update_index()
{ 
const char* serverIndex = 
"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
   "<input type='file' name='update'>"
        "<input type='submit' value='Update'>"
    "</form>"
 "<div id='prg'>progress: 0%</div>"
 "<script>"
  "$('form').submit(function(e){"
  "e.preventDefault();"
  "var form = $('#upload_form')[0];"
  "var data = new FormData(form);"
  " $.ajax({"
  "url: '/update',"
  "type: 'POST',"
  "data: data,"
  "contentType: false,"
  "processData:false,"
  "xhr: function() {"
  "var xhr = new window.XMLHttpRequest();"
  "xhr.upload.addEventListener('progress', function(evt) {"
  "if (evt.lengthComputable) {"
  "var per = evt.loaded / evt.total;"
  "$('#prg').html('progress: ' + Math.round(per*100) + '%');"
  "}"
  "}, false);"
  "return xhr;"
  "},"
  "success:function(d, s) {"
  "console.log('success!')" 
 "},"
 "error: function (a, b, c) {"
 "}"
 "});"
 "});"
 "</script>";
server.sendHeader("Connection", "close");
 server.send(200, "text/html", serverIndex);
}
void update_error()
              {
                server.sendHeader("Connection", "close");
                server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
                ESP.restart();
              }

void update_file()

                {   
                  HTTPUpload& upload = server.upload();
                  if (upload.status == UPLOAD_FILE_START) {
                  Serial.printf("Update: %s\n", upload.filename.c_str());
                  if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
                    Update.printError(Serial);
                  }
                } else if (upload.status == UPLOAD_FILE_WRITE) {
                  /* flashing firmware to ESP*/
                  if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
                    Update.printError(Serial);
                  }
                } else if (upload.status == UPLOAD_FILE_END) {
                  if (Update.end(true)) { //true to set the size to the current progress
                    Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
                  } else {
                    Update.printError(Serial);
                  }
                }
                }

      

Veuillez vous connecter ou créer un compte pour pouvoir poster un commentaire.