From b0e137f239fb0e5c7da4f7f9a2024c60e4c1106c Mon Sep 17 00:00:00 2001 From: Owen Carter Date: Tue, 8 Jun 2021 15:03:22 +0200 Subject: [PATCH 01/14] Fix #119: add 3.x maintenance branch --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 987087e..c5f6364 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # ESP32-CAM example revisited.     [![CI Status](https://travis-ci.org/easytarget/esp32-cam-webserver.svg?branch=master)](https://travis-ci.org/github/easytarget/esp32-cam-webserver)    ![ESP-EYE logo](Docs/logo.svg) +# V3.x - Legacy Branch +### This is the *old* 3.x branch of the project, with Face Recognition, but no Over The Air updates +I will continue to fix bugs as needed on this branch for the forseeable future, but will not be adding any new features + +See the [master](https://github.com/easytarget/esp32-cam-webserver/tree/master/) branch for the current (v4+) version which has lost the basic Face Recognition features, but gained Over The Air updates and other new features. + ## Taken from the ESP examples, and expanded This sketch is a extension/expansion/rework of the 'official' ESP32 Camera example sketch from Espressif: From 9fb70cb2c6023068da55080a7c65bce385510daf Mon Sep 17 00:00:00 2001 From: Owen Carter Date: Thu, 1 Jul 2021 11:29:41 +0200 Subject: [PATCH 02/14] Import latest fixes from upstream jsonlib (#132) * Fix an off-by-one error that might affect us, etc. --- src/jsonlib/jsonlib.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jsonlib/jsonlib.cpp b/src/jsonlib/jsonlib.cpp index 2aa8ede..b567db8 100644 --- a/src/jsonlib/jsonlib.cpp +++ b/src/jsonlib/jsonlib.cpp @@ -78,7 +78,7 @@ String jsonExtract(String json, String name){ if(next == '\"'){ //Serial.println(".. a string"); start = start + 1; - stop = json.indexOf('"', start + 1); + stop = json.indexOf('"', start); } else if(next == '['){ //Serial.println(".. a list"); @@ -111,7 +111,7 @@ String jsonExtract(String json, String name){ else if(next == '.' || next == '-' || ('0' <= next && next <= '9')){ //Serial.println(".. a number"); int i = start; - while((i++ < json.length() && json.charAt(i) == '.') || ('0' <= json.charAt(i) && json.charAt(i) <= '9')){ + while(i++ < json.length() && (json.charAt(i) == '.' || ('0' <= json.charAt(i) && json.charAt(i) <= '9'))){ } stop = i; } From 50d2a7d919a8ae572f0bb4b0f1aef1858a3b9285 Mon Sep 17 00:00:00 2001 From: Owen Carter Date: Thu, 1 Jul 2021 01:04:29 +0200 Subject: [PATCH 03/14] Fix compiling for ESP Arduino core 2.x (#130) --- src/jsonlib/jsonlib.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jsonlib/jsonlib.cpp b/src/jsonlib/jsonlib.cpp index b567db8..4a5c454 100644 --- a/src/jsonlib/jsonlib.cpp +++ b/src/jsonlib/jsonlib.cpp @@ -70,9 +70,10 @@ String jsonIndexList(String json, int idx){ String jsonExtract(String json, String name){ char next; int start = 0, stop = 0; + static const size_t npos = -1; name = String("\"") + name + String("\""); - if (json.indexOf(name) == std::string::npos) return json.substring(0,0); + if (json.indexOf(name) == npos) return json.substring(0,0); start = json.indexOf(name) + name.length() + 1; next = json.charAt(start); if(next == '\"'){ From 594adb550d11dbd2669dae6fb834ab504f48a371 Mon Sep 17 00:00:00 2001 From: Owen Carter Date: Wed, 30 Jun 2021 18:22:51 +0200 Subject: [PATCH 04/14] Handle corrupt preferences files (#129) --- storage.cpp | 24 +++++++++++++++++++----- storage.h | 1 + 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/storage.cpp b/storage.cpp index 8061427..39bfb0b 100644 --- a/storage.cpp +++ b/storage.cpp @@ -49,7 +49,11 @@ void dumpPrefs(fs::FS &fs){ if (fs.exists(PREFERENCES_FILE)) { // Dump contents for debug File file = fs.open(PREFERENCES_FILE, FILE_READ); - while (file.available()) Serial.print(char(file.read())); + int countSize = 0; + while (file.available() && countSize <= PREFERENCES_MAX_SIZE) { + Serial.print(char(file.read())); + countSize++; + } Serial.println(""); file.close(); } else { @@ -64,15 +68,25 @@ void loadPrefs(fs::FS &fs){ Serial.printf("Loading preferences from file %s\r\n", PREFERENCES_FILE); File file = fs.open(PREFERENCES_FILE, FILE_READ); if (!file) { - Serial.println("Failed to open preferences file"); + Serial.println("Failed to open preferences file for reading, maybe corrupt, removing"); + removePrefs(SPIFFS); return; } size_t size = file.size(); - if (size > 800) { - Serial.println("Preferences file size is too large, maybe corrupt"); + if (size > PREFERENCES_MAX_SIZE) { + Serial.println("Preferences file size is too large, maybe corrupt, removing"); + removePrefs(SPIFFS); return; } - while (file.available()) prefs += char(file.read()); + while (file.available()) { + prefs += char(file.read()); + if (prefs.length() > size) { + // corrupted SPIFFS files can return data beyond their declared size. + Serial.println("Preferences file failed to load properly, appears to be corrupt, removing"); + removePrefs(SPIFFS); + return; + } + } // get sensor reference sensor_t * s = esp_camera_sensor_get(); // process all the settings diff --git a/storage.h b/storage.h index e5ae34c..a2d3064 100644 --- a/storage.h +++ b/storage.h @@ -2,6 +2,7 @@ #include "SPIFFS.h" #define FORMAT_SPIFFS_IF_FAILED true +#define PREFERENCES_MAX_SIZE 500 #define PREFERENCES_FILE "/esp32cam-preferences.json" #define FACE_DB_FILE "/esp32cam-facedb" From ba13cfdd396c50c5aef1a57234618ffbaac7342d Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 3 Sep 2021 12:21:07 +0200 Subject: [PATCH 05/14] Bump to 3.4 --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index eb1c845..1487875 100644 --- a/src/version.h +++ b/src/version.h @@ -1,3 +1,3 @@ /* Version of upstream code */ -char baseVersion[] = "3.2.1"; +char baseVersion[] = "3.4"; From f6f4642ed3426e847774dbbbe4bfe37c37802e4c Mon Sep 17 00:00:00 2001 From: Owen Date: Thu, 2 Sep 2021 13:20:59 +0200 Subject: [PATCH 06/14] Temperature Display in data screen (#151) --- app_httpd.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app_httpd.cpp b/app_httpd.cpp index a8ab2d4..fb4cab5 100644 --- a/app_httpd.cpp +++ b/app_httpd.cpp @@ -104,6 +104,14 @@ static ra_filter_t ra_filter; httpd_handle_t stream_httpd = NULL; httpd_handle_t camera_httpd = NULL; +#ifdef __cplusplus +extern "C" { +#endif +uint8_t temprature_sens_read(); +#ifdef __cplusplus +} +#endif + static mtmn_config_t mtmn_config = {0}; static int8_t is_enrolling = 0; static face_id_list id_list = {0}; @@ -872,9 +880,14 @@ static esp_err_t dump_handler(httpd_req_t *req){ int upHours = int64_t(floor(sec/3600)) % 24; int upMin = int64_t(floor(sec/60)) % 60; int upSec = sec % 60; + int McuTc = (temprature_sens_read() - 32) / 1.8; // celsius + int McuTf = temprature_sens_read(); // fahrenheit + 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,""); + 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()); d+= sprintf(d,"Psram: %i, free: %i, min free: %i, max block: %i
\n", ESP.getPsramSize(), ESP.getFreePsram(), ESP.getMinFreePsram(), ESP.getMaxAllocPsram()); if (filesystem) { From 8d11706a16e4ca4895a30f0e0cdc3602d3cbfc2f Mon Sep 17 00:00:00 2001 From: Owen Carter Date: Sat, 11 Sep 2021 15:17:41 +0200 Subject: [PATCH 07/14] Re-Calculate URLs on WiFi reconnect (#159) --- esp32-cam-webserver.ino | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/esp32-cam-webserver.ino b/esp32-cam-webserver.ino index 2f9ed1e..330884f 100644 --- a/esp32-cam-webserver.ino +++ b/esp32-cam-webserver.ino @@ -241,6 +241,26 @@ void setLamp(int newVal) { } } +void calcURLs() { + // Set the URL's + #if defined(URL_HOSTNAME) + if (httpPort != 80) { + sprintf(httpURL, "http://%s:%d/", URL_HOSTNAME, httpPort); + } else { + sprintf(httpURL, "http://%s/", URL_HOSTNAME); + } + sprintf(streamURL, "http://%s:%d/", URL_HOSTNAME, streamPort); + #else + Serial.println("Setting httpURL"); + if (httpPort != 80) { + sprintf(httpURL, "http://%d.%d.%d.%d:%d/", ip[0], ip[1], ip[2], ip[3], httpPort); + } else { + sprintf(httpURL, "http://%d.%d.%d.%d/", ip[0], ip[1], ip[2], ip[3]); + } + sprintf(streamURL, "http://%d.%d.%d.%d:%d/", ip[0], ip[1], ip[2], ip[3], streamPort); + #endif +} + void WifiSetup() { // Feedback that we are now attempting to connect flashLED(300); @@ -367,6 +387,7 @@ void WifiSetup() { Serial.printf("IP address: %d.%d.%d.%d\r\n",ip[0],ip[1],ip[2],ip[3]); Serial.printf("Netmask : %d.%d.%d.%d\r\n",net[0],net[1],net[2],net[3]); Serial.printf("Gateway : %d.%d.%d.%d\r\n",gw[0],gw[1],gw[2],gw[3]); + calcURLs(); // Flash the LED to show we are connected for (int i = 0; i < 5; i++) { flashLED(50); @@ -412,6 +433,7 @@ void WifiSetup() { gw = WiFi.gatewayIP(); strcpy(apName, stationList[0].ssid); Serial.printf("IP address: %d.%d.%d.%d\r\n",ip[0],ip[1],ip[2],ip[3]); + calcURLs(); // Flash the LED to show we are connected for (int i = 0; i < 5; i++) { flashLED(150); @@ -620,21 +642,6 @@ void setup() { // Now we have a network we can start the two http handlers for the UI and Stream. startCameraServer(httpPort, streamPort); - #if defined(URL_HOSTNAME) - if (httpPort != 80) { - sprintf(httpURL, "http://%s:%d/", URL_HOSTNAME, httpPort); - } else { - sprintf(httpURL, "http://%s/", URL_HOSTNAME); - } - sprintf(streamURL, "http://%s:%d/", URL_HOSTNAME, streamPort); - #else - if (httpPort != 80) { - sprintf(httpURL, "http://%d.%d.%d.%d:%d/", ip[0], ip[1], ip[2], ip[3], httpPort); - } else { - sprintf(httpURL, "http://%d.%d.%d.%d/", ip[0], ip[1], ip[2], ip[3]); - } - sprintf(streamURL, "http://%d.%d.%d.%d:%d/", ip[0], ip[1], ip[2], ip[3], streamPort); - #endif if (critERR.length() == 0) { Serial.printf("\r\nCamera Ready!\r\nUse '%s' to connect\r\n", httpURL); Serial.printf("Stream viewer available at '%sview'\r\n", streamURL); From 052f58673c8b831ddedec0f20a151720b7d211df Mon Sep 17 00:00:00 2001 From: Owen Date: Mon, 27 Sep 2021 16:43:21 +0200 Subject: [PATCH 08/14] update ide and framework in travis --- .travis.yml | 16 ++++++++++------ API.md | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index db24e40..572035a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,18 +7,22 @@ os: dist: focal + branches: + only: + - master + before_script: - "export DISPLAY=:99.0" - sleep 3 # give xvfb some time to start - - wget http://downloads.arduino.cc/arduino-1.8.13-linux64.tar.xz - - tar xf arduino-1.8.13-linux64.tar.xz - - mv arduino-1.8.13 $HOME/arduino_ide + - wget http://downloads.arduino.cc/arduino-1.8.16-linux64.tar.xz + - tar xf arduino-1.8.16-linux64.tar.xz + - mv arduino-1.8.16 $HOME/arduino_ide - cd $HOME/arduino_ide/hardware - mkdir esp32 - cd esp32 - - wget https://github.com/espressif/arduino-esp32/archive/refs/tags/1.0.6.tar.gz - - tar -xzf 1.0.6.tar.gz - - mv arduino-esp32-1.0.6/ esp32 + - wget https://github.com/espressif/arduino-esp32/archive/refs/tags/2.0.0.tar.gz + - tar -xzf 2.0.0.tar.gz + - mv arduino-esp32-2.0.0/ esp32 - cd esp32/tools - python --version - python get.py diff --git a/API.md b/API.md index c54c504..8e0be09 100644 --- a/API.md +++ b/API.md @@ -96,7 +96,7 @@ reboot - Reboots the camera * `http:///control?var=lamp&val=50` * `http:///control?var=lamp&val=0` * Set resolution to VGA - * `http:///control?var=framesize&val=6` + * `http:///control?var=framesize&val=8` * Show camera details and settings * All settings are returned via single `status` call in [JSON](https://www.json.org/) format. * `http:///status` From 827e53323680a7ee6e4eae9cecfc404ba80b6a6d Mon Sep 17 00:00:00 2001 From: Owen Date: Mon, 27 Sep 2021 16:44:43 +0200 Subject: [PATCH 09/14] fix branch definition in travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 572035a..b9ff27d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ os: dist: focal - branches: +branches: only: - master From 4a6e80d137d372f81b57cf49faecf704cd9e9f60 Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 31 Dec 2021 19:03:45 +0100 Subject: [PATCH 10/14] Bring in latest v4 changes where appropriate --- .travis.yml | 9 ++--- README.md | 2 ++ app_httpd.cpp | 64 ++++++++++++++++++++++++--------- camera_pins.h | 79 +++++++++++++++++++++++++++-------------- esp32-cam-webserver.ino | 23 ++++++++++-- platformio.ini | 6 +++- src/version.h | 2 +- 7 files changed, 133 insertions(+), 52 deletions(-) diff --git a/.travis.yml b/.travis.yml index b9ff27d..83b4bcb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,12 +11,13 @@ branches: only: - master + before_script: - "export DISPLAY=:99.0" - sleep 3 # give xvfb some time to start - - wget http://downloads.arduino.cc/arduino-1.8.16-linux64.tar.xz - - tar xf arduino-1.8.16-linux64.tar.xz - - mv arduino-1.8.16 $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 @@ -32,7 +33,7 @@ before_script: script: - cd $TRAVIS_BUILD_DIR - export PATH="$HOME/arduino_ide:$PATH" - - arduino --board esp32:esp32:esp32:PartitionScheme=huge_app,FlashFreq=80 --pref compiler.warning_level=all --save-prefs + - arduino --board esp32:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app,FlashFreq=80 --pref compiler.warning_level=all --save-prefs - arduino --verbose --verify esp32-cam-webserver.ino - cp --preserve --verbose myconfig.sample.h myconfig.h - arduino --verbose --verify esp32-cam-webserver.ino diff --git a/README.md b/README.md index c5f6364..ccd95fb 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,8 @@ To make a permanent config with your home wifi settings, different defaults or a Assuming you are using the latest Espressif Arduino core the `AI-THINKER` board (or whatever board you select for programming) will appear in the ESP32 Arduino section of the boards list. ![IDE board config](Docs/board-selection-small.png) +If you have a different board and are using a generic ESP32 DEV board select `Huge APP (3MB No OTA/1MB SPIFFS` for the partition scheme, and make sure PSRAM is enabled (it defaults to off!) + Compile and upload the code from the IDE, when the `Connecting...` appears in the console reboot the ESP32 module while keeping **GPIO0** grounded. You can release GPO0 once the sketch is uploading, most boards have a 'boot' button to trigger a reboot. Once the upload completes (be patient, it can be a bit slow) open the serial monitor in the IDE and reboot the board again without GPIO0 grounded. In the serial monitor you should see the board start, connect to the wifi and then report the IP address it has been assigned. diff --git a/app_httpd.cpp b/app_httpd.cpp index fb4cab5..5f6f52e 100644 --- a/app_httpd.cpp +++ b/app_httpd.cpp @@ -64,6 +64,8 @@ extern int sketchSpace; extern String sketchMD5; extern char knownFaceText[]; extern char unknownFaceText[]; +extern unsigned long xclkFreqHz; + #include "fb_gfx.h" @@ -260,11 +262,7 @@ static int run_face_recognition(dl_matrix3du_t *image_matrix, box_array_t *net_b } void serialDump() { - Serial.println("\r\nPreferences file: "); - dumpPrefs(SPIFFS); - if (critERR.length() > 0) { - Serial.printf("\r\n\r\nA critical error has occurred when initialising Camera Hardware, see startup megssages\r\n"); - } + Serial.println(); // Module Serial.printf("Name: %s\r\n", myName); Serial.printf("Firmware: %s (base: %s)\r\n", myVer, baseVersion); @@ -303,15 +301,33 @@ void serialDump() { int upHours = int64_t(floor(sec/3600)) % 24; int upMin = int64_t(floor(sec/60)) % 60; 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()); - Serial.printf("Psram: %i, free: %i, min free: %i, max block: %i\r\n", ESP.getPsramSize(), ESP.getFreePsram(), ESP.getMinFreePsram(), ESP.getMaxAllocPsram()); - if (filesystem) { + if(psramFound()) { + Serial.printf("Psram: %i, free: %i, min free: %i, max block: %i\r\n", ESP.getPsramSize(), ESP.getFreePsram(), ESP.getMinFreePsram(), ESP.getMaxAllocPsram()); + } else { + Serial.printf("Psram: Not found; please check your board configuration.\r\n"); + Serial.printf("- High resolution/quality settings will show incomplete frames due to low memory.\r\n"); + } + // Filesystems + if (filesystem && (SPIFFS.totalBytes() > 0)) { Serial.printf("Spiffs: %i, used: %i\r\n", SPIFFS.totalBytes(), SPIFFS.usedBytes()); + } else { + Serial.printf("Spiffs: No filesystem found, please check your board configuration.\r\n"); + Serial.printf("- Saving and restoring camera settings will not function without this.\r\n"); } Serial.printf("Enrolled faces: %i (max %i)\r\n", id_list.count, id_list.size); + Serial.println("Preferences file: "); + dumpPrefs(SPIFFS); + if (critERR.length() > 0) { + Serial.printf("\r\n\r\nA critical error has occurred when initialising Camera Hardware, see startup megssages\r\n"); + } Serial.println(); return; } @@ -333,7 +349,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(); @@ -392,7 +411,8 @@ static esp_err_t capture_handler(httpd_req_t *req){ s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf); esp_camera_fb_return(fb); - if(!s){ + fb = NULL; +if(!s){ dl_matrix3du_free(image_matrix); Serial.println("CAPTURE: frame convert to rgb888 failed"); httpd_resp_send_500(req); @@ -429,7 +449,9 @@ static esp_err_t capture_handler(httpd_req_t *req){ } imagesServed++; - if (autoLamp && (lampVal != -1)) setLamp(0); + if (autoLamp && (lampVal != -1)) { + setLamp(0); + } return res; } @@ -609,6 +631,7 @@ static esp_err_t cmd_handler(httpd_req_t *req){ size_t buf_len; char variable[32] = {0,}; char value[32] = {0,}; + flashLED(75); buf_len = httpd_req_get_url_query_len(req) + 1; @@ -835,8 +858,8 @@ static esp_err_t dump_handler(httpd_req_t *req){ d+= sprintf(d,"\n"); d+= sprintf(d,"\n"); if (critERR.length() > 0) { - d+= sprintf(d,"Hardware Error Detected!\n(the serial log may give more information)\n"); - d+= sprintf(d,"%s
\n", critERR.c_str()); + d+= sprintf(d,"%s
\n", critERR.c_str()); + d+= sprintf(d,"

(the serial log may give more information)


\n"); } d+= sprintf(d,"

ESP32 Cam Webserver

\n"); // Module @@ -882,16 +905,25 @@ 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()); - d+= sprintf(d,"Psram: %i, free: %i, min free: %i, max block: %i
\n", ESP.getPsramSize(), ESP.getFreePsram(), ESP.getMinFreePsram(), ESP.getMaxAllocPsram()); - if (filesystem) { + if (psramFound()) { + d+= sprintf(d,"Psram: %i, free: %i, min free: %i, max block: %i
\n", ESP.getPsramSize(), ESP.getFreePsram(), ESP.getMinFreePsram(), ESP.getMaxAllocPsram()); + } else { + d+= sprintf(d,"Psram: Not found, please check your board configuration.
\n"); + d+= sprintf(d,"- High resolution/quality images & streams will show incomplete frames due to low memory.
\n"); + } + if (filesystem && (SPIFFS.totalBytes() > 0)) { d+= sprintf(d,"Spiffs: %i, used: %i
\n", SPIFFS.totalBytes(), SPIFFS.usedBytes()); + } else { + d+= sprintf(d,"Spiffs: No filesystem found, please check your board configuration.
\n"); + d+= sprintf(d,"- saving and restoring camera settings will not function without this.
\n"); } d+= sprintf(d,"Enrolled faces: %i (max %i)
\n", id_list.count, id_list.size); 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/esp32-cam-webserver.ino b/esp32-cam-webserver.ino index 330884f..46857d5 100644 --- a/esp32-cam-webserver.ino +++ b/esp32-cam-webserver.ino @@ -93,7 +93,7 @@ extern void serialDump(); #endif #if !defined(WIFI_WATCHDOG) - #define WIFI_WATCHDOG 5000 + #define WIFI_WATCHDOG 15000 #endif // Number of known networks in stationList[] @@ -131,6 +131,15 @@ unsigned long imagesServed = 0; // Total image requests // This will be displayed to identify the firmware 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. +// See https://github.com/espressif/esp32-camera/issues/150#issuecomment-726473652 et al. +#if !defined (XCLK_FREQ_HZ) + unsigned long xclkFreqHz = 16500000; +#else + unsigned long xclkFreqHz = XCLK_FREQ_HZ; +#endif + // initial rotation // can be set in myconfig.h #if !defined(CAM_ROTATION) @@ -495,9 +504,9 @@ 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 = 20000000; + config.xclk_freq_hz = xclkFreqHz; config.pixel_format = PIXFORMAT_JPEG; - //init with highest supported specs to pre-allocate large buffers + // Pre-allocate large buffers if(psramFound()){ config.frame_size = FRAMESIZE_UXGA; config.jpeg_quality = 10; @@ -611,6 +620,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); loadFaceDB(SPIFFS); @@ -662,6 +672,13 @@ 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"); + } + } void loop() { diff --git a/platformio.ini b/platformio.ini index 74a34ef..7435574 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,6 +12,10 @@ src_dir = ./ [env:esp32cam] -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.0 board = esp32cam framework = arduino +build_flags = + -DBOARD_HAS_PSRAM + -mfix-esp32-psram-cache-issue diff --git a/src/version.h b/src/version.h index 1487875..cf8d128 100644 --- a/src/version.h +++ b/src/version.h @@ -1,3 +1,3 @@ /* Version of upstream code */ -char baseVersion[] = "3.4"; +char baseVersion[] = "3.5-beta1"; From 28ea59e8a27f6aae66481823569053c6c1e5f942 Mon Sep 17 00:00:00 2001 From: Owen Date: Mon, 7 Mar 2022 08:42:40 +0100 Subject: [PATCH 11/14] Bump version --- Docs/v3x-select-106-ide-core.png | Bin 0 -> 62166 bytes src/version.h | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 Docs/v3x-select-106-ide-core.png diff --git a/Docs/v3x-select-106-ide-core.png b/Docs/v3x-select-106-ide-core.png new file mode 100644 index 0000000000000000000000000000000000000000..1a3ef535a13e98049891e35cf6d4f5050c66c075 GIT binary patch literal 62166 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໎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%0Di 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 CD8can literal 0 HcmV?d00001 diff --git a/src/version.h b/src/version.h index cf8d128..4d4c54a 100644 --- a/src/version.h +++ b/src/version.h @@ -1,3 +1,3 @@ /* Version of upstream code */ -char baseVersion[] = "3.5-beta1"; +char baseVersion[] = "3.5"; From 048ed892f9a6a9aa9f275697f9b53066fce28917 Mon Sep 17 00:00:00 2001 From: Owen Date: Mon, 7 Mar 2022 08:47:48 +0100 Subject: [PATCH 12/14] No longer building 3.x on travis --- .travis.yml | 47 ----------------------------------------------- 1 file changed, 47 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 83b4bcb..0000000 --- a/.travis.yml +++ /dev/null @@ -1,47 +0,0 @@ -sudo: false - -language: bash - -os: - - linux - -dist: focal - -branches: - only: - - master - - -before_script: - - "export DISPLAY=:99.0" - - sleep 3 # give xvfb some time to start - - 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.0.tar.gz - - tar -xzf 2.0.0.tar.gz - - mv arduino-esp32-2.0.0/ esp32 - - cd esp32/tools - - python --version - - python get.py - - pip install --user platformio - - platformio update - -script: - - cd $TRAVIS_BUILD_DIR - - export PATH="$HOME/arduino_ide:$PATH" - - arduino --board esp32:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app,FlashFreq=80 --pref compiler.warning_level=all --save-prefs - - arduino --verbose --verify esp32-cam-webserver.ino - - cp --preserve --verbose myconfig.sample.h myconfig.h - - arduino --verbose --verify esp32-cam-webserver.ino - - platformio run - - -notifications: - email: - on_success: change - on_failure: change - From 08e5f8517f74bb1d1144831ee80fefd02714bbec Mon Sep 17 00:00:00 2001 From: Owen Carter Date: Mon, 7 Mar 2022 09:19:24 +0100 Subject: [PATCH 13/14] V3.5 notes --- README.md | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index ccd95fb..1e378f1 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ -# ESP32-CAM example revisited.     [![CI Status](https://travis-ci.org/easytarget/esp32-cam-webserver.svg?branch=master)](https://travis-ci.org/github/easytarget/esp32-cam-webserver)    ![ESP-EYE logo](Docs/logo.svg) +# ESP32-CAM example revisited. # V3.x - Legacy Branch ### This is the *old* 3.x branch of the project, with Face Recognition, but no Over The Air updates I will continue to fix bugs as needed on this branch for the forseeable future, but will not be adding any new features +You need to **downgrade** the esp32 board definition in the Arduino IDE to use this, instructions are below but please understand that this is not really recommended, the only reason you should be using this branch is to investigate the (very limited!) Face Recognition features of the camera module. + See the [master](https://github.com/easytarget/esp32-cam-webserver/tree/master/) branch for the current (v4+) version which has lost the basic Face Recognition features, but gained Over The Air updates and other new features. ## Taken from the ESP examples, and expanded @@ -55,6 +57,16 @@ The existing [issues list](https://github.com/easytarget/esp32-cam-webserver/iss * For programming you will need a suitable development environment, I use the Arduino IDE, but this code should work in the Espressif development environment too. * Make sure you are using the [latest version](https://www.arduino.cc/en/main/software#download) of the IDE and then follow [This Guide](https://github.com/espressif/arduino-esp32/blob/master/docs/arduino-ide/boards_manager.md) to set up the Espressif Arduino core for the IDE. + +### Downgrade the ESP arduino core to v1.0.6 + +* This (3.x) branch only compiles with, and is only supported on, the old [v1.0.6](https://github.com/espressif/arduino-esp32/releases/tag/1.0.6) version of the expressif arduino core. +* Before compiling you must select this version in the Boards manager of the IDE: +![Selecting the correct IDE core version](Docs/v3x-select-106-ide-core.png) +* If you later upgrade back to the latest camera version or want to program other esp32 based boards do not forget to revert this when done programming. + +## Programming: + * If you have a development board (anything that can be programmed via a standard USB cable/jack on the board itself) you are in luck. Just plug it in and skip ahead to the [config](#config) section. Remember to set your board model. * The AI-THINKER board requires use of an external **3.3v** serial adapter to program; I use a `FTDI Friend` adapter, for more about this read AdaFruits excellent [FTDI Friend guide](https://learn.adafruit.com/ftdi-friend). * Be careful not to use a 5v serial adapter since this will damage the ESP32. @@ -127,18 +139,4 @@ I would also like to shoutout to @jmfloyd; who suggested rotating the image in t ## Contributing -Contributions are welcome; please see the [Contribution guidelines](CONTRIBUTING.md). - -## Plans - -Time allowing; my Current plan is: - -V4 Remove face recognition entirely; -* Dont try to make it optional, this is a code and maintenance nightmare. V3 can be maintained on a branch for those who need it. -* Investigate using SD card to capture images -* implement OTA and a better network stack for remembering multiple AP's, auto-config etc. -* UI Skinning/Theming -* OSD - * Temperature/humidity/pressure sensor suport (bme20,dht11) -You can check the [enhancement list](https://github.com/easytarget/esp32-cam-webserver/issues?q=is%3Aissue+label%3Aenhancement) (past and present), and add any thoghts you may have there. - +Contributions for the main branch are welcome; please see the [Contribution guidelines](CONTRIBUTING.md). From 0bd175366c3e0f8311d030a320a1efb368710ed2 Mon Sep 17 00:00:00 2001 From: Owen Carter Date: Tue, 8 Mar 2022 12:37:07 +0100 Subject: [PATCH 14/14] be slightly more explicit in instructions --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1e378f1..a88785f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ### This is the *old* 3.x branch of the project, with Face Recognition, but no Over The Air updates I will continue to fix bugs as needed on this branch for the forseeable future, but will not be adding any new features -You need to **downgrade** the esp32 board definition in the Arduino IDE to use this, instructions are below but please understand that this is not really recommended, the only reason you should be using this branch is to investigate the (very limited!) Face Recognition features of the camera module. +You need to **downgrade** the esp32 board definition in the Arduino IDE to an old version (v1.0.6) to use this, instructions are below but please understand that this is not really recommended, the only reason you should be using this branch is to investigate the (very limited!) Face Recognition features of the camera module. See the [master](https://github.com/easytarget/esp32-cam-webserver/tree/master/) branch for the current (v4+) version which has lost the basic Face Recognition features, but gained Over The Air updates and other new features. @@ -60,7 +60,7 @@ The existing [issues list](https://github.com/easytarget/esp32-cam-webserver/iss ### Downgrade the ESP arduino core to v1.0.6 -* This (3.x) branch only compiles with, and is only supported on, the old [v1.0.6](https://github.com/espressif/arduino-esp32/releases/tag/1.0.6) version of the expressif arduino core. +* This (3.x) branch only compiles with, *and is only supported on*, the old [v1.0.6](https://github.com/espressif/arduino-esp32/releases/tag/1.0.6) version of the expressif arduino core. * Before compiling you must select this version in the Boards manager of the IDE: ![Selecting the correct IDE core version](Docs/v3x-select-106-ide-core.png) * If you later upgrade back to the latest camera version or want to program other esp32 based boards do not forget to revert this when done programming. @@ -81,10 +81,9 @@ Is pretty simple, You just need jumper wires, no soldering really required, see * You must supply 5v to the ESP32 in order to power it during programming, the FTDI board can supply this. ### Download the Sketch, Unpack and Rename -Download the latest release of the sketch from https://github.com/easytarget/esp32-cam-webserver/releases/latest -- You can get the latest stable development release by cloning / downloading the `master` branch of the repo. +Download the latest 3.X release of the sketch from https://github.com/easytarget/esp32-cam-webserver/releases?q=v3.&expanded=true -This will give you an archive file with the Version number in it, eg.`esp32-cam-webserver-3.0.zip`. Tou need to unpack this into your Arduino sketch folder, and then you need to rename the folder you just extracted to remove the version number, eg.`esp32-cam-webserver-3.0` becomes `esp32-cam-webserver`. +This will give you an archive file with the Version number in it, eg.`esp32-cam-webserver-3.5.zip`. Tou need to unpack this into your Arduino sketch folder, and then you need to rename the folder you just extracted to remove the version number, eg.`esp32-cam-webserver-3.0` becomes `esp32-cam-webserver`. Once you have done that you can open the sketch in the IDE by going to the `esp32-cam-webserver` sketch folder and selecting `esp32-cam-webserver.ino`.