diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index db24e40..0000000 --- a/.travis.yml +++ /dev/null @@ -1,42 +0,0 @@ -sudo: false - -language: bash - -os: - - linux - -dist: focal - -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 - - 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 - - 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: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 - 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` diff --git a/Docs/v3x-select-106-ide-core.png b/Docs/v3x-select-106-ide-core.png new file mode 100644 index 0000000..1a3ef53 Binary files /dev/null and b/Docs/v3x-select-106-ide-core.png differ diff --git a/README.md b/README.md index 987087e..a88785f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,12 @@ -# 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 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. ## Taken from the ESP examples, and expanded This sketch is a extension/expansion/rework of the 'official' ESP32 Camera example sketch from Espressif: @@ -49,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. @@ -63,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`. @@ -81,6 +98,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. @@ -119,18 +138,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). diff --git a/app_httpd.cpp b/app_httpd.cpp index a8ab2d4..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" @@ -104,6 +106,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}; @@ -252,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); @@ -295,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; } @@ -325,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(); @@ -384,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); @@ -421,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; } @@ -601,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; @@ -827,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 @@ -872,13 +903,27 @@ 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 + 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 2f9ed1e..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) @@ -241,6 +250,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 +396,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 +442,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); @@ -473,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; @@ -589,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); @@ -620,21 +652,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); @@ -655,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/jsonlib/jsonlib.cpp b/src/jsonlib/jsonlib.cpp index 2aa8ede..4a5c454 100644 --- a/src/jsonlib/jsonlib.cpp +++ b/src/jsonlib/jsonlib.cpp @@ -70,15 +70,16 @@ 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 == '\"'){ //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 +112,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; } diff --git a/src/version.h b/src/version.h index eb1c845..4d4c54a 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.5"; 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"