Merge branch '4-0-rc1' into framerate_limit

This commit is contained in:
Owen Carter 2022-03-09 16:34:18 +01:00 committed by GitHub
commit cfe81b0ff8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 300 additions and 185 deletions

View File

@ -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

View File

@ -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

View File

@ -48,7 +48,11 @@ The ESP itself is susceptible to the usual list of WiFi problems, not helped by
A basic limitation of the sketch is that it can can only support one stream at a time. If you try to connect to a cam that is already streaming (or attempting to stream) you will get no response and, eventually, a timeout. The stream itself is a [MJPEG stream](https://en.wikipedia.org/wiki/Motion_JPEG), which relies on the client (the web browser) to hold the connection open and request each new frame in turn via javascript. This can cause errors when browsers run into Javascript or caching problem, fail to request new frames or refuse to close the connection.
* You can check the `/dump` page of the cam to see if it currently reports the camera as streaming or not.
The existing [issues list](https://github.com/easytarget/esp32-cam-webserver/issues?q=is%3Aissue) on Github is a good place to start if you have a specific issue not covered above.
A lot of common issues with this sketch are discussed and covered in the discussion forums:
https://github.com/easytarget/esp32-cam-webserver/discussions/categories/common-issues
The existing [issues list](https://github.com/easytarget/esp32-cam-webserver/issues?q=is%3Aissue) on Github is a good place to start if you have a specific issue not covered above or in the forums.
Note that I do not respond to any Private Messages (via github, hackaday, or wherever) for support.
@ -74,7 +78,7 @@ Is pretty simple, You just need jumper wires, no soldering really required, see
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.
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-4.0.zip`. You need to unpack this into your Arduino sketch folder, and then you need to **rename the folder you extracted to remove the version number**, eg.`esp32-cam-webserver-4.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`.
@ -142,16 +146,10 @@ Contributions are welcome; please see the [Contribution guidelines](CONTRIBUTING
Time allowing; my Current plan is:
V4
* Remove face recognition entirely;
* **Done**, see the `NoFace` branch :sunglasses:
* Not 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.
* **Basic OTA is Done**, see the `NoFace` branch.
* Implement a better network stack for remembering multiple AP's, auto-config etc.
* Advanced (web upload) OTA might be nice to have if possible
* For the Network setup I want to implement https://github.com/Hieromon/AutoConnect
* UI Skinning/Theming
* OSD
* Temperature/humidity/pressure sensor support (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 thoughts you may have there.

View File

@ -64,6 +64,7 @@ extern int sketchSpace;
extern String sketchMD5;
extern bool otaEnabled;
extern char otaPassword[];
extern unsigned long xclk;
typedef struct {
httpd_req_t *req;
@ -78,6 +79,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
@ -143,7 +147,7 @@ void serialDump() {
int McuTf = temprature_sens_read(); // fahrenheit
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: %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()) {
@ -173,7 +177,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();
@ -199,12 +206,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;
}
@ -215,6 +226,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..
@ -273,7 +286,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;
@ -340,6 +353,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);
@ -389,6 +403,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
@ -422,6 +437,7 @@ static esp_err_t status_handler(httpd_req_t *req){
p+=sprintf(p, "\"min_frame_time\":%d,", minFrameTime);
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);
@ -496,7 +512,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;
@ -570,7 +586,7 @@ static esp_err_t dump_handler(httpd_req_t *req){
d+= sprintf(d,"Up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)<br>\n", upDays, upHours, upMin, upSec);
d+= sprintf(d,"Active streams: %i, Previous streams: %lu, Images captured: %lu<br>\n", streamCount, streamsServed, imagesServed);
d+= sprintf(d,"Freq: %i MHz<br>\n", ESP.getCpuFreqMHz());
d+= sprintf(d,"CPU Freq: %i MHz, Xclk Freq: %i MHz<br>\n", ESP.getCpuFreqMHz(), xclk);
d+= sprintf(d,"<span title=\"NOTE: Internal temperature sensor readings can be innacurate on the ESP32-c1 chipset, and may vary significantly between devices!\">");
d+= sprintf(d,"MCU temperature : %i &deg;C, %i &deg;F</span>\n<br>", McuTc, McuTf);
d+= sprintf(d,"Heap: %i, free: %i, min free: %i, max block: %i<br>\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap());
@ -590,6 +606,7 @@ static esp_err_t dump_handler(httpd_req_t *req){
// Footer
d+= sprintf(d,"<br><div class=\"input-group\">\n");
d+= sprintf(d,"<button title=\"Instant Refresh; the page reloads every minute anyway\" onclick=\"location.replace(document.URL)\">Refresh</button>\n");
d+= sprintf(d,"<button title=\"Stop any active streams\" onclick=\"let throwaway = fetch('stop');setTimeout(function(){\nlocation.replace(document.URL);\n}, 200);\">Stop Stream</button>\n");
d+= sprintf(d,"<button title=\"Close this page\" onclick=\"javascript:window.close()\">Close</button>\n");
d+= sprintf(d,"</div>\n</body>\n");
// A javascript timer to refresh the page every minute.
@ -601,6 +618,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 +635,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 +643,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("<APPURL>")) != std::string::npos)
@ -705,7 +731,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 +793,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 +849,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;

View File

@ -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...

View File

@ -6,6 +6,7 @@
#include <ArduinoOTA.h>
#include "src/parsebytes.h"
#include "time.h"
#include <ESPmDNS.h>
/* This sketch is a extension/expansion/reork of the 'official' ESP32 Camera example
@ -95,7 +96,7 @@ extern void serialDump();
#endif
#if !defined(WIFI_WATCHDOG)
#define WIFI_WATCHDOG 8000
#define WIFI_WATCHDOG 15000
#endif
// Number of known networks in stationList[]
@ -134,10 +135,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)
#define XCLK_FREQ_HZ 16500000;
#if !defined (XCLK_FREQ_MHZ)
unsigned long xclk = 16;
#else
unsigned long xclk = XCLK_FREQ_MHZ;
#endif
// initial rotation
@ -482,8 +485,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();
@ -494,6 +495,16 @@ 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()){
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");
@ -508,6 +519,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;
@ -528,13 +545,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 = xclk * 1000000;
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;
@ -644,7 +662,7 @@ void setup() {
// check for saved preferences and apply them
if (filesystem) {
filesystemStart();
delay(200); // a short delay to let spi bus settle after camera init
loadPrefs(SPIFFS);
} else {
Serial.println("No Internal Filesystem, cannot load or save preferences");
@ -655,24 +673,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");
@ -714,7 +721,16 @@ void setup() {
ArduinoOTA.begin();
} else {
Serial.println("OTA is disabled");
if (!MDNS.begin(myName)) {
Serial.println("Error setting up MDNS responder!");
}
Serial.println("mDNS responder started");
}
//MDNS Config -- note that if OTA is NOT enabled this needs prior steps!
MDNS.addService("http", "tcp", 80);
Serial.println("Added HTTP service to MDNS server");
// Set time via NTP server when enabled
if (haveTime) {
@ -725,7 +741,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) {
@ -741,22 +772,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();
// 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");
}
void loop() {

View File

@ -36,11 +36,11 @@ const uint8_t index_simple_html[] = R"=====(<!doctype html>
<div class="hidden" id="sidebar">
<input type="checkbox" id="nav-toggle-cb">
<nav id="menu" style="width:24em;">
<div class="input-group hidden" id="lamp-group">
<div class="input-group hidden" id="lamp-group" title="Brightness of flashlight LED. Warning: Very bright! Be careful when increasing. Avoid looking directly at LED!>
<label for="lamp">Light</label>
<div class="range-min">Off</div>
<input type="range" id="lamp" min="0" max="100" value="0" class="action-setting">
<div class="range-max">Full</div>
<div class="range-max">Full&#9888;</div>
</div>
<div class="input-group" id="framesize-group">
<label for="framesize">Resolution</label>

View File

@ -35,16 +35,16 @@ const uint8_t index_ov2640_html[] = R"=====(<!doctype html>
<div class="hidden" id="sidebar">
<input type="checkbox" id="nav-toggle-cb" checked="checked">
<nav id="menu">
<div class="input-group hidden" id="lamp-group">
<div class="input-group hidden" id="lamp-group" title="Brightness of flashlight LED. Warning: Very bright! Be careful when increasing. Avoid looking directly at LED!">
<label for="lamp">Light</label>
<div class="range-min">Off</div>
<input type="range" id="lamp" min="0" max="100" value="0" class="default-action">
<div class="range-max">Full</div>
<div class="range-max">Full&#9888;</div>
</div>
<div class="input-group hidden" id="autolamp-group">
<div class="input-group hidden" id="autolamp-group" title="Lamp only on when camera active">
<label for="autolamp">Auto Lamp</label>
<div class="switch">
<input id="autolamp" type="checkbox" class="default-action" title="Lamp only on when camera active">
<input id="autolamp" type="checkbox" class="default-action">
<label class="slider" for="autolamp"></label>
</div>
</div>
@ -74,6 +74,13 @@ const uint8_t index_ov2640_html[] = R"=====(<!doctype html>
<input type="range" id="quality" min="6" max="63" value="10" class="default-action">
<div class="range-max">High<br><span style="font-size: 80%;">(slow)</span></div>
</div>
<div class="input-group" id="set-xclk-group">
<label for="set-xclk">XCLK</label>
<div class="text">
<input id="xclk" type="number" min="2" max="32" size="4" step="1" class="default-action">
<div class="range-max">MHz</div>
</div>
</div>
<div class="input-group" id="brightness-group">
<label for="brightness">Brightness</label>
<div class="range-min">-2</div>
@ -252,7 +259,7 @@ const uint8_t index_ov2640_html[] = R"=====(<!doctype html>
</select>
</div>
<div class="input-group" id="preferences-group">
<label for="reboot" style="line-height: 2em;">Preferences</label>
<label for="prefs" style="line-height: 2em;">Preferences</label>
<button id="reboot" title="Reboot the camera module">Reboot</button>
<button id="save_prefs" title="Save Preferences on camera module">Save</button>
<button id="clear_prefs" title="Erase saved Preferences on camera module">Erase</button>
@ -306,6 +313,7 @@ const uint8_t index_ov2640_html[] = R"=====(<!doctype html>
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')
@ -412,6 +420,7 @@ const uint8_t index_ov2640_html[] = R"=====(<!doctype html>
value = el.checked ? 1 : 0
break
case 'range':
case 'number':
case 'select-one':
value = el.value
break
@ -581,6 +590,10 @@ const uint8_t index_ov2640_html[] = R"=====(<!doctype html>
minFrameTime.onchange = () => {
updateConfig(minFrameTime)
xclk.onchange = () => {
console.log("xclk:" , xclk);
updateConfig(xclk)
}
swapButton.onclick = () => {

View File

@ -35,16 +35,16 @@ const uint8_t index_ov3660_html[] = R"=====(<!doctype html>
<div class="hidden" id="sidebar">
<input type="checkbox" id="nav-toggle-cb" checked="checked">
<nav id="menu">
<div class="input-group hidden" id="lamp-group">
<div class="input-group hidden" id="lamp-group" title="Brightness of flashlight LED. Warning: Very bright! Be careful when increasing. Avoid looking directly at LED!">
<label for="lamp">Light</label>
<div class="range-min">Off</div>
<input type="range" id="lamp" min="0" max="100" value="0" class="default-action">
<div class="range-max">Full</div>
<div class="range-max">Full&#9888;</div>
</div>
<div class="input-group hidden" id="autolamp-group">
<div class="input-group hidden" id="autolamp-group" title="Lamp only on when camera active">
<label for="autolamp">Auto Lamp</label>
<div class="switch">
<input id="autolamp" type="checkbox" class="default-action" title="Lamp only on when camera active">
<input id="autolamp" type="checkbox" class="default-action">
<label class="slider" for="autolamp"></label>
</div>
</div>
@ -76,6 +76,13 @@ const uint8_t index_ov3660_html[] = R"=====(<!doctype html>
<input type="range" id="quality" min="4" max="63" value="10" class="default-action">
<div class="range-max">High<br><span style="font-size: 80%;">(slow)</span></div>
</div>
<div class="input-group" id="set-xclk-group">
<label for="set-xclk">XCLK</label>
<div class="text">
<input id="xclk" type="number" min="2" max="32" size="4" step="1" class="default-action">
<div class="range-max">MHz</div>
</div>
</div>
<div class="input-group" id="brightness-group">
<label for="brightness">Brightness</label>
<div class="range-min">-3</div>
@ -266,7 +273,7 @@ const uint8_t index_ov3660_html[] = R"=====(<!doctype html>
</select>
</div>
<div class="input-group" id="preferences-group">
<label for="reboot" style="line-height: 2em;">Preferences</label>
<label for="prefs" style="line-height: 2em;">Preferences</label>
<button id="reboot" title="Reboot the camera module">Reboot</button>
<button id="save_prefs" title="Save Preferences on camera module">Save</button>
<button id="clear_prefs" title="Erase saved Preferences on camera module">Erase</button>
@ -320,6 +327,7 @@ const uint8_t index_ov3660_html[] = R"=====(<!doctype html>
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')
@ -424,6 +432,7 @@ const uint8_t index_ov3660_html[] = R"=====(<!doctype html>
value = el.checked ? 1 : 0
break
case 'range':
case 'number':
case 'select-one':
value = el.value
break
@ -590,6 +599,10 @@ const uint8_t index_ov3660_html[] = R"=====(<!doctype html>
minFrameTime.onchange = () => {
updateConfig(minFrameTime)
xclk.onchange = () => {
console.log("xclk:" , xclk);
updateConfig(xclk)
}
swapButton.onclick = () => {

View File

@ -5,7 +5,10 @@
*/
/* Give the camera a name for the web interface */
/* Give the camera a name for the web interface
* A word of warning: This name is also used for OTA updates and MDNS addressing.
* Pick something convenient!
*/
#define CAM_NAME "ESP32 camera server"
@ -99,9 +102,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
@ -161,6 +164,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
@ -185,8 +189,12 @@ 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
// 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
// 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;

View File

@ -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

View File

@ -1,4 +1,4 @@
/* Version of upstream code */
char baseVersion[] = "4.0.beta2";
char baseVersion[] = "4.0.rc1";

View File

@ -6,8 +6,8 @@
extern void flashLED(int flashtime);
extern int myRotation; // Rotation
extern int lampVal; // The current Lamp value
extern int autoLamp; // Automatic lamp mode
extern int minFrameTime; // Minimal frame duration
extern bool autoLamp; // Automatic lamp mode
extern int xclk; // Camera module clock speed
/*
* Useful utility when debugging...
@ -90,10 +90,13 @@ 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();
if (jsonExtract(prefs, "autolamp").toInt() == 0) autoLamp = false; else autoLamp = true;
minFrameTime = jsonExtract(prefs, "min_frame_time").toInt();
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());
s->set_saturation(s, jsonExtract(prefs, "saturation").toInt());
@ -141,6 +144,7 @@ void savePrefs(fs::FS &fs){
p+=sprintf(p, "\"min_frame_time\":%d,", minFrameTime);
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);
@ -183,10 +187,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
@ -195,6 +200,5 @@ void filesystemStart(){
delay(1000);
Serial.println("Retrying..");
}
Serial.println("Internal filesystem contents");
listDir(SPIFFS, "/", 0);
}