From 152eec7be60723cb7d9789ea2bbcc79a8a6f5fc5 Mon Sep 17 00:00:00 2001 From: Owen Carter Date: Fri, 31 Dec 2021 02:47:58 +0100 Subject: [PATCH 01/16] Framebuffer fix (#199) * Slightly longer flash delay, #188 * Framebuffer delayed frames * Fix Travis, again * show XCLK in dump output * comment on slow XCLK for slow clones * pump up the wifi watchdog default * latest IDE and esp core --- .travis.yml | 12 ++++++------ app_httpd.cpp | 18 ++++++++++++++---- esp32-cam-webserver.ino | 12 ++++++++---- myconfig.sample.h | 6 ++++-- platformio.ini | 3 ++- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index 15b1cc6..f6bdf9b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,15 +15,15 @@ branches: before_script: - "export DISPLAY=:99.0" - sleep 3 # give xvfb some time to start - - wget https://downloads.arduino.cc/arduino-1.8.18-linux64.tar.xz - - tar xf arduino-1.8.18-linux64.tar.xz - - mv arduino-1.8.18 $HOME/arduino_ide + - wget https://downloads.arduino.cc/arduino-1.8.19-linux64.tar.xz + - tar xf arduino-1.8.19-linux64.tar.xz + - mv arduino-1.8.19 $HOME/arduino_ide - cd $HOME/arduino_ide/hardware - mkdir esp32 - cd esp32 - - wget https://github.com/espressif/arduino-esp32/archive/refs/tags/2.0.1.tar.gz - - tar -xzf 2.0.1.tar.gz - - mv arduino-esp32-2.0.1/ esp32 + - wget https://github.com/espressif/arduino-esp32/archive/refs/tags/2.0.2.tar.gz + - tar -xzf 2.0.2.tar.gz + - mv arduino-esp32-2.0.2/ esp32 - cd esp32/tools - python --version - python get.py diff --git a/app_httpd.cpp b/app_httpd.cpp index 5b4c8bd..eeed766 100644 --- a/app_httpd.cpp +++ b/app_httpd.cpp @@ -63,6 +63,7 @@ extern int sketchSpace; extern String sketchMD5; extern bool otaEnabled; extern char otaPassword[]; +extern unsigned long xclkFreqHz; typedef struct { httpd_req_t *req; @@ -140,9 +141,10 @@ void serialDump() { int upSec = sec % 60; int McuTc = (temprature_sens_read() - 32) / 1.8; // celsius int McuTf = temprature_sens_read(); // fahrenheit + float xclk = xclkFreqHz/1000000; Serial.printf("System up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)\r\n", upDays, upHours, upMin, upSec); Serial.printf("Active streams: %i, Previous streams: %lu, Images captured: %lu\r\n", streamCount, streamsServed, imagesServed); - Serial.printf("Freq: %i MHz\r\n", ESP.getCpuFreqMHz()); + Serial.printf("CPU Freq: %i MHz, Xclk Freq: %.1f MHz\r\n", ESP.getCpuFreqMHz(), xclk); Serial.printf("MCU temperature : %i C, %i F (approximate)\r\n", McuTc, McuTf); Serial.printf("Heap: %i, free: %i, min free: %i, max block: %i\r\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap()); if(psramFound()) { @@ -172,7 +174,10 @@ static esp_err_t capture_handler(httpd_req_t *req){ esp_err_t res = ESP_OK; Serial.println("Capture Requested"); - if (autoLamp && (lampVal != -1)) setLamp(lampVal); + if (autoLamp && (lampVal != -1)) { + setLamp(lampVal); + delay(75); // coupled with the status led flash this gives ~150ms for lamp to settle. + } flashLED(75); // little flash of status LED int64_t fr_start = esp_timer_get_time(); @@ -198,12 +203,16 @@ static esp_err_t capture_handler(httpd_req_t *req){ Serial.println("Capture Error: Non-JPEG image returned by camera module"); } esp_camera_fb_return(fb); + fb = NULL; + int64_t fr_end = esp_timer_get_time(); if (debugData) { Serial.printf("JPG: %uB %ums\r\n", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start)/1000)); } imagesServed++; - if (autoLamp && (lampVal != -1)) setLamp(0); + if (autoLamp && (lampVal != -1)) { + setLamp(0); + } return res; } @@ -557,10 +566,11 @@ static esp_err_t dump_handler(httpd_req_t *req){ int upSec = sec % 60; int McuTc = (temprature_sens_read() - 32) / 1.8; // celsius int McuTf = temprature_sens_read(); // fahrenheit + float xclk = xclkFreqHz/1000000; d+= sprintf(d,"Up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)
\n", upDays, upHours, upMin, upSec); d+= sprintf(d,"Active streams: %i, Previous streams: %lu, Images captured: %lu
\n", streamCount, streamsServed, imagesServed); - d+= sprintf(d,"Freq: %i MHz
\n", ESP.getCpuFreqMHz()); + d+= sprintf(d,"CPU Freq: %i MHz, Xclk Freq: %.1f MHz
\n", ESP.getCpuFreqMHz(), xclk); d+= sprintf(d,""); d+= sprintf(d,"MCU temperature : %i °C, %i °F\n
", McuTc, McuTf); d+= sprintf(d,"Heap: %i, free: %i, min free: %i, max block: %i
\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap()); diff --git a/esp32-cam-webserver.ino b/esp32-cam-webserver.ino index 507030d..2ca4b7a 100644 --- a/esp32-cam-webserver.ino +++ b/esp32-cam-webserver.ino @@ -95,7 +95,7 @@ extern void serialDump(); #endif #if !defined(WIFI_WATCHDOG) - #define WIFI_WATCHDOG 8000 + #define WIFI_WATCHDOG 15000 #endif // Number of known networks in stationList[] @@ -137,7 +137,9 @@ char myVer[] PROGMEM = __DATE__ " @ " __TIME__; // Originally: config.xclk_freq_hz = 20000000, but this lead to visual artifacts on many modules. // See https://github.com/espressif/esp32-camera/issues/150#issuecomment-726473652 et al. #if !defined (XCLK_FREQ_HZ) - #define XCLK_FREQ_HZ 16500000; + unsigned long xclkFreqHz = 16500000; +#else + unsigned long xclkFreqHz = XCLK_FREQ_HZ; #endif // initial rotation @@ -522,13 +524,14 @@ void setup() { config.pin_sscb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; - config.xclk_freq_hz = XCLK_FREQ_HZ; + config.xclk_freq_hz = xclkFreqHz; config.pixel_format = PIXFORMAT_JPEG; + config.grab_mode = CAMERA_GRAB_LATEST; // Pre-allocate large buffers if(psramFound()){ config.frame_size = FRAMESIZE_UXGA; config.jpeg_quality = 10; - config.fb_count = 6; // We can be generous since we are not using facedetect anymore, allows for bigger jpeg frame size (data) + config.fb_count = 2; } else { config.frame_size = FRAMESIZE_SVGA; config.jpeg_quality = 12; @@ -638,6 +641,7 @@ void setup() { // check for saved preferences and apply them if (filesystem) { + delay(200); // a short delay to let spi bus settle after camera init filesystemStart(); loadPrefs(SPIFFS); } else { diff --git a/myconfig.sample.h b/myconfig.sample.h index 215f9ec..46bf3fd 100644 --- a/myconfig.sample.h +++ b/myconfig.sample.h @@ -99,9 +99,9 @@ struct station stationList[] = {{"ssid1", "pass1", true}, /* * Wifi Watchdog defines how long we spend waiting for a connection before retrying, * and how often we check to see if we are still connected, milliseconds - * You may wish to increase this if your WiFi is slow at conencting, + * You may wish to increase this if your WiFi is slow at conencting. */ -// #define WIFI_WATCHDOG 8000 +// #define WIFI_WATCHDOG 15000 /* * Over The Air firmware updates can be disabled by uncommenting the folowing line @@ -187,3 +187,5 @@ struct station stationList[] = {{"ssid1", "pass1", true}, // Currently defaults to 16.5MHz, but some (non-clone) modules may be able to use the // original frequency of 20MHz for to allow higher framerates etc. // #define XCLK_FREQ_HZ 20000000; +// For clone modules that have camera module artifacts and SPIFFS issues; try setting this very low: +// #define XCLK_FREQ_HZ 3000000; diff --git a/platformio.ini b/platformio.ini index 624baf5..a8c88b4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,7 +12,8 @@ src_dir = ./ [env:esp32dev] -platform = espressif32 +platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream +platform_packages = framework-arduinoespressif32@https://github.com/espressif/arduino-esp32.git#2.0.2 board = esp32dev board_build.partitions = min_spiffs.csv framework = arduino From 395c4c70bbbc710076e383b6fec2b5959f79b082 Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 31 Dec 2021 10:36:10 +0100 Subject: [PATCH 02/16] Update Version [ci skip] --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 25581dc..453ad7d 100644 --- a/src/version.h +++ b/src/version.h @@ -1,4 +1,4 @@ /* Version of upstream code */ -char baseVersion[] = "4.0.beta2"; +char baseVersion[] = "4.0.beta3"; From 4b6cd9a56ef75c3e744c50b91043bca84f79cd92 Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 31 Dec 2021 11:09:51 +0100 Subject: [PATCH 03/16] Add definition for ArduCAM_ESP32S_UNO [ci skip] --- camera_pins.h | 79 +++++++++++++++++++++++++++++++---------------- myconfig.sample.h | 1 + 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/camera_pins.h b/camera_pins.h index 3853863..68c4284 100644 --- a/camera_pins.h +++ b/camera_pins.h @@ -5,7 +5,33 @@ * Defaults to AI-THINKER CAM module * */ -#if defined(CAMERA_MODEL_WROVER_KIT) +#if defined(CAMERA_MODEL_AI_THINKER) + // + // AI Thinker + // https://github.com/SeeedDocument/forum_doc/raw/master/reg/ESP32_CAM_V1.6.pdf + // + #define PWDN_GPIO_NUM 32 + #define RESET_GPIO_NUM -1 + #define XCLK_GPIO_NUM 0 + #define SIOD_GPIO_NUM 26 + #define SIOC_GPIO_NUM 27 + #define Y9_GPIO_NUM 35 + #define Y8_GPIO_NUM 34 + #define Y7_GPIO_NUM 39 + #define Y6_GPIO_NUM 36 + #define Y5_GPIO_NUM 21 + #define Y4_GPIO_NUM 19 + #define Y3_GPIO_NUM 18 + #define Y2_GPIO_NUM 5 + #define VSYNC_GPIO_NUM 25 + #define HREF_GPIO_NUM 23 + #define PCLK_GPIO_NUM 22 + #define LED_PIN 33 // Status led + #define LED_ON LOW // - Pin is inverted. + #define LED_OFF HIGH // + #define LAMP_PIN 4 // LED FloodLamp. + +#elif defined(CAMERA_MODEL_WROVER_KIT) // // ESP WROVER // https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_SCH-2.pdf @@ -161,32 +187,6 @@ // #define LED_OFF LOW // // #define LAMP_PIN x // LED FloodLamp. -#elif defined(CAMERA_MODEL_AI_THINKER) - // - // AI Thinker - // https://github.com/SeeedDocument/forum_doc/raw/master/reg/ESP32_CAM_V1.6.pdf - // - #define PWDN_GPIO_NUM 32 - #define RESET_GPIO_NUM -1 - #define XCLK_GPIO_NUM 0 - #define SIOD_GPIO_NUM 26 - #define SIOC_GPIO_NUM 27 - #define Y9_GPIO_NUM 35 - #define Y8_GPIO_NUM 34 - #define Y7_GPIO_NUM 39 - #define Y6_GPIO_NUM 36 - #define Y5_GPIO_NUM 21 - #define Y4_GPIO_NUM 19 - #define Y3_GPIO_NUM 18 - #define Y2_GPIO_NUM 5 - #define VSYNC_GPIO_NUM 25 - #define HREF_GPIO_NUM 23 - #define PCLK_GPIO_NUM 22 - #define LED_PIN 33 // Status led - #define LED_ON LOW // - Pin is inverted. - #define LED_OFF HIGH // - #define LAMP_PIN 4 // LED FloodLamp. - #elif defined(CAMERA_MODEL_TTGO_T_JOURNAL) // // LilyGO TTGO T-Journal ESP32; with OLED! but not used here.. :-( @@ -212,6 +212,31 @@ // #define LED_OFF HIGH // // #define LAMP_PIN 4 // LED FloodLamp. +#elif defined(CAMERA_MODEL_ARDUCAM_ESP32S_UNO) + // Pins from user @rdragonrydr + // https://github.com/ArduCAM/ArduCAM_ESP32S_UNO/ + // Based on AI-THINKER definitions + #define PWDN_GPIO_NUM 32 + #define RESET_GPIO_NUM -1 + #define XCLK_GPIO_NUM 0 + #define SIOD_GPIO_NUM 26 + #define SIOC_GPIO_NUM 27 + #define Y9_GPIO_NUM 35 + #define Y8_GPIO_NUM 34 + #define Y7_GPIO_NUM 39 + #define Y6_GPIO_NUM 36 + #define Y5_GPIO_NUM 21 + #define Y4_GPIO_NUM 19 + #define Y3_GPIO_NUM 18 + #define Y2_GPIO_NUM 5 + #define VSYNC_GPIO_NUM 25 + #define HREF_GPIO_NUM 23 + #define PCLK_GPIO_NUM 22 + #define LED_PIN 2 // Status led + #define LED_ON HIGH // - Pin is not inverted. + #define LED_OFF LOW // + //#define LAMP_PIN x // No LED FloodLamp. + #else // Well. // that went badly... diff --git a/myconfig.sample.h b/myconfig.sample.h index 46bf3fd..e463e4b 100644 --- a/myconfig.sample.h +++ b/myconfig.sample.h @@ -182,6 +182,7 @@ struct station stationList[] = {{"ssid1", "pass1", true}, // #define CAMERA_MODEL_M5STACK_WIDE // #define CAMERA_MODEL_M5STACK_ESP32CAM // Originally: CAMERA_MODEL_M5STACK_NO_PSRAM // #define CAMERA_MODEL_TTGO_T_JOURNAL +// #define CAMERA_MODEL_ARDUCAM_ESP32S_UNO // Camera module bus communications frequency, setting too high can cause visual artifacts. // Currently defaults to 16.5MHz, but some (non-clone) modules may be able to use the From de0154779d9bb497546eadbe1b43cfd3320419b3 Mon Sep 17 00:00:00 2001 From: Owen Date: Tue, 8 Mar 2022 11:34:45 +0100 Subject: [PATCH 04/16] Xclock in gui and stream stop button --- app_httpd.cpp | 42 +++++++++++++++++++++++++++++++---------- esp32-cam-webserver.ino | 10 +++++----- index_ov2640.h | 14 ++++++++++++++ index_ov3660.h | 14 ++++++++++++++ myconfig.sample.h | 37 ++++++++++++++++++------------------ src/version.h | 2 +- storage.cpp | 5 +++++ 7 files changed, 90 insertions(+), 34 deletions(-) diff --git a/app_httpd.cpp b/app_httpd.cpp index eeed766..6e75f26 100644 --- a/app_httpd.cpp +++ b/app_httpd.cpp @@ -63,7 +63,7 @@ extern int sketchSpace; extern String sketchMD5; extern bool otaEnabled; extern char otaPassword[]; -extern unsigned long xclkFreqHz; +extern unsigned long xclk; typedef struct { httpd_req_t *req; @@ -78,6 +78,9 @@ static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: % httpd_handle_t stream_httpd = NULL; httpd_handle_t camera_httpd = NULL; +// Flag that can be set to kill all active streams +bool streamKill; + #ifdef __cplusplus extern "C" { #endif @@ -141,10 +144,9 @@ void serialDump() { int upSec = sec % 60; int McuTc = (temprature_sens_read() - 32) / 1.8; // celsius int McuTf = temprature_sens_read(); // fahrenheit - float xclk = xclkFreqHz/1000000; Serial.printf("System up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)\r\n", upDays, upHours, upMin, upSec); Serial.printf("Active streams: %i, Previous streams: %lu, Images captured: %lu\r\n", streamCount, streamsServed, imagesServed); - Serial.printf("CPU Freq: %i MHz, Xclk Freq: %.1f MHz\r\n", ESP.getCpuFreqMHz(), xclk); + Serial.printf("CPU Freq: %i MHz, Xclk Freq: %i MHz\r\n", ESP.getCpuFreqMHz(), xclk); Serial.printf("MCU temperature : %i C, %i F (approximate)\r\n", McuTc, McuTf); Serial.printf("Heap: %i, free: %i, min free: %i, max block: %i\r\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap()); if(psramFound()) { @@ -223,6 +225,8 @@ static esp_err_t stream_handler(httpd_req_t *req){ uint8_t * _jpg_buf = NULL; char * part_buf[64]; + streamKill = false; + Serial.println("Stream requested"); if (autoLamp && (lampVal != -1)) setLamp(lampVal); streamCount = 1; // at present we only have one stream handler, so values are 0 or 1.. @@ -277,7 +281,7 @@ static esp_err_t stream_handler(httpd_req_t *req){ free(_jpg_buf); _jpg_buf = NULL; } - if(res != ESP_OK){ + if((res != ESP_OK) || streamKill){ // This is the only exit point from the stream loop. // We end the stream here only if a Hard failure has been encountered or the connection has been interrupted. break; @@ -341,6 +345,7 @@ static esp_err_t cmd_handler(httpd_req_t *req){ if(s->pixformat == PIXFORMAT_JPEG) res = s->set_framesize(s, (framesize_t)val); } else if(!strcmp(variable, "quality")) res = s->set_quality(s, val); + else if(!strcmp(variable, "xclk")) { xclk = val; res = s->set_xclk(s, LEDC_TIMER_0, val); } else if(!strcmp(variable, "contrast")) res = s->set_contrast(s, val); else if(!strcmp(variable, "brightness")) res = s->set_brightness(s, val); else if(!strcmp(variable, "saturation")) res = s->set_saturation(s, val); @@ -421,6 +426,7 @@ static esp_err_t status_handler(httpd_req_t *req){ p+=sprintf(p, "\"autolamp\":%d,", autoLamp); p+=sprintf(p, "\"framesize\":%u,", s->status.framesize); p+=sprintf(p, "\"quality\":%u,", s->status.quality); + p+=sprintf(p, "\"xclk\":%u,", xclk); p+=sprintf(p, "\"brightness\":%d,", s->status.brightness); p+=sprintf(p, "\"contrast\":%d,", s->status.contrast); p+=sprintf(p, "\"saturation\":%d,", s->status.saturation); @@ -495,7 +501,7 @@ static esp_err_t logo_svg_handler(httpd_req_t *req){ static esp_err_t dump_handler(httpd_req_t *req){ flashLED(75); - Serial.println("\r\nDump Requested via Web"); + Serial.println("\r\nDump requested via Web"); serialDump(); static char dumpOut[2000] = ""; char * d = dumpOut; @@ -566,11 +572,10 @@ static esp_err_t dump_handler(httpd_req_t *req){ int upSec = sec % 60; int McuTc = (temprature_sens_read() - 32) / 1.8; // celsius int McuTf = temprature_sens_read(); // fahrenheit - float xclk = xclkFreqHz/1000000; d+= sprintf(d,"Up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)
\n", upDays, upHours, upMin, upSec); d+= sprintf(d,"Active streams: %i, Previous streams: %lu, Images captured: %lu
\n", streamCount, streamsServed, imagesServed); - d+= sprintf(d,"CPU Freq: %i MHz, Xclk Freq: %.1f MHz
\n", ESP.getCpuFreqMHz(), xclk); + d+= sprintf(d,"CPU Freq: %i MHz, Xclk Freq: %i MHz
\n", ESP.getCpuFreqMHz(), xclk); d+= sprintf(d,""); d+= sprintf(d,"MCU temperature : %i °C, %i °F\n
", McuTc, McuTf); d+= sprintf(d,"Heap: %i, free: %i, min free: %i, max block: %i
\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap()); @@ -590,6 +595,7 @@ static esp_err_t dump_handler(httpd_req_t *req){ // Footer d+= sprintf(d,"
\n"); d+= sprintf(d,"\n"); + d+= sprintf(d,"\n"); d+= sprintf(d,"\n"); d+= sprintf(d,"
\n\n"); // A javascript timer to refresh the page every minute. @@ -601,6 +607,15 @@ static esp_err_t dump_handler(httpd_req_t *req){ return httpd_resp_send(req, dumpOut, strlen(dumpOut)); } +static esp_err_t stop_handler(httpd_req_t *req){ + flashLED(75); + Serial.println("\r\nStream stop requested via Web"); + streamKill = true; + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + return httpd_resp_send(req, NULL, 0); +} + + static esp_err_t style_handler(httpd_req_t *req){ httpd_resp_set_type(req, "text/css"); httpd_resp_set_hdr(req, "Content-Encoding", "identity"); @@ -609,7 +624,7 @@ static esp_err_t style_handler(httpd_req_t *req){ static esp_err_t streamviewer_handler(httpd_req_t *req){ flashLED(75); - Serial.println("Stream Viewer requested"); + Serial.println("Stream viewer requested"); httpd_resp_set_type(req, "text/html"); httpd_resp_set_hdr(req, "Content-Encoding", "identity"); return httpd_resp_send(req, (const char *)streamviewer_html, streamviewer_html_len); @@ -617,7 +632,7 @@ static esp_err_t streamviewer_handler(httpd_req_t *req){ static esp_err_t error_handler(httpd_req_t *req){ flashLED(75); - Serial.println("Sending Error page"); + Serial.println("Sending error page"); std::string s(error_html); size_t index; while ((index = s.find("")) != std::string::npos) @@ -705,7 +720,7 @@ static esp_err_t index_handler(httpd_req_t *req){ void startCameraServer(int hPort, int sPort){ httpd_config_t config = HTTPD_DEFAULT_CONFIG(); - config.max_uri_handlers = 12; // we use more than the default 8 (on port 80) + config.max_uri_handlers = 16; // we use more than the default 8 (on port 80) httpd_uri_t index_uri = { .uri = "/", @@ -767,6 +782,12 @@ void startCameraServer(int hPort, int sPort){ .handler = dump_handler, .user_ctx = NULL }; + httpd_uri_t stop_uri = { + .uri = "/stop", + .method = HTTP_GET, + .handler = stop_handler, + .user_ctx = NULL + }; httpd_uri_t stream_uri = { .uri = "/", .method = HTTP_GET, @@ -817,6 +838,7 @@ void startCameraServer(int hPort, int sPort){ httpd_register_uri_handler(camera_httpd, &favicon_ico_uri); httpd_register_uri_handler(camera_httpd, &logo_svg_uri); httpd_register_uri_handler(camera_httpd, &dump_uri); + httpd_register_uri_handler(camera_httpd, &stop_uri); } config.server_port = sPort; diff --git a/esp32-cam-webserver.ino b/esp32-cam-webserver.ino index 2ca4b7a..c6851cc 100644 --- a/esp32-cam-webserver.ino +++ b/esp32-cam-webserver.ino @@ -134,12 +134,12 @@ unsigned long imagesServed = 0; // Total image requests char myVer[] PROGMEM = __DATE__ " @ " __TIME__; // Camera module bus communications frequency. -// Originally: config.xclk_freq_hz = 20000000, but this lead to visual artifacts on many modules. +// Originally: config.xclk_freq_mhz = 20000000, but this lead to visual artifacts on many modules. // See https://github.com/espressif/esp32-camera/issues/150#issuecomment-726473652 et al. -#if !defined (XCLK_FREQ_HZ) - unsigned long xclkFreqHz = 16500000; +#if !defined (XCLK_FREQ_MHZ) + unsigned long xclk = 16; #else - unsigned long xclkFreqHz = XCLK_FREQ_HZ; + unsigned long xclk = XCLK_FREQ_MHZ; #endif // initial rotation @@ -524,7 +524,7 @@ void setup() { config.pin_sscb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; - config.xclk_freq_hz = xclkFreqHz; + config.xclk_freq_hz = xclk * 1000000; config.pixel_format = PIXFORMAT_JPEG; config.grab_mode = CAMERA_GRAB_LATEST; // Pre-allocate large buffers diff --git a/index_ov2640.h b/index_ov2640.h index f923a21..3baa56b 100644 --- a/index_ov2640.h +++ b/index_ov2640.h @@ -74,6 +74,13 @@ const uint8_t index_ov2640_html[] = R"=====(
High
(slow)
+
+ +
+ +
MHz
+
+
-2
@@ -292,6 +299,7 @@ const uint8_t index_ov2640_html[] = R"=====( const closeButton = document.getElementById('close-stream') const streamLink = document.getElementById('stream_link') const framesize = document.getElementById('framesize') + const xclk = document.getElementById('xclk') const swapButton = document.getElementById('swap-viewer') const savePrefsButton = document.getElementById('save_prefs') const clearPrefsButton = document.getElementById('clear_prefs') @@ -395,6 +403,7 @@ const uint8_t index_ov2640_html[] = R"=====( value = el.checked ? 1 : 0 break case 'range': + case 'number': case 'select-one': value = el.value break @@ -562,6 +571,11 @@ const uint8_t index_ov2640_html[] = R"=====( updateConfig(framesize) } + xclk.onchange = () => { + console.log("xclk:" , xclk); + updateConfig(xclk) + } + swapButton.onclick = () => { window.open('/?view=simple','_self'); } diff --git a/index_ov3660.h b/index_ov3660.h index eb7ca74..9992376 100644 --- a/index_ov3660.h +++ b/index_ov3660.h @@ -76,6 +76,13 @@ const uint8_t index_ov3660_html[] = R"=====(
High
(slow)
+
+ +
+ +
MHz
+
+
-3
@@ -306,6 +313,7 @@ const uint8_t index_ov3660_html[] = R"=====( const closeButton = document.getElementById('close-stream') const streamLink = document.getElementById('stream_link') const framesize = document.getElementById('framesize') + const xclk = document.getElementById('xclk') const swapButton = document.getElementById('swap-viewer') const savePrefsButton = document.getElementById('save_prefs') const clearPrefsButton = document.getElementById('clear_prefs') @@ -407,6 +415,7 @@ const uint8_t index_ov3660_html[] = R"=====( value = el.checked ? 1 : 0 break case 'range': + case 'number': case 'select-one': value = el.value break @@ -571,6 +580,11 @@ const uint8_t index_ov3660_html[] = R"=====( updateConfig(framesize) } + xclk.onchange = () => { + console.log("xclk:" , xclk); + updateConfig(xclk) + } + swapButton.onclick = () => { window.open('/?view=simple','_self'); } diff --git a/myconfig.sample.h b/myconfig.sample.h index e463e4b..4388422 100644 --- a/myconfig.sample.h +++ b/myconfig.sample.h @@ -1,6 +1,6 @@ -/* +/* * Rename this example to 'myconfig.h' and fill in your details. - * + * * The local config is in the '.gitignore' file, which helps to keep details secret. */ @@ -11,7 +11,7 @@ /* * WiFi Settings - * + * * For the simplest connection to an existing network * just replace your ssid and password in the line below. */ @@ -31,18 +31,18 @@ struct station stationList[] = {{"ssid1", "pass1", true}, * it will be used for the AccessPoint ssid and password. See the comments there for more. * * The 'dhcp' setting controls whether the station uses DHCP or static IP settings; if in doubt leave 'true' - * + * * You can also use a BSSID (eg: "2F:67:94:F5:BB:6A", a colon separated mac address string) in place of * the ssid to force connections to specific networks even when the ssid's collide, */ /* Extended WiFi Settings */ -/* +/* * Hostname. Optional, uncomment and set if desired * - used in DHCP request when connecting to networks, not used in AP mode * - Most useful when used with a static netwrk config, not all routers respect this setting - * + * * The URL_HOSTNAME will be used in place of the IP address in internal URL's */ @@ -51,22 +51,22 @@ struct station stationList[] = {{"ssid1", "pass1", true}, /* * Static network settings for client mode - * + * * Note: The same settings will be applied to all client connections where the dhcp setting is 'false' * You must define all three: IP, Gateway and NetMask */ // warning - IP addresses must be separated with commas (,) and not decimals (.) // #define ST_IP 192,168,0,123 -// #define ST_GATEWAY 192,168,0,2 +// #define ST_GATEWAY 192,168,0,2 // #define ST_NETMASK 255,255,255,0 // One or two DNS servers can be supplied, only the NTP code currently uses them // #define ST_DNS1 192,168,0,2 // #define ST_DNS2 8,8,8,8 -/* - * AccessPoint; +/* + * AccessPoint; * - * Uncomment to enable AP mode; + * Uncomment to enable AP mode; * */ // #define WIFI_AP_ENABLE @@ -79,7 +79,7 @@ struct station stationList[] = {{"ssid1", "pass1", true}, * if they are found. AP then works as a fallback mode for when there are no 'real' networks available. * * Setting the 'dhcp' field to true for the AP enables a captive portal and attempts to send - * all visitors to the webcam page, with varying degrees of success depending on the visitors + * all visitors to the webcam page, with varying degrees of success depending on the visitors * browser and other settings. */ // Optionally change the AccessPoint ip address (default = 192.168.4.1) @@ -184,9 +184,10 @@ struct station stationList[] = {{"ssid1", "pass1", true}, // #define CAMERA_MODEL_TTGO_T_JOURNAL // #define CAMERA_MODEL_ARDUCAM_ESP32S_UNO -// Camera module bus communications frequency, setting too high can cause visual artifacts. -// Currently defaults to 16.5MHz, but some (non-clone) modules may be able to use the -// original frequency of 20MHz for to allow higher framerates etc. -// #define XCLK_FREQ_HZ 20000000; -// For clone modules that have camera module artifacts and SPIFFS issues; try setting this very low: -// #define XCLK_FREQ_HZ 3000000; +// Initial Camera module bus communications frequency +// Currently defaults to 8MHz +// The post-initialisation (runtime) value can be set and edited by the user in the UI +// For clone modules that have camera module and SPIFFS startup issues try setting +// this very low (start at 2MHZ and increase): +// #define XCLK_FREQ_MHZ 2 + diff --git a/src/version.h b/src/version.h index 453ad7d..4c68dce 100644 --- a/src/version.h +++ b/src/version.h @@ -1,4 +1,4 @@ /* Version of upstream code */ -char baseVersion[] = "4.0.beta3"; +char baseVersion[] = "4.0.rc1"; diff --git a/storage.cpp b/storage.cpp index 8ebc7fa..8a2644a 100644 --- a/storage.cpp +++ b/storage.cpp @@ -7,6 +7,7 @@ extern void flashLED(int flashtime); extern int myRotation; // Rotation extern int lampVal; // The current Lamp value extern int autoLamp; // Automatic lamp mode +extern int xclk; // Camera module clock speed /* * Useful utility when debugging... @@ -90,8 +91,11 @@ void loadPrefs(fs::FS &fs){ // process all the settings lampVal = jsonExtract(prefs, "lamp").toInt(); autoLamp = jsonExtract(prefs, "autolamp").toInt(); + int xclkPref = jsonExtract(prefs, "xclk").toInt(); + if (xclkPref != 0) xclk = xclkPref; s->set_framesize(s, (framesize_t)jsonExtract(prefs, "framesize").toInt()); s->set_quality(s, jsonExtract(prefs, "quality").toInt()); + s->set_xclk(s, LEDC_TIMER_0, xclk); s->set_brightness(s, jsonExtract(prefs, "brightness").toInt()); s->set_contrast(s, jsonExtract(prefs, "contrast").toInt()); s->set_saturation(s, jsonExtract(prefs, "saturation").toInt()); @@ -138,6 +142,7 @@ void savePrefs(fs::FS &fs){ p+=sprintf(p, "\"autolamp\":%u,", autoLamp); p+=sprintf(p, "\"framesize\":%u,", s->status.framesize); p+=sprintf(p, "\"quality\":%u,", s->status.quality); + p+=sprintf(p, "\"xclk\":%u,", xclk); p+=sprintf(p, "\"brightness\":%d,", s->status.brightness); p+=sprintf(p, "\"contrast\":%d,", s->status.contrast); p+=sprintf(p, "\"saturation\":%d,", s->status.saturation); From 6d825277cfc37cb8a795fdd6f6186c52b5ff10b9 Mon Sep 17 00:00:00 2001 From: Owen Date: Tue, 8 Mar 2022 13:46:51 +0100 Subject: [PATCH 05/16] Fail if no PSRAM, fix #196 --- esp32-cam-webserver.ino | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/esp32-cam-webserver.ino b/esp32-cam-webserver.ino index c6851cc..a0a5290 100644 --- a/esp32-cam-webserver.ino +++ b/esp32-cam-webserver.ino @@ -478,8 +478,6 @@ void WifiSetup() { } void setup() { - // This might reduce boot loops caused by camera init failures when soft rebooting - // See, for instance, https://esp32.com/viewtopic.php?t=3152 Serial.begin(115200); Serial.setDebugOutput(true); Serial.println(); @@ -491,12 +489,21 @@ void setup() { Serial.print("Base Release: "); Serial.println(baseVersion); + // Warn if no PSRAM is detected (typically user error with board selection in the IDE) + if(!psramFound()){ + Serial.println("\r\nFatal Error; Halting"); + while (true) { + Serial.println("No PSRAM found; camera cannot be initialised: Please check the board config for your module."); + delay(5000); + } + } + if (stationCount == 0) { - Serial.println("\r\nFatal Error; Halting"); - while (true) { - Serial.println("No wifi details have been configured; we cannot connect to existing WiFi or start our own AccessPoint, there is no point in proceeding."); - delay(5000); - } + Serial.println("\r\nFatal Error; Halting"); + while (true) { + Serial.println("No wifi details have been configured; we cannot connect to existing WiFi or start our own AccessPoint, there is no point in proceeding."); + delay(5000); + } } #if defined(LED_PIN) // If we have a notification LED, set it to output @@ -747,12 +754,6 @@ void setup() { // As a final init step chomp out the serial buffer in case we have recieved mis-keys or garbage during startup while (Serial.available()) Serial.read(); - // Warn if no PSRAM is detected (typically user error with board selection in the IDE) - if(!psramFound()){ - Serial.printf("\r\nNo PSRAM found.\r\nPlease check the board config for your module.\r\n"); - Serial.printf("High resolution/quality images & streams will show incomplete frames due to low memory.\r\n"); - } - // While in Beta; Warn! Serial.print("\r\nThis is the 4.0 alpha\r\n - Face detection has been removed!\r\n"); } From 9402cdf4b713cb1f9cecb35a9692fd2c12c3e1ea Mon Sep 17 00:00:00 2001 From: Owen Date: Tue, 8 Mar 2022 13:51:56 +0100 Subject: [PATCH 06/16] remove the beta warning --- esp32-cam-webserver.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esp32-cam-webserver.ino b/esp32-cam-webserver.ino index a0a5290..5b46b0f 100644 --- a/esp32-cam-webserver.ino +++ b/esp32-cam-webserver.ino @@ -754,8 +754,8 @@ void setup() { // As a final init step chomp out the serial buffer in case we have recieved mis-keys or garbage during startup while (Serial.available()) Serial.read(); - // While in Beta; Warn! - Serial.print("\r\nThis is the 4.0 alpha\r\n - Face detection has been removed!\r\n"); + // Info line; use for Info messages; eg 'This is a Beta!' warnings, etc. as necesscary + // Serial.print("\r\nThis is the 4.1 beta\r\n"); } void loop() { From 2be6d0bdd20a5f15bfd037bd1dfd3c0c2081891e Mon Sep 17 00:00:00 2001 From: Owen Date: Tue, 8 Mar 2022 14:56:25 +0100 Subject: [PATCH 07/16] Start SPIFFS before camera module, #214 --- esp32-cam-webserver.ino | 8 +++++++- storage.cpp | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/esp32-cam-webserver.ino b/esp32-cam-webserver.ino index 5b46b0f..bc94b59 100644 --- a/esp32-cam-webserver.ino +++ b/esp32-cam-webserver.ino @@ -488,6 +488,7 @@ void setup() { Serial.println(myVer); Serial.print("Base Release: "); Serial.println(baseVersion); + Serial.println(); // Warn if no PSRAM is detected (typically user error with board selection in the IDE) if(!psramFound()){ @@ -511,6 +512,12 @@ void setup() { digitalWrite(LED_PIN, LED_ON); #endif + // Start the SPIFFS filesystem before we initialise the camera + if (filesystem) { + filesystemStart(); + delay(200); // a short delay to let spi bus settle after SPIFFS init + } + // Create camera config structure; and populate with hardware and other defaults camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; @@ -649,7 +656,6 @@ void setup() { if (filesystem) { delay(200); // a short delay to let spi bus settle after camera init - filesystemStart(); loadPrefs(SPIFFS); } else { Serial.println("No Internal Filesystem, cannot load or save preferences"); diff --git a/storage.cpp b/storage.cpp index 8a2644a..e740878 100644 --- a/storage.cpp +++ b/storage.cpp @@ -185,10 +185,11 @@ void removePrefs(fs::FS &fs) { } void filesystemStart(){ + Serial.println("Starting internal SPIFFS filesystem"); while ( !SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED) ) { // if we sit in this loop something is wrong; // if no existing spiffs partition exists one should be automagically created. - Serial.println("SPIFFS Mount failed, this can happen on first-run initialisation."); + Serial.println("SPIFFS Mount failed, this can happen on first-run initialisation"); Serial.println("If it happens repeatedly check if a SPIFFS partition is present for your board?"); for (int i=0; i<10; i++) { flashLED(100); // Show SPIFFS failure @@ -197,6 +198,5 @@ void filesystemStart(){ delay(1000); Serial.println("Retrying.."); } - Serial.println("Internal filesystem contents"); listDir(SPIFFS, "/", 0); } From 3fc9389c5721eefe13c6890672f480fe62ac2b63 Mon Sep 17 00:00:00 2001 From: Owen Date: Wed, 9 Mar 2022 08:27:29 +0100 Subject: [PATCH 08/16] fix doc --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cc8b8d6..2efd161 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ Pull requests are the best way to propose changes to the codebase (I use [Github 1. Fork the repo and create your branch from `master`. 2. Give your branch a clear descriptive name and do your changes there. 3. If you've changed the HTTP APIs, update the documentation. -4. Issue a pull request against a branch *of the same name* in the main repo. +4. Issue a pull request against the master branch in the main repo. 5. Clearly describe your changes and the reason for them in the pull request. ## Any contributions you make will be under the GNU Lesser General Public License v2.1 From 322187ced98f991ca593fb4eb0f79df562d01cf7 Mon Sep 17 00:00:00 2001 From: Owen Date: Wed, 9 Mar 2022 08:40:00 +0100 Subject: [PATCH 09/16] Strip trailing whitespace everywhere --- app_httpd.cpp | 2 +- camera_pins.h | 10 ++++----- css.h | 2 +- esp32-cam-webserver.ino | 48 ++++++++++++++++++++--------------------- index_other.h | 10 ++++----- index_ov2640.h | 8 +++---- index_ov3660.h | 8 +++---- src/favicons.h | 2 +- storage.cpp | 4 ++-- 9 files changed, 47 insertions(+), 47 deletions(-) diff --git a/app_httpd.cpp b/app_httpd.cpp index 6e75f26..de7da05 100644 --- a/app_httpd.cpp +++ b/app_httpd.cpp @@ -514,7 +514,7 @@ static esp_err_t dump_handler(httpd_req_t *req){ d+= sprintf(d,"\n"); d+= sprintf(d,"\n"); d+= sprintf(d,"\n"); - d+= sprintf(d,"\n"); + d+= sprintf(d,"\n"); if (critERR.length() > 0) { d+= sprintf(d,"%s
\n", critERR.c_str()); d+= sprintf(d,"

(the serial log may give more information)


\n"); diff --git a/camera_pins.h b/camera_pins.h index 68c4284..ce4b93d 100644 --- a/camera_pins.h +++ b/camera_pins.h @@ -1,9 +1,9 @@ -/* +/* * Pin definitions for some common ESP-CAM modules - * + * * Select the module to use in myconfig.h * Defaults to AI-THINKER CAM module - * + * */ #if defined(CAMERA_MODEL_AI_THINKER) // @@ -33,7 +33,7 @@ #elif defined(CAMERA_MODEL_WROVER_KIT) // - // ESP WROVER + // ESP WROVER // https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_SCH-2.pdf // #define PWDN_GPIO_NUM -1 @@ -189,7 +189,7 @@ #elif defined(CAMERA_MODEL_TTGO_T_JOURNAL) // - // LilyGO TTGO T-Journal ESP32; with OLED! but not used here.. :-( + // LilyGO TTGO T-Journal ESP32; with OLED! but not used here.. :-( #define PWDN_GPIO_NUM 0 #define RESET_GPIO_NUM 15 #define XCLK_GPIO_NUM 27 diff --git a/css.h b/css.h index 1c329b6..66a0deb 100644 --- a/css.h +++ b/css.h @@ -2,7 +2,7 @@ * Master CSS file for the camera pages */ -const uint8_t style_css[] = R"=====(/* +const uint8_t style_css[] = R"=====(/* * CSS for the esp32 cam webserver */ diff --git a/esp32-cam-webserver.ino b/esp32-cam-webserver.ino index bc94b59..0ebbfd8 100644 --- a/esp32-cam-webserver.ino +++ b/esp32-cam-webserver.ino @@ -16,7 +16,7 @@ * greater feedback via a status LED, and the HTML contents are present in plain text * for easy modification. * - * A camera name can now be configured, and wifi details can be stored in an optional + * A camera name can now be configured, and wifi details can be stored in an optional * header file to allow easier updated of the repo. * * The web UI has had changes to add the lamp control, rotation, a standalone viewer, @@ -26,7 +26,7 @@ */ -/* +/* * FOR NETWORK AND HARDWARE SETTINGS COPY OR RENAME 'myconfig.sample.h' TO 'myconfig.h' AND EDIT THAT. * * By default this sketch will assume an AI-THINKER ESP-CAM and create @@ -42,7 +42,7 @@ #warning "Using Defaults: Copy myconfig.sample.h to myconfig.h and edit that to use your own settings" #define WIFI_AP_ENABLE #define CAMERA_MODEL_AI_THINKER - struct station { const char ssid[65]; const char password[65]; const bool dhcp;} + struct station { const char ssid[65]; const char password[65]; const bool dhcp;} stationList[] = {{"ESP32-CAM-CONNECT","InsecurePassword", true}}; #endif @@ -103,7 +103,7 @@ int stationCount = sizeof(stationList)/sizeof(stationList[0]); // If we have AP mode enabled, ignore first entry in the stationList[] #if defined(WIFI_AP_ENABLE) - int firstStation = 1; + int firstStation = 1; #else int firstStation = 0; #endif @@ -158,7 +158,7 @@ int myRotation = CAM_ROTATION; #else int lampVal = 0; //default to off #endif -#else +#else int lampVal = -1; // no lamp pin assigned #endif @@ -234,7 +234,7 @@ void handleSerial() { while (Serial.available()) Serial.read(); // chomp the buffer } -// Notification LED +// Notification LED void flashLED(int flashtime) { #ifdef LED_PIN // If we have it; flash it. digitalWrite(LED_PIN, LED_ON); // On at full power. @@ -297,7 +297,7 @@ void WifiSetup() { flashLED(300); Serial.println("Starting WiFi"); - // Disable power saving on WiFi to improve responsiveness + // Disable power saving on WiFi to improve responsiveness // (https://github.com/espressif/arduino-esp32/issues/1484) WiFi.setSleep(false); @@ -311,13 +311,13 @@ void WifiSetup() { byte mac[6] = {0,0,0,0,0,0}; WiFi.macAddress(mac); Serial.printf("MAC address: %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - + int bestStation = -1; long bestRSSI = -1024; char bestSSID[65] = ""; uint8_t bestBSSID[6]; if (stationCount > firstStation) { - // We have a list to scan + // We have a list to scan Serial.printf("Scanning local Wifi Networks\r\n"); int stationsFound = WiFi.scanNetworks(); Serial.printf("%i networks found\r\n", stationsFound); @@ -330,7 +330,7 @@ void WifiSetup() { Serial.printf("%3i : [%s] %s (%i)", i + 1, thisBSSID.c_str(), thisSSID.c_str(), thisRSSI); // Scan our list of known external stations for (int sta = firstStation; sta < stationCount; sta++) { - if ((strcmp(stationList[sta].ssid, thisSSID.c_str()) == 0) || + if ((strcmp(stationList[sta].ssid, thisSSID.c_str()) == 0) || (strcmp(stationList[sta].ssid, thisBSSID.c_str()) == 0)) { Serial.print(" - Known!"); // Chose the strongest RSSI seen @@ -338,7 +338,7 @@ void WifiSetup() { bestStation = sta; strncpy(bestSSID, thisSSID.c_str(), 64); // Convert char bssid[] to a byte array - parseBytes(thisBSSID.c_str(), ':', bestBSSID, 6, 16); + parseBytes(thisBSSID.c_str(), ':', bestBSSID, 6, 16); bestRSSI = thisRSSI; } } @@ -348,11 +348,11 @@ void WifiSetup() { } } else { // No list to scan, therefore we are an accesspoint - accesspoint = true; + accesspoint = true; } if (bestStation == -1) { - if (!accesspoint) { + if (!accesspoint) { #if defined(WIFI_AP_ENABLE) Serial.println("No known networks found, entering AccessPoint fallback mode"); accesspoint = true; @@ -363,14 +363,14 @@ void WifiSetup() { Serial.println("AccessPoint mode selected in config"); } } else { - Serial.printf("Connecting to Wifi Network %d: [%02X:%02X:%02X:%02X:%02X:%02X] %s \r\n", - bestStation, bestBSSID[0], bestBSSID[1], bestBSSID[2], bestBSSID[3], + Serial.printf("Connecting to Wifi Network %d: [%02X:%02X:%02X:%02X:%02X:%02X] %s \r\n", + bestStation, bestBSSID[0], bestBSSID[1], bestBSSID[2], bestBSSID[3], bestBSSID[4], bestBSSID[5], bestSSID); // Apply static settings if necesscary if (stationList[bestStation].dhcp == false) { #if defined(ST_IP) Serial.println("Applying static IP settings"); - #if !defined (ST_GATEWAY) || !defined (ST_NETMASK) + #if !defined (ST_GATEWAY) || !defined (ST_NETMASK) #error "You must supply both Gateway and NetMask when specifying a static IP address" #endif IPAddress staticIP(ST_IP); @@ -400,7 +400,7 @@ void WifiSetup() { WiFi.begin(bestSSID, stationList[bestStation].password, 0, bestBSSID); // Wait to connect, or timeout - unsigned long start = millis(); + unsigned long start = millis(); while ((millis() - start <= WIFI_WATCHDOG) && (WiFi.status() != WL_CONNECTED)) { delay(500); Serial.print('.'); @@ -518,7 +518,7 @@ void setup() { delay(200); // a short delay to let spi bus settle after SPIFFS init } - // Create camera config structure; and populate with hardware and other defaults + // Create camera config structure; and populate with hardware and other defaults camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; @@ -574,7 +574,7 @@ void setup() { critERR += "

We will continue to reboot once per minute since this error sometimes clears automatically.

"; // Start a 60 second watchdog timer esp_task_wdt_init(60,true); - esp_task_wdt_add(NULL); + esp_task_wdt_add(NULL); } else { Serial.println("Camera init succeeded"); @@ -621,7 +621,7 @@ void setup() { /* * Add any other defaults you want to apply at startup here: * uncomment the line and set the value as desired (see the comments) - * + * * these are defined in the esp headers here: * https://github.com/espressif/esp32-camera/blob/master/driver/include/sensor.h#L149 */ @@ -688,7 +688,7 @@ void setup() { // Start OTA once connected Serial.println("Setting up OTA"); // Port defaults to 3232 - // ArduinoOTA.setPort(3232); + // ArduinoOTA.setPort(3232); // Hostname defaults to esp3232-[MAC] ArduinoOTA.setHostname(myName); // No authentication by default @@ -765,7 +765,7 @@ void setup() { } void loop() { - /* + /* * Just loop forever, reconnecting Wifi As necesscary in client mode * The stream and URI handler processes initiated by the startCameraServer() call at the * end of setup() will handle the camera and UI processing from now on. @@ -781,12 +781,12 @@ void loop() { if (captivePortal) dnsServer.processNextRequest(); } } else { - // client mode can fail; so reconnect as appropriate + // client mode can fail; so reconnect as appropriate static bool warned = false; if (WiFi.status() == WL_CONNECTED) { // We are connected, wait a bit and re-check if (warned) { - // Tell the user if we have just reconnected + // Tell the user if we have just reconnected Serial.println("WiFi reconnected"); warned = false; } diff --git a/index_other.h b/index_other.h index 06f5646..409d8d4 100644 --- a/index_other.h +++ b/index_other.h @@ -125,7 +125,7 @@ const uint8_t index_simple_html[] = R"=====( updateConfig(el); } else if(!updateRemote){ if(el.id === "lamp"){ - if (value == -1) { + if (value == -1) { hide(lampGroup) } else { show(lampGroup) @@ -142,7 +142,7 @@ const uint8_t index_simple_html[] = R"=====( streamURL = value; streamButton.setAttribute("title", `Start the stream :: {streamURL}`); console.log('Stream URL set to:' + value); - } + } } } @@ -408,7 +408,7 @@ const uint8_t streamviewer_html[] = R"=====( } else if(el.id === "stream_url"){ streamURL = value; console.log('Stream URL set to:' + value); - } + } } } @@ -460,7 +460,7 @@ const uint8_t streamviewer_html[] = R"=====( size_t streamviewer_html_len = sizeof(streamviewer_html)-1; -/* Captive Portal page +/* Captive Portal page we replace the <> delimited strings with correct values as it is served */ const std::string portal_html = R"=====( @@ -489,7 +489,7 @@ const std::string portal_html = R"=====( )====="; -/* Error page +/* Error page we replace the <> delimited strings with correct values as it is served */ const std::string error_html = R"=====( diff --git a/index_ov2640.h b/index_ov2640.h index 3baa56b..5d54c8b 100644 --- a/index_ov2640.h +++ b/index_ov2640.h @@ -350,7 +350,7 @@ const uint8_t index_ov2640_html[] = R"=====( } else if(el.id === "awb_gain"){ value ? show(wb) : hide(wb) } else if(el.id === "lamp"){ - if (value == -1) { + if (value == -1) { hide(lampGroup) hide(autolampGroup) } else { @@ -378,7 +378,7 @@ const uint8_t index_ov2640_html[] = R"=====( show(streamGroup) console.log('Stream URL set to: ' + streamURL); console.log('Stream Viewer URL set to: ' + viewerURL); - } + } } } @@ -488,7 +488,7 @@ const uint8_t index_ov2640_html[] = R"=====( } // Attach actions to controls - + streamLink.onclick = () => { stopStream(); window.open(viewerURL, "_blank"); @@ -579,7 +579,7 @@ const uint8_t index_ov2640_html[] = R"=====( swapButton.onclick = () => { window.open('/?view=simple','_self'); } - + savePrefsButton.onclick = () => { if (confirm("Save the current preferences?")) { updateConfig(savePrefsButton); diff --git a/index_ov3660.h b/index_ov3660.h index 9992376..8c1a082 100644 --- a/index_ov3660.h +++ b/index_ov3660.h @@ -362,7 +362,7 @@ const uint8_t index_ov3660_html[] = R"=====( } else if(el.id === "awb_gain"){ value ? show(wb) : hide(wb) } else if(el.id === "lamp"){ - if (value == -1) { + if (value == -1) { hide(lampGroup) hide(autolampGroup) } else { @@ -390,7 +390,7 @@ const uint8_t index_ov3660_html[] = R"=====( show(streamGroup) console.log('Stream URL set to: ' + streamURL); console.log('Stream Viewer URL set to: ' + viewerURL); - } + } } } @@ -500,7 +500,7 @@ const uint8_t index_ov3660_html[] = R"=====( } // Attach actions to controls - + streamLink.onclick = () => { stopStream(); window.open(viewerURL, "_blank"); @@ -588,7 +588,7 @@ const uint8_t index_ov3660_html[] = R"=====( swapButton.onclick = () => { window.open('/?view=simple','_self'); } - + savePrefsButton.onclick = () => { if (confirm("Save the current preferences?")) { updateConfig(savePrefsButton); diff --git a/src/favicons.h b/src/favicons.h index e5a5880..e513e1a 100644 --- a/src/favicons.h +++ b/src/favicons.h @@ -155,7 +155,7 @@ unsigned char favicon_32x32_png[] = { }; unsigned int favicon_32x32_png_len = 1051; -/* 32x32 .ico format */ +/* 32x32 .ico format */ unsigned char favicon_ico[] = { 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x20, 0x20, 0x00, 0x00, 0x01, 0x00, diff --git a/storage.cpp b/storage.cpp index e740878..fbba969 100644 --- a/storage.cpp +++ b/storage.cpp @@ -10,7 +10,7 @@ extern int autoLamp; // Automatic lamp mode extern int xclk; // Camera module clock speed /* - * Useful utility when debugging... + * Useful utility when debugging... */ void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ @@ -187,7 +187,7 @@ void removePrefs(fs::FS &fs) { void filesystemStart(){ Serial.println("Starting internal SPIFFS filesystem"); while ( !SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED) ) { - // if we sit in this loop something is wrong; + // if we sit in this loop something is wrong; // if no existing spiffs partition exists one should be automagically created. Serial.println("SPIFFS Mount failed, this can happen on first-run initialisation"); Serial.println("If it happens repeatedly check if a SPIFFS partition is present for your board?"); From cb78162ea4ba3f5056a4c8b168f3a98ecbc4ef86 Mon Sep 17 00:00:00 2001 From: Owen Date: Wed, 9 Mar 2022 11:40:40 +0100 Subject: [PATCH 10/16] lamp default state fix #204 --- app_httpd.cpp | 1 + esp32-cam-webserver.ino | 41 ++++++++++++++++++++--------------------- myconfig.sample.h | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/app_httpd.cpp b/app_httpd.cpp index de7da05..a8e0ea8 100644 --- a/app_httpd.cpp +++ b/app_httpd.cpp @@ -394,6 +394,7 @@ static esp_err_t cmd_handler(httpd_req_t *req){ if (filesystem) removePrefs(SPIFFS); } else if(!strcmp(variable, "reboot")) { + if (lampVal != -1) setLamp(0); // kill the lamp; otherwise it can remain on during the soft-reboot esp_task_wdt_init(3,true); // schedule a a watchdog panic event for 3 seconds in the future esp_task_wdt_add(NULL); periph_module_disable(PERIPH_I2C0_MODULE); // try to shut I2C down properly diff --git a/esp32-cam-webserver.ino b/esp32-cam-webserver.ino index 0ebbfd8..81644db 100644 --- a/esp32-cam-webserver.ino +++ b/esp32-cam-webserver.ino @@ -666,24 +666,13 @@ void setup() { * Camera setup complete; initialise the rest of the hardware. */ - // Initialise and set the lamp - if (lampVal != -1) { - ledcSetup(lampChannel, pwmfreq, pwmresolution); // configure LED PWM channel - if (autoLamp) setLamp(0); // set default value - else setLamp(lampVal); - #if defined(LAMP_PIN) - ledcAttachPin(LAMP_PIN, lampChannel); // attach the GPIO pin to the channel - #endif - } else { - Serial.println("No lamp, or lamp disabled in config"); - } - - // Having got this far; start Wifi and loop until we are connected or have started an AccessPoint + // Start Wifi and loop until we are connected or have started an AccessPoint while ((WiFi.status() != WL_CONNECTED) && !accesspoint) { WifiSetup(); delay(1000); } + // Set up OTA if (otaEnabled) { // Start OTA once connected Serial.println("Setting up OTA"); @@ -736,7 +725,22 @@ void setup() { Serial.println("Time functions disabled"); } - // Now we have a network we can start the two http handlers for the UI and Stream. + // Gather static values used when dumping status; these are slow functions, so just do them once during startup + sketchSize = ESP.getSketchSize(); + sketchSpace = ESP.getFreeSketchSpace(); + sketchMD5 = ESP.getSketchMD5(); + + // Initialise and set the lamp + if (lampVal != -1) { + ledcSetup(lampChannel, pwmfreq, pwmresolution); // configure LED PWM channel + ledcAttachPin(LAMP_PIN, lampChannel); // attach the GPIO pin to the channel + if (autoLamp) setLamp(0); // set default value + else setLamp(lampVal); + } else { + Serial.println("No lamp, or lamp disabled in config"); + } + + // Start the camera server startCameraServer(httpPort, streamPort); if (critERR.length() == 0) { @@ -752,16 +756,11 @@ void setup() { Serial.printf("\r\nCamera unavailable due to initialisation errors.\r\n\r\n"); } - // Used when dumping status; these are slow functions, so just do them once during startup - sketchSize = ESP.getSketchSize(); - sketchSpace = ESP.getFreeSketchSpace(); - sketchMD5 = ESP.getSketchMD5(); + // Info line; use for Info messages; eg 'This is a Beta!' warnings, etc. as necesscary + // Serial.print("\r\nThis is the 4.1 beta\r\n"); // As a final init step chomp out the serial buffer in case we have recieved mis-keys or garbage during startup while (Serial.available()) Serial.read(); - - // Info line; use for Info messages; eg 'This is a Beta!' warnings, etc. as necesscary - // Serial.print("\r\nThis is the 4.1 beta\r\n"); } void loop() { diff --git a/myconfig.sample.h b/myconfig.sample.h index 4388422..851f7f8 100644 --- a/myconfig.sample.h +++ b/myconfig.sample.h @@ -158,6 +158,7 @@ struct station stationList[] = {{"ssid1", "pass1", true}, // #define LAMP_DISABLE // Define the startup lamp power setting (as a percentage, defaults to 0%) +// Saved (SPIFFS) user settings will override this // #define LAMP_DEFAULT 0 // Assume the module used has a SPIFFS/LittleFS partition, and use that for persistent setting storage @@ -190,4 +191,3 @@ struct station stationList[] = {{"ssid1", "pass1", true}, // For clone modules that have camera module and SPIFFS startup issues try setting // this very low (start at 2MHZ and increase): // #define XCLK_FREQ_MHZ 2 - From f4bde8b77caa10d3b2758233909197843e7b316d Mon Sep 17 00:00:00 2001 From: Owen Date: Wed, 9 Mar 2022 11:41:40 +0100 Subject: [PATCH 11/16] autolamp value in prefs should be bool --- storage.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/storage.cpp b/storage.cpp index fbba969..56a1d75 100644 --- a/storage.cpp +++ b/storage.cpp @@ -4,10 +4,10 @@ // These are defined in the main .ino file extern void flashLED(int flashtime); -extern int myRotation; // Rotation -extern int lampVal; // The current Lamp value -extern int autoLamp; // Automatic lamp mode -extern int xclk; // Camera module clock speed +extern int myRotation; // Rotation +extern int lampVal; // The current Lamp value +extern bool autoLamp; // Automatic lamp mode +extern int xclk; // Camera module clock speed /* * Useful utility when debugging... @@ -90,11 +90,11 @@ void loadPrefs(fs::FS &fs){ sensor_t * s = esp_camera_sensor_get(); // process all the settings lampVal = jsonExtract(prefs, "lamp").toInt(); - autoLamp = jsonExtract(prefs, "autolamp").toInt(); - int xclkPref = jsonExtract(prefs, "xclk").toInt(); - if (xclkPref != 0) xclk = xclkPref; + if (jsonExtract(prefs, "autolamp").toInt() == 0) autoLamp = false; else autoLamp = true; s->set_framesize(s, (framesize_t)jsonExtract(prefs, "framesize").toInt()); s->set_quality(s, jsonExtract(prefs, "quality").toInt()); + int xclkPref = jsonExtract(prefs, "xclk").toInt(); + if (xclkPref != 0) xclk = xclkPref; s->set_xclk(s, LEDC_TIMER_0, xclk); s->set_brightness(s, jsonExtract(prefs, "brightness").toInt()); s->set_contrast(s, jsonExtract(prefs, "contrast").toInt()); From b5c2293ceb1d112126eed4340d0a76a08d0130a1 Mon Sep 17 00:00:00 2001 From: Eric Fontaine Date: Wed, 9 Mar 2022 05:55:03 -0500 Subject: [PATCH 12/16] fix autolamp tooltip (#146) Properly apply autolamp tooltip --- index_ov2640.h | 4 ++-- index_ov3660.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/index_ov2640.h b/index_ov2640.h index f923a21..8165522 100644 --- a/index_ov2640.h +++ b/index_ov2640.h @@ -41,10 +41,10 @@ const uint8_t index_ov2640_html[] = R"=====(
Full
- -