Source file: /~heha/ewa/Ofen/Kamera.zip/Kamera.ino

/*********
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-cam-video-streaming-web-server-camera-home-assistant/
  
  IMPORTANT!!! 
   - Select Board "AI Thinker ESP32-CAM"
   - GPIO 0 must be connected to GND to upload a sketch
   - After connecting GPIO 0 to GND, press the ESP32-CAM on-board RESET button to put your board in flashing mode
Anpassung an tuc-special sowie Allgemeinfall
(nicht so'n Murks mit dem Eincompilieren von SSID+Passphrase):
-Videotyp an URL
*********/

#define BOARD_HAS_PSRAM

#include <esp_camera.h>
#include <WiFi.h>
#include <esp_timer.h>
#include <img_converters.h>
#include <Arduino.h>
#include <fb_gfx.h>
#include <soc/soc.h> //disable brownout problems
#include <soc/rtc_cntl_reg.h>  //disable brownout problems
#include <esp_http_server.h>
#include <Preferences.h>
#include "input.h"

#define PART_BOUNDARY "123456789000000000000987654321"

static httpd_handle_t stream_httpd;

static esp_err_t stream_handler(httpd_req_t *req) {
 Serial.println("Stream-Handler startet.");
 esp_err_t res = httpd_resp_set_type(req,"multipart/x-mixed-replace;boundary=" PART_BOUNDARY);
 while (res == ESP_OK){
  camera_fb_t*fb = esp_camera_fb_get();
  if (!fb) {
   Serial.println("Camera capture failed");
   res = ESP_FAIL;
   break;
  }
  size_t jpg_buf_len = 0;
  byte*jpg_buf = 0;
  if (fb->width > 400){
   if (fb->format != PIXFORMAT_JPEG){
    bool jpeg_converted = frame2jpg(fb, 80,&jpg_buf, &jpg_buf_len);
    esp_camera_fb_return(fb);
    fb = 0;
    if (!jpeg_converted){
     Serial.println("JPEG compression failed");
     res = ESP_FAIL;
     break;
    }
   }
  }
  jpg_buf_len = fb->len;
  jpg_buf = fb->buf;
  char part_buf[64];
  size_t hlen = snprintf(part_buf,sizeof part_buf,
    "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n",
    jpg_buf_len);
  if (res == ESP_OK) res=httpd_resp_send_chunk(req,part_buf,hlen);
  if (res == ESP_OK) res=httpd_resp_send_chunk(req,reinterpret_cast<char*>(jpg_buf),jpg_buf_len);
  static const char STREAM_BOUNDARY[] = "\r\n--" PART_BOUNDARY "\r\n";
  if (res == ESP_OK) res=httpd_resp_send_chunk(req,STREAM_BOUNDARY,strlen(STREAM_BOUNDARY));
  if (fb) esp_camera_fb_return(fb);
  else free(jpg_buf);
    //Serial.printf("MJPG: %uB\n",(uint32_t)(jpg_buf_len));
 };
 Serial.println("Stream-Handler beendet.");
 return res;
}

void startCameraServer(){
  httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  config.server_port = 80;

  httpd_uri_t index_uri = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = stream_handler,
    .user_ctx  = 0
  };
  
  //Serial.printf("Starting web server on port: '%d'\n", config.server_port);
  if (httpd_start(&stream_httpd, &config) == ESP_OK) {
    httpd_register_uri_handler(stream_httpd, &index_uri);
  }
}

static Preferences preferences;

void setup() {
// Wer/was auch immer noch etws VORHER in die Konsole kritzelt ...
 WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
 
 Serial.begin(115200);
 Serial.setDebugOutput(false);
  
 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; 
  
 if (psramFound()){
  Serial.println("Kamerainitialisierung mit PSRAM, 1600x1200");
  config.frame_size = FRAMESIZE_UXGA; // 1600x1200, kommt aber nicht an!
  config.jpeg_quality = 10;
  config.fb_count = 2;
 } else {
  Serial.println("Kamerainitialisierung ohne PSRAM, 800x600");
  config.frame_size = FRAMESIZE_SVGA; // 800x600, das kommt an! Kein PSRAM? Sollte drauf sein!
  config.jpeg_quality = 12;
  config.fb_count = 1;
 }
  
  // Camera init
 esp_err_t err = esp_camera_init(&config);
 if (err != ESP_OK) {
  Serial.printf("Camera init failed with error 0x%X", err);
  return;
 }
// WLAN-Verbindung
 char ssid[64], password[64];
 auto queryCredentials=[&]() {
  Serial.println("\e[6n");  // Cursorposition abfragen und Cursor nach links zurück
  char answer[16];
  size_t alen=0;
  for (auto tic=millis();millis()-tic<100;) {
   auto c=Serial.read();
   if (c>=0) answer[alen++]=c;    
  }
  isTerm=!!alen;  // Wenn Antwort dann Terminal (putty) sonst dummer Arduino Serial Monitor
  if (isTerm) Serial.print("\e[4m");  // unterstreichen
  Serial.print("WLAN-Infrastruktur-Zugang muss konfiguriert werden!");
  if (isTerm) Serial.print("\e[m"); // unterstreichen aus
  Serial.println();
  int n = WiFi.scanNetworks();
  for (int i = 0; i < n; ++i) {
   for (int j=0; j<i; j++) {
    if (WiFi.encryptionType(j)==WiFi.encryptionType(i)
    && WiFi.SSID(j).equals(WiFi.SSID(i))) goto already;
   }
   Serial.print(WiFi.encryptionType(i) == WIFI_AUTH_OPEN?"🔓":"🔒");  // 🔐 wenn Schlüssel vorhanden
   Serial.println(WiFi.SSID(i));
already:;
  }
  Serial.print("Diese MAC-Adresse: ");
  Serial.println(WiFi.macAddress());
// strcpy(ssid,"tuc-special");  // Vorgabe für TU Chemnitz
  do{
   input("WLAN-Netzwerkname",ssid,sizeof ssid);
   input(" Zugangsschlüssel",password,sizeof password);
  }while (!*ssid);
  Serial.println("Angaben werden gespeichert.");
  preferences.putString("ssid",ssid);
  preferences.putString("password",password);
 };
 preferences.begin("credentials");
 preferences.getString("ssid",ssid,sizeof ssid);
 preferences.getString("password",password,sizeof password);
 if (!*ssid) queryCredentials();
 WiFi.mode(WIFI_STA);
 for(;;) {
  WiFi.disconnect();
  WiFi.begin(ssid, password);
  char intime=20; // 10 Sekunden
  do{
   if (WiFi.status() == WL_CONNECTED) break;
   Serial.print(".");
   delay(500);
  }while(--intime);
  if (intime) break;
  Serial.println(" Zeitüberschreitung!");
  queryCredentials();
 }
 Serial.println();
 Serial.println("Verbindung mit WLAN-Router hergestellt.");
  
 Serial.print("Kamera bereit! Bild im Browser durch Aufruf von: ");
 if (isTerm) Serial.print("\e[1m"); // fett
 Serial.print("http://");
 Serial.print(WiFi.localIP());
 Serial.print("/");
 if (isTerm) Serial.print("\e[m");  // fett aus
 Serial.println();
  // Start streaming web server
 startCameraServer();
}

void loop() {
 switch (Serial.read()) {
  case 'C'-'@': preferences.clear(); //nobreak
  case 'R'-'@': setup(); // ^R wirkt wie Reset
 }
 delay(1);
}
Detected encoding: UTF-80