[TUTO] Caméra à focale fixe basée sur ESP32

Je vous laisse découvrir …

CODE V1.8
//---------------------------------------------------------------------------------------------------------------------
// DOCS UTILES:
// ------------
// SERVEUR WEB CAM: https://community.jeedom.com/t/tuto-camera-a-focale-fixe-basee-sur-esp32/17587/49
// LED WIFI: https://techtutorialsx.com/2018/02/03/esp32-arduino-async-server-controlling-http-methods-allowed/
// Installing Asyncwebserver: https://techtutorialsx.com/2017/12/01/esp32-arduino-asynchronous-http-webserver/
// IMAGE PARAMS: https://randomnerdtutorials.com/esp32-cam-ov2640-camera-settings/
// @drs
// modified @olive v1.71 jeudi 21 mai 2020 21h27
//
// PARAMETRES A MODIFIER:
// ----------------------
// RESOLUTION: FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA / QUALITY (10-63)
// WSPORT: port  web (pour affichage images)
// ASYNCPORT: port AsyncWebServer (pour gestion LED)
// Paramètres image
//
// USAGE:
// ------
// http://ip-esp:WSPORT/                page d'accueil
// http://ip-esp:WSPORT/_ac             page de config
// http://ip-esp:WSPORT/mjpg:           stream
// http://ip-esp:WSPORT/snapshot.jpg    image
//
// GESTION DE LA LED:
// ------------------
// http://ip-esp:ASYNCPORT/led           Etat de la led (format binaire)
// http://ip-esp:ASYNCPORT/led/on        Allume la LED
// http://ip-esp:ASYNCPORT/led/off       Eteint la LED
// http://ip-esp:ASYNCPORT/led/toggle    Allume/Eteint la LED
//
// GESTION DU GPIO12:
// ------------------
// http://ip-esp:ASYNCPORT/gpio12           Etat du gpio2 (format binaire)
// http://ip-esp:ASYNCPORT/gpio12/on        Allume gpio12
// http://ip-esp:ASYNCPORT/gpio12/off       Eteint gpio12
// http://ip-esp:ASYNCPORT/gpio12/toggle    Allume/Eteint gpio12
//
// INTEGRATION JEEDOM:
// -------------------
// Plugin Camera:
// Laisser le type de camera sur "Aucun"
// Renseigner l'IP et le port (webserver)
// URL de snapshot:   /snapshot.jpg
// URL de flux:       /mjpg
//
// Script gestion led:
// Action/Default
// URL: voir ci-dessus
// Cocher "Pas d'erreurs"
// La réponse doit contenir: ok (en minuscule)
// Timeout: si besoin (pas nécessaire)
//
//---------------------------------------------------------------------------------------------------------------------

#include <WiFi.h>
#include <WebServer.h>
#include <ESPAsyncWebServer.h>  //permet la connexion simultanee pour la gestion de la LED
#include <WiFiClient.h>
#include <AutoConnect.h>        // Needs AutoConnect, PageBuilder libraries!
#include "soc/soc.h"            //disable brownout problems
#include "soc/rtc_cntl_reg.h"  //disable brownout problems
#include "esp_camera.h"        // Pas sur de l'utilité. A vérifier

#define ENABLE_RTSPSERVER
#define ENABLE_WEBSERVER
#define RESOLUTION  FRAMESIZE_CIF   // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
#define QUALITY        10           // JPEG quality 10-63 (lower means better quality)

// PARAMETRES IMAGE
#define BRIGHT    1           // Brightness: -2 to 2
#define CONTRAST  0           // Contrast: -2 to 2
#define SATUR     0           // Color Saturation: -2 to 2
#define SPECIAL   0           // Special effects: 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)
#define WHITEBAL  1           // White Balance: 0 = disable , 1 = enable
#define AWBGAIN   1           // White Balance Gain: 0 = disable , 1 = enable
#define AWBMODE   3           // White Balance Mode: 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
#define EXPOS     1           // Exposure Control: 0 = disable , 1 = enable
#define AEC2      0           // 0 = disable , 1 = enable
#define AELEV     0           // -2 to 2
#define AECVAL    300         // 0 to 1200
#define GAINCT    1           // 0 = disable , 1 = enable
#define GAINAGC   0           // 0 = disable , 1 = enable
#define GAINCELL  0           // 0 = disable , 1 = enable
#define BPC       0           // 0 = disable , 1 = enable
#define WPC       1           // 0 = disable , 1 = enable
#define RAWGMA    1           // 0 = disable , 1 = enable
#define LENC      1           // Lens Correction: 0 = disable , 1 = enable
#define MIRROR    0           // Horizontal Mirror: 0 = disable , 1 = enable
#define FLIP      0           // Vertical Flip: 0 = disable , 1 = enable
#define DCW       1           // 0 = disable , 1 = enable
#define CBAR      0           // Set a colorBar: 0 = disable , 1 = enable

#define LED_BUILTIN 4         // VA SERVIR POUR ALLUMER et ETEINDRE LA LED - NE PAS MODIFIER CETTE VALEUR (GPIO4)

#include "OV2640.h"
#ifdef ENABLE_RTSPSERVER
 #include "OV2640Streamer.h"
 #include "CRtspSession.h"
#endif

OV2640 cam;
boolean useRTSP = true;

#define WSPORT  80                // modifier le port pour Webserver Image
#define ASYNCPORT  81             // modifier le port pour Webserver LED
WebServer server(WSPORT); 
AsyncWebServer serverasync(ASYNCPORT);
AutoConnect Portal(server);
AutoConnectConfig acConfig;



#ifdef ENABLE_RTSPSERVER
WiFiServer rtspServer(554);
CStreamer *streamer;
#endif



void handle_jpg_stream(void)
{
  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)
  {
    cam.run();
    if (!client.connected())
      break;
    response = "--frame\r\n";
    response += "Content-Type: image/jpeg\r\n\r\n";
    server.sendContent(response);

    client.write((char *)cam.getfb(), cam.getSize());
    server.sendContent("\r\n");
    if (!client.connected())
      break;
  }
}

void handle_jpg(void)
{
  WiFiClient client = server.client();
  cam.run();
  if (!client.connected())
  {
    return;
  }
  String response = "HTTP/1.1 200 OK\r\n";
  response += "Content-disposition: inline; filename=snapshot.jpg\r\n";
  response += "Content-type: image/jpeg\r\n\r\n";
  server.sendContent(response);
  client.write((char *)cam.getfb(), cam.getSize());
  
}

void handle_root(void)
{
  String reply ="<!doctype html>\
  <style type=text/css>\
  body {\
  background-color: #272727; \
  }\
  <style>\
  th, td {\
  border: 1px solid black;\
  background-color: #FFFF00; \
  }\
  table {\
  border-collapse: collapse;\  
  background-color: #00AA00; \
  }\
  a {\
   color: red; \  
  }\
  </style>";
  reply +=F("<html><head><meta charset='UTF-8'></head><table><tr><td colspan='2'><H1>ESP32CAM</H1></td></tr>");
  reply +=F("<tr><td>VERSION </td><td>1.8</td></tr>");
  reply += F("<tr><td>Resolution</td>");

  switch(RESOLUTION) {
    case FRAMESIZE_QVGA:
     reply += F("<td>QVGA (320x240)</td>");
    break;
    case FRAMESIZE_CIF:
     reply += F("<td>CIF (400x296)</td>");
    break;
    case FRAMESIZE_VGA:
     reply += F("<td>VGA (640x480)</td>");
    break;
    case FRAMESIZE_SVGA:
     reply += F("<td>SVGA (800x600)</td>");
    break;
    case FRAMESIZE_XGA:
     reply += F("<td>XGA (1024x768)</td>");
    break;
    case FRAMESIZE_SXGA:
     reply += F("<td>SXGA (1280x1024)</td>");
    break;
    case FRAMESIZE_UXGA:
     reply += F("<td>UXGA (1600x1200)</td>");
    break;
    default:
     reply += F("<td>Unknown</td>");
    break;
  }
  
  reply += F("</tr><tr><td>PSRAM found</td>");
  if (psramFound()){
   reply += F("<td>TRUE</td></tr>");
  } else {
   reply += F("<td>FALSE</td></tr></tr>");
  }
  String IP = WiFi.localIP().toString();
  String IPH = "http://" + IP + ":" + WSPORT;
  String IPA = "http://" + IP + ":" + ASYNCPORT;
  String IPR = "rstp://" + IP + ":554";
  
  String url = IPH + "/snapshot.jpg";
  reply += "<tr><td>Snapshot URL</td><td><a href='" + url + "'>" + url + "</a></td></tr>";
  url = IPH + "/mjpg";
  reply += "<tr><td>HTTP MJPEG URL</td><td><a href='" + url + "'>" + url + "</a></td></tr>";
  url =  IPR + "/mjpeg/1";
  reply += "<tr><td>RTSP MJPEG URL</td><td>" + url;
  url =  IPH + "/_ac";
  reply += "<tr><td>WiFi settings page</td><td><a href='" + url + "'>" + url + "</a></td></tr>";

  //LED
  url =  IPA + "/led/on";
  reply += "<tr><td>Led_on</td><td><a href='" + url + "'>" + url + "</a></td></tr>";

  url =  IPA + "/led/off";
  reply += "<tr><td>Led_off</td><td><a href='" + url + "'>" + url + "</a></td></tr>";

  url =  IPA + "/led/toggle";
  reply += "<tr><td>Led_toggle</td><td><a href='" + url + "'>" + url + "</a></td></tr>";

  url =  IPA + "/led";
  reply += "<tr><td>Led_etat</td><td><a href='" + url + "'>" + url + "</a></td></tr>";


  //GPIO12
  url =  IPA + "/gpio12/on";
  reply += "<tr><td>gpio12_on</td><td><a href='" + url + "'>" + url + "</a></td></tr>";

  url =  IPA + "/gpio12/off";
  reply += "<tr><td>gpio12_off</td><td><a href='" + url + "'>" + url + "</a></td></tr>";

  url =  IPA + "/gpio12/toggle";
  reply += "<tr><td>gpio12_toggle</td><td><a href='" + url + "'>" + url + "</a></td></tr>";

  url =  IPA + "/gpio12";
  reply += "<tr><td>gpio12_etat</td><td><a href='" + url + "'>" + url + "</a></td></tr>";
  
  reply += "</table><img src='"+IPH+"/mjpg'>\
  </body></html>";
  server.send(200, "text/html", reply);
}

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

void setup(){

  pinMode(LED_BUILTIN, OUTPUT);       // pour LED
  digitalWrite(LED_BUILTIN, LOW);     // pour LED

  pinMode(12, OUTPUT);       // pour RELAIS SUR GPIO12
  digitalWrite(12, LOW);     // pour RELAIS SUR GPIO12  
  
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector 
  Serial.begin(115200);
  //  while (!Serial){;} // debug only
  camera_config_t cconfig;
  cconfig = esp32cam_aithinker_config;

  if (psramFound()) {
    cconfig.frame_size = RESOLUTION; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
    cconfig.jpeg_quality = QUALITY;
    cconfig.fb_count = 2;
  } else {
    if (RESOLUTION>FRAMESIZE_SVGA) {
     cconfig.frame_size = FRAMESIZE_SVGA;
    }
    cconfig.jpeg_quality = 12;
    cconfig.fb_count = 1;
  }

  cam.init(cconfig);

sensor_t * s = esp_camera_sensor_get();
  s->set_brightness(s, BRIGHT);
  s->set_contrast(s, CONTRAST);
  s->set_saturation(s, SATUR);
  s->set_special_effect(s, SPECIAL);
  s->set_whitebal(s, WHITEBAL);
  s->set_awb_gain(s, AWBGAIN);
  s->set_wb_mode(s, AWBMODE);
  s->set_exposure_ctrl(s, EXPOS);
  s->set_aec2(s, AEC2);
  s->set_ae_level(s, AELEV);
  s->set_aec_value(s, AECVAL);
  s->set_gain_ctrl(s, GAINCT);
  s->set_agc_gain(s, GAINAGC);
  s->set_gainceiling(s, (gainceiling_t)GAINCELL);
  s->set_bpc(s, BPC);
  s->set_wpc(s, WPC);
  s->set_raw_gma(s, RAWGMA);
  s->set_lenc(s, LENC);
  s->set_hmirror(s, MIRROR);
  s->set_vflip(s, FLIP);
  s->set_dcw(s, DCW);
  s->set_colorbar(s, CBAR);

  server.on("/", handle_root);
  server.on("/mjpg", HTTP_GET, handle_jpg_stream);
  server.on("/snapshot.jpg", HTTP_GET, handle_jpg);
  Portal.onNotFound(handleNotFound);
  acConfig.apid = "ESP-" + String((uint32_t)(ESP.getEfuseMac() >> 32), HEX);
  acConfig.psk = "configesp";
  acConfig.apip = IPAddress(192,168,4,1);
  acConfig.hostName = acConfig.apid;
  acConfig.autoReconnect = true;
  Portal.config(acConfig);
  Portal.begin();

  Serial.println(" ");
  Serial.println("Adresse IP: " + WiFi.localIP().toString() );
  Serial.println(" ");

// POUR LED
serverasync.on("/led/off", HTTP_ANY, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", "ok");
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("LED TURNED OFF");
  });
  
  serverasync.on("/led/on", HTTP_ANY, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain","ok");
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.println("LED TURNED ON");
  });
  
  serverasync.on("/led/toggle", HTTP_ANY, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain","ok");
     digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
     Serial.println("LED TURNED TOGGLE");
  });
  
  serverasync.on("/led", HTTP_GET, [](AsyncWebServerRequest *request){
     request->send(200, "text/plain", String(digitalRead(LED_BUILTIN)));
  });



// POUR GPIO 12
serverasync.on("/gpio12/off", HTTP_ANY, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", "ok");
    digitalWrite(12, LOW);
    Serial.println("gpio12 TURNED OFF");
  });
  
  serverasync.on("/gpio12/on", HTTP_ANY, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain","ok");
    digitalWrite(12, HIGH);
    Serial.println("gpio12 TURNED ON");
  });
  
  serverasync.on("/gpio12/toggle", HTTP_ANY, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain","ok");
     digitalWrite(12, !digitalRead(12));
     Serial.println("gpio12 TURNED TOGGLE");
  });
  
  serverasync.on("/gpio12", HTTP_GET, [](AsyncWebServerRequest *request){
     request->send(200, "text/plain", String(digitalRead(12)));
  });
  
  
  serverasync.begin();


#ifdef ENABLE_RTSPSERVER
  if (useRTSP) {
    rtspServer.begin();
    streamer = new OV2640Streamer(cam);             // our streamer for UDP/TCP based RTP transport
  }
#endif
}

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


  
#ifdef ENABLE_RTSPSERVER
  if (useRTSP) {
    uint32_t msecPerFrame = 100;
    static uint32_t lastimage = millis();

    // If we have an active client connection, just service that until gone
    streamer->handleRequests(0); // we don't use a timeout here,
    // instead we send only if we have new enough frames
    uint32_t now = millis();
    if (streamer->anySessions()) {
      if (now > lastimage + msecPerFrame || now < lastimage) { // handle clock rollover
        streamer->streamImage(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);
        }
      }
    }

    WiFiClient rtspClient = rtspServer.accept();
    if (rtspClient) {
      Serial.print("client: ");
      Serial.print(rtspClient.remoteIP());
      Serial.println();
      streamer->addSession(rtspClient);
    }
  }
#endif
}

@Theduck38 tu va devoir corriger le post 7 aussi :wink:

1 « J'aime »