Skip to content

Commit

Permalink
Xclock in gui and stream stop button
Browse files Browse the repository at this point in the history
  • Loading branch information
easytarget committed Mar 8, 2022
1 parent 4b6cd9a commit de01547
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 34 deletions.
42 changes: 32 additions & 10 deletions app_httpd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ extern int sketchSpace;
extern String sketchMD5;
extern bool otaEnabled;
extern char otaPassword[];
extern unsigned long xclkFreqHz;
extern unsigned long xclk;

typedef struct {
httpd_req_t *req;
Expand All @@ -78,6 +78,9 @@ static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %
httpd_handle_t stream_httpd = NULL;
httpd_handle_t camera_httpd = NULL;

// Flag that can be set to kill all active streams
bool streamKill;

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -141,10 +144,9 @@ void serialDump() {
int upSec = sec % 60;
int McuTc = (temprature_sens_read() - 32) / 1.8; // celsius
int McuTf = temprature_sens_read(); // fahrenheit
float xclk = xclkFreqHz/1000000;
Serial.printf("System up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)\r\n", upDays, upHours, upMin, upSec);
Serial.printf("Active streams: %i, Previous streams: %lu, Images captured: %lu\r\n", streamCount, streamsServed, imagesServed);
Serial.printf("CPU Freq: %i MHz, Xclk Freq: %.1f MHz\r\n", ESP.getCpuFreqMHz(), xclk);
Serial.printf("CPU Freq: %i MHz, Xclk Freq: %i MHz\r\n", ESP.getCpuFreqMHz(), xclk);
Serial.printf("MCU temperature : %i C, %i F (approximate)\r\n", McuTc, McuTf);
Serial.printf("Heap: %i, free: %i, min free: %i, max block: %i\r\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap());
if(psramFound()) {
Expand Down Expand Up @@ -223,6 +225,8 @@ static esp_err_t stream_handler(httpd_req_t *req){
uint8_t * _jpg_buf = NULL;
char * part_buf[64];

streamKill = false;

Serial.println("Stream requested");
if (autoLamp && (lampVal != -1)) setLamp(lampVal);
streamCount = 1; // at present we only have one stream handler, so values are 0 or 1..
Expand Down Expand Up @@ -277,7 +281,7 @@ static esp_err_t stream_handler(httpd_req_t *req){
free(_jpg_buf);
_jpg_buf = NULL;
}
if(res != ESP_OK){
if((res != ESP_OK) || streamKill){
// This is the only exit point from the stream loop.
// We end the stream here only if a Hard failure has been encountered or the connection has been interrupted.
break;
Expand Down Expand Up @@ -341,6 +345,7 @@ static esp_err_t cmd_handler(httpd_req_t *req){
if(s->pixformat == PIXFORMAT_JPEG) res = s->set_framesize(s, (framesize_t)val);
}
else if(!strcmp(variable, "quality")) res = s->set_quality(s, val);
else if(!strcmp(variable, "xclk")) { xclk = val; res = s->set_xclk(s, LEDC_TIMER_0, val); }
else if(!strcmp(variable, "contrast")) res = s->set_contrast(s, val);
else if(!strcmp(variable, "brightness")) res = s->set_brightness(s, val);
else if(!strcmp(variable, "saturation")) res = s->set_saturation(s, val);
Expand Down Expand Up @@ -421,6 +426,7 @@ static esp_err_t status_handler(httpd_req_t *req){
p+=sprintf(p, "\"autolamp\":%d,", autoLamp);
p+=sprintf(p, "\"framesize\":%u,", s->status.framesize);
p+=sprintf(p, "\"quality\":%u,", s->status.quality);
p+=sprintf(p, "\"xclk\":%u,", xclk);
p+=sprintf(p, "\"brightness\":%d,", s->status.brightness);
p+=sprintf(p, "\"contrast\":%d,", s->status.contrast);
p+=sprintf(p, "\"saturation\":%d,", s->status.saturation);
Expand Down Expand Up @@ -495,7 +501,7 @@ static esp_err_t logo_svg_handler(httpd_req_t *req){

static esp_err_t dump_handler(httpd_req_t *req){
flashLED(75);
Serial.println("\r\nDump Requested via Web");
Serial.println("\r\nDump requested via Web");
serialDump();
static char dumpOut[2000] = "";
char * d = dumpOut;
Expand Down Expand Up @@ -566,11 +572,10 @@ static esp_err_t dump_handler(httpd_req_t *req){
int upSec = sec % 60;
int McuTc = (temprature_sens_read() - 32) / 1.8; // celsius
int McuTf = temprature_sens_read(); // fahrenheit
float xclk = xclkFreqHz/1000000;

d+= sprintf(d,"Up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)<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,"CPU Freq: %i MHz, Xclk Freq: %.1f MHz<br>\n", ESP.getCpuFreqMHz(), xclk);
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());
Expand All @@ -590,6 +595,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.
Expand All @@ -601,6 +607,15 @@ static esp_err_t dump_handler(httpd_req_t *req){
return httpd_resp_send(req, dumpOut, strlen(dumpOut));
}

static esp_err_t stop_handler(httpd_req_t *req){
flashLED(75);
Serial.println("\r\nStream stop requested via Web");
streamKill = true;
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}


static esp_err_t style_handler(httpd_req_t *req){
httpd_resp_set_type(req, "text/css");
httpd_resp_set_hdr(req, "Content-Encoding", "identity");
Expand All @@ -609,15 +624,15 @@ 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);
}

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)
Expand Down Expand Up @@ -705,7 +720,7 @@ static esp_err_t index_handler(httpd_req_t *req){

void startCameraServer(int hPort, int sPort){
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.max_uri_handlers = 12; // we use more than the default 8 (on port 80)
config.max_uri_handlers = 16; // we use more than the default 8 (on port 80)

httpd_uri_t index_uri = {
.uri = "/",
Expand Down Expand Up @@ -767,6 +782,12 @@ void startCameraServer(int hPort, int sPort){
.handler = dump_handler,
.user_ctx = NULL
};
httpd_uri_t stop_uri = {
.uri = "/stop",
.method = HTTP_GET,
.handler = stop_handler,
.user_ctx = NULL
};
httpd_uri_t stream_uri = {
.uri = "/",
.method = HTTP_GET,
Expand Down Expand Up @@ -817,6 +838,7 @@ void startCameraServer(int hPort, int sPort){
httpd_register_uri_handler(camera_httpd, &favicon_ico_uri);
httpd_register_uri_handler(camera_httpd, &logo_svg_uri);
httpd_register_uri_handler(camera_httpd, &dump_uri);
httpd_register_uri_handler(camera_httpd, &stop_uri);
}

config.server_port = sPort;
Expand Down
10 changes: 5 additions & 5 deletions esp32-cam-webserver.ino
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,12 @@ unsigned long imagesServed = 0; // Total image requests
char myVer[] PROGMEM = __DATE__ " @ " __TIME__;

// Camera module bus communications frequency.
// Originally: config.xclk_freq_hz = 20000000, but this lead to visual artifacts on many modules.
// Originally: config.xclk_freq_mhz = 20000000, but this lead to visual artifacts on many modules.
// See https://github.com/espressif/esp32-camera/issues/150#issuecomment-726473652 et al.
#if !defined (XCLK_FREQ_HZ)
unsigned long xclkFreqHz = 16500000;
#if !defined (XCLK_FREQ_MHZ)
unsigned long xclk = 16;
#else
unsigned long xclkFreqHz = XCLK_FREQ_HZ;
unsigned long xclk = XCLK_FREQ_MHZ;
#endif

// initial rotation
Expand Down Expand Up @@ -524,7 +524,7 @@ void setup() {
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = xclkFreqHz;
config.xclk_freq_hz = xclk * 1000000;
config.pixel_format = PIXFORMAT_JPEG;
config.grab_mode = CAMERA_GRAB_LATEST;
// Pre-allocate large buffers
Expand Down
14 changes: 14 additions & 0 deletions index_ov2640.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -292,6 +299,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')
Expand Down Expand Up @@ -395,6 +403,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
Expand Down Expand Up @@ -562,6 +571,11 @@ const uint8_t index_ov2640_html[] = R"=====(<!doctype html>
updateConfig(framesize)
}

xclk.onchange = () => {
console.log("xclk:" , xclk);
updateConfig(xclk)
}

swapButton.onclick = () => {
window.open('/?view=simple','_self');
}
Expand Down
14 changes: 14 additions & 0 deletions index_ov3660.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -306,6 +313,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')
Expand Down Expand Up @@ -407,6 +415,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
Expand Down Expand Up @@ -571,6 +580,11 @@ const uint8_t index_ov3660_html[] = R"=====(<!doctype html>
updateConfig(framesize)
}

xclk.onchange = () => {
console.log("xclk:" , xclk);
updateConfig(xclk)
}

swapButton.onclick = () => {
window.open('/?view=simple','_self');
}
Expand Down
37 changes: 19 additions & 18 deletions myconfig.sample.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
/*
* Rename this example to 'myconfig.h' and fill in your details.
*
*
* The local config is in the '.gitignore' file, which helps to keep details secret.
*/

Expand All @@ -11,7 +11,7 @@

/*
* WiFi Settings
*
*
* For the simplest connection to an existing network
* just replace your ssid and password in the line below.
*/
Expand All @@ -31,18 +31,18 @@ struct station stationList[] = {{"ssid1", "pass1", true},
* it will be used for the AccessPoint ssid and password. See the comments there for more.
*
* The 'dhcp' setting controls whether the station uses DHCP or static IP settings; if in doubt leave 'true'
*
*
* You can also use a BSSID (eg: "2F:67:94:F5:BB:6A", a colon separated mac address string) in place of
* the ssid to force connections to specific networks even when the ssid's collide,
*/

/* Extended WiFi Settings */

/*
/*
* Hostname. Optional, uncomment and set if desired
* - used in DHCP request when connecting to networks, not used in AP mode
* - Most useful when used with a static netwrk config, not all routers respect this setting
*
*
* The URL_HOSTNAME will be used in place of the IP address in internal URL's
*/

Expand All @@ -51,22 +51,22 @@ struct station stationList[] = {{"ssid1", "pass1", true},

/*
* Static network settings for client mode
*
*
* Note: The same settings will be applied to all client connections where the dhcp setting is 'false'
* You must define all three: IP, Gateway and NetMask
*/
// warning - IP addresses must be separated with commas (,) and not decimals (.)
// #define ST_IP 192,168,0,123
// #define ST_GATEWAY 192,168,0,2
// #define ST_GATEWAY 192,168,0,2
// #define ST_NETMASK 255,255,255,0
// One or two DNS servers can be supplied, only the NTP code currently uses them
// #define ST_DNS1 192,168,0,2
// #define ST_DNS2 8,8,8,8

/*
* AccessPoint;
/*
* AccessPoint;
*
* Uncomment to enable AP mode;
* Uncomment to enable AP mode;
*
*/
// #define WIFI_AP_ENABLE
Expand All @@ -79,7 +79,7 @@ struct station stationList[] = {{"ssid1", "pass1", true},
* if they are found. AP then works as a fallback mode for when there are no 'real' networks available.
*
* Setting the 'dhcp' field to true for the AP enables a captive portal and attempts to send
* all visitors to the webcam page, with varying degrees of success depending on the visitors
* all visitors to the webcam page, with varying degrees of success depending on the visitors
* browser and other settings.
*/
// Optionally change the AccessPoint ip address (default = 192.168.4.1)
Expand Down Expand Up @@ -184,9 +184,10 @@ struct station stationList[] = {{"ssid1", "pass1", true},
// #define CAMERA_MODEL_TTGO_T_JOURNAL
// #define CAMERA_MODEL_ARDUCAM_ESP32S_UNO

// Camera module bus communications frequency, setting too high can cause visual artifacts.
// Currently defaults to 16.5MHz, but some (non-clone) modules may be able to use the
// original frequency of 20MHz for to allow higher framerates etc.
// #define XCLK_FREQ_HZ 20000000;
// For clone modules that have camera module artifacts and SPIFFS issues; try setting this very low:
// #define XCLK_FREQ_HZ 3000000;
// Initial Camera module bus communications frequency
// Currently defaults to 8MHz
// The post-initialisation (runtime) value can be set and edited by the user in the UI
// For clone modules that have camera module and SPIFFS startup issues try setting
// this very low (start at 2MHZ and increase):
// #define XCLK_FREQ_MHZ 2

2 changes: 1 addition & 1 deletion src/version.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Version of upstream code */

char baseVersion[] = "4.0.beta3";
char baseVersion[] = "4.0.rc1";

5 changes: 5 additions & 0 deletions storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ extern void flashLED(int flashtime);
extern int myRotation; // Rotation
extern int lampVal; // The current Lamp value
extern int autoLamp; // Automatic lamp mode
extern int xclk; // Camera module clock speed

/*
* Useful utility when debugging...
Expand Down Expand Up @@ -90,8 +91,11 @@ void loadPrefs(fs::FS &fs){
// process all the settings
lampVal = jsonExtract(prefs, "lamp").toInt();
autoLamp = jsonExtract(prefs, "autolamp").toInt();
int xclkPref = jsonExtract(prefs, "xclk").toInt();
if (xclkPref != 0) xclk = xclkPref;
s->set_framesize(s, (framesize_t)jsonExtract(prefs, "framesize").toInt());
s->set_quality(s, jsonExtract(prefs, "quality").toInt());
s->set_xclk(s, LEDC_TIMER_0, xclk);
s->set_brightness(s, jsonExtract(prefs, "brightness").toInt());
s->set_contrast(s, jsonExtract(prefs, "contrast").toInt());
s->set_saturation(s, jsonExtract(prefs, "saturation").toInt());
Expand Down Expand Up @@ -138,6 +142,7 @@ void savePrefs(fs::FS &fs){
p+=sprintf(p, "\"autolamp\":%u,", autoLamp);
p+=sprintf(p, "\"framesize\":%u,", s->status.framesize);
p+=sprintf(p, "\"quality\":%u,", s->status.quality);
p+=sprintf(p, "\"xclk\":%u,", xclk);
p+=sprintf(p, "\"brightness\":%d,", s->status.brightness);
p+=sprintf(p, "\"contrast\":%d,", s->status.contrast);
p+=sprintf(p, "\"saturation\":%d,", s->status.saturation);
Expand Down

0 comments on commit de01547

Please sign in to comment.