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

Une autre question
Comment les cde et infos sont configurer dans jeedom ? Espeasy ?

Par script pour les entrées/sorties (led / GPIO12). Voir l’en-tête du code .ino pour les paramètres du script.
Pas d’ESPEasy puisque c’est du code compilé en direct.

Comme le dit @Theduck38
tu peut manipuler ces commandes depuis ton jeedom a l’aide du pulugin script
ou depuis un scénario

ex:
Capture d’écran du 2020-05-22 16-17-16

Attention néanmoins dans tes commandes de script il te faudra ajuster l’adresse IP à celle de ta caméra…

Tiens, j’ai une question concernant les récupérations d’états sur un script… comment fais-tu ?

Il faut appeler le « refresh » du script pour avoir des états à jour… tu passes par un scénario qui rafraîchit toutes les xx minutes chaque commande, ou l’auto-actualisation du script dans l’onglet « équipement » ?

Dans le cas présenté en exemple puisque c’est le même équipement il se trouve rafraîchi a chaque action ou au refresh

Dans un scénario tu peut demandé l’état sans passer par un plugin-script

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 »

:ok_hand:
Bon boulot ! c’est OK pour moi (+ led OK mais pas testé le GPIO hormis etat qui est cohérent)

:grin: Je croyais que tu allais sortir une version avec tous les param de gestion cam en param optionels d’une url de params

http://192.168.1.x/params?RESOLUTION=FRAMESIZE_CIF?QUALITY=10?BRIGHT=1?WHITEBAL=0...

Mais là j’exagère peut-être :thinking:

Je suis pas sur que ce soit interessant en ligne de commande mais pourquoi pas ?

pour tester le gpio il te suffit ou d’une voltmetre ou d’une led …

A mettre entre GND et IO12 tu doit trouvé 0 ou 3 volts.

Yes ça je maîtrise pas l’utilité sur cette cam. Merci

Cela avait été demandé en début de post pour avoir un contact sec il faut bien sur ajouter un relais …

Super, j’ai mis à jour le post avec les bibliothèques et la version actuelle.

Concernant le relais, c’était pour pouvoir commander un filtre IR si j’ai bien compris, voire déclencher de l’éclairage led IR pour une caméra nocturne. C’est un sujet que je ne maîtrise pas du tout (filtre IR, pas filtre etc…), mais ça pourrait être intéressant ; d’autant que les caméras devraient être directement compatibles.

J’ai tout commandé pour tester. Relais, les ir… Des que ça arrive je teste et vous dit.

Salut à tous,
Cela fait quelques temps que je cherchais un code fonctionnel, super et merci pour le boulot.

Une remarque sur la commande snapshot, c’est la photo n-1 qui remonte quand on sollicite url.

Par ailleurs, est-ce une limitation technique de ne pas avoir implémenté la maj via http ?
C’est très pratique quand l’objet est en production :wink:

A+

Comme je l’ait dit C arduino n’est pas vraiment ma tasse de tea …
Il faut que je travaille sur une base MicroPython la ce sera beaucoup plus simple de faire de la MAJ à distance en ligne …
patience !

Pour ma part, je ne suis pas un expert de la prog, mais je suis plus à l’aise en arduino donc en C :crazy_face:

J’essaie de le faire mais avec déjà tout ces serveurs web, j’ai peur de mettre la grouille.
A+

Oui, j’ai dû l’indiquer quelque part dans le tuto… pas trouvé pourquoi.

en tout cas olive, super taf !!!

je serais aussi preneur si possible de la possiblité de couper les divers flux manuellement , dans l’optique d’économiser des ressources (si ça a un impact)

perso, le flux HTTP ne m’interesse pas du tout car j’utiliserais seulement le flux RTSP et les snapshots pour jeedom + tinyCAM monitor

encore merci pour le partage !

Bonjour,
j’essaye de reflashé mes esp32 pour les mettre sur la nouvelle version mais impossible de compiler.
j’ai bien un dossier libraries avec les bon dossier 1.8
j’ai bien le dossier ESP32_RTSP_Cam_v1.8
Tout ceci dans document arduino.
j’ai supprimer tous l’ancienne version pour éviter les conflits.

voici les messsages d’erreurs.

In file included from C:\Users\EDC292\Documents\Arduino\libraries\AutoConnect-master\src/AutoConnectAux.h:22:0,

             from C:\Users\EDC292\Documents\Arduino\libraries\AutoConnect-master\src/AutoConnect.h:34,

Plusieurs bibliothèque trouvées pour « WiFi.h »
Utilisé : C:\Users\EDC292\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\libraries\WiFi
Non utilisé : C:\Program Files (x86)\Arduino\libraries\WiFi
from C:\Users\EDC292\Documents\Arduino\ESP32_RTSP_Cam_v1.8\ESP32_RTSP_Cam_v1.8.ino:60:

C:\Users\EDC292\Documents\Arduino\libraries\AutoConnect-master\src/AutoConnectElement.h:15:25: fatal error: ArduinoJson.h: No such file or directory

compilation terminated.

exit status 1
Erreur de compilation pour la carte ESP32 Wrover Module

il te faut rajouter la librairies arduinojson j’ai l’inpression
et autoconnect

j’ai ça :
Capture d’écran du 2020-05-25 12-57-03

Dallas et MAX a mon avis pas nécessaire