Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stream view fix, Status dump #63

Merged
merged 6 commits into from
Oct 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 94 additions & 25 deletions app_httpd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "esp_camera.h"
#include "img_converters.h"
#include "Arduino.h"
#include <WiFi.h>

#include "index_ov2640.h"
#include "index_ov3660.h"
Expand All @@ -31,14 +32,22 @@ extern void flashLED(int flashtime);
extern void setLamp(int newVal);

// External variables declared in main .ino
extern char myName[]; // Camera Name
extern char myVer[]; // Firmware Build Info
extern int myRotation; // Rotation
extern int lampVal; // The current Lamp value
extern char streamURL[]; // Stream URL
extern int8_t detection_enabled; // Face detection enable
extern int8_t recognition_enabled; // Face recognition enable
extern bool filesystem; // Save/restore features enabled
extern char myName[];
extern char myVer[];
extern int myRotation;
extern int lampVal;
extern char streamURL[];
extern int8_t detection_enabled;
extern int8_t recognition_enabled;
extern bool filesystem;
extern int httpPort;
extern int streamPort;
extern IPAddress ip;
extern IPAddress net;
extern IPAddress gw;
extern int sketchSize;
extern int sketchSpace;
extern String sketchMD5;

#include "fb_gfx.h"
#include "fd_forward.h"
Expand Down Expand Up @@ -659,7 +668,6 @@ static esp_err_t info_handler(httpd_req_t *req){
char * p = json_response;
*p++ = '{';
p+=sprintf(p, "\"cam_name\":\"%s\",", myName);
p+=sprintf(p, "\"code_ver\":\"%s\",", myVer);
p+=sprintf(p, "\"rotate\":\"%d\",", myRotation);
p+=sprintf(p, "\"stream_url\":\"%s\"", streamURL);
*p++ = '}';
Expand Down Expand Up @@ -687,19 +695,81 @@ static esp_err_t favicon_ico_handler(httpd_req_t *req){
return httpd_resp_send(req, (const char *)favicon_ico, favicon_ico_len);
}

// DEBUG
extern void dumpPrefs(fs::FS &fs);
static esp_err_t dump_prefs_handler(httpd_req_t *req){
static esp_err_t dump_handler(httpd_req_t *req){
flashLED(75);
Serial.println("\nDump Requested");
Serial.print("Preferences file: ");
dumpPrefs(SPIFFS);
Serial.printf("mtmn_config size: %u :: ra_filter size: %u :: id_list %u\n", sizeof(mtmn_config), sizeof(ra_filter), sizeof(id_list));
httpd_resp_set_type(req, "text/css");
static char dumpOut[1200] = "n";
char * d = dumpOut;
// Header
d+= sprintf(d,"<html><head><meta charset=\"utf-8\">\n");
d+= sprintf(d,"<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n");
d+= sprintf(d,"<title>%s - Status</title>\n", myName);
d+= sprintf(d,"<link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/favicon-32x32.png\">\n");
d+= sprintf(d,"<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/favicon-16x16.png\">\n");
d+= sprintf(d,"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">\n");
d+= sprintf(d,"</head>\n<body>\n");
d+= sprintf(d,"<h1>ESP32 Cam Webserver</h1>\n");
// Module
d+= sprintf(d,"Name: %s<br>\n", myName);
Serial.printf("Name: %s\n", myName);
d+= sprintf(d,"Firmware: %s<br>\n", myVer);
Serial.printf("Firmware: %s\n", myVer);
float sketchPct = 100 * sketchSize / sketchSpace;
d+= sprintf(d,"Sketch Size: %i (total: %i, %.1f%% used)<br>\n", sketchSize, sketchSpace, sketchPct);
Serial.printf("Sketch Size: %i (total: %i, %.1f%% used)\n", sketchSize, sketchSpace, sketchPct);
d+= sprintf(d,"MD5: %s<br>\n", sketchMD5.c_str());
Serial.printf("MD5: %s\n", sketchMD5.c_str());
d+= sprintf(d,"ESP sdk: %s<br>\n", ESP.getSdkVersion());
Serial.printf("ESP sdk: %s\n", ESP.getSdkVersion());
// Network
d+= sprintf(d,"<h2>WiFi</h2>\n");
String ssidName = WiFi.SSID();
d+= sprintf(d,"SSID: %s<br>\n", ssidName.c_str());
Serial.printf("Ssid: %s\n", ssidName.c_str());
d+= sprintf(d,"Rssi: %i<br>\n", WiFi.RSSI());
Serial.printf("Rssi: %i\n", WiFi.RSSI());
d+= sprintf(d,"Http port: %i, Stream port: %i<br>\n", httpPort, streamPort);
Serial.printf("Http port: %i, Stream port: %i\n", httpPort, streamPort);
d+= sprintf(d,"IP address: %d.%d.%d.%d<br>\n", ip[0], ip[1], ip[2], ip[3]);
Serial.printf("IP address: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
d+= sprintf(d,"Netmask: %d.%d.%d.%d<br>\n", net[0], net[1], net[2], net[3]);
Serial.printf("Netmask: %d.%d.%d.%d\n", net[0], net[1], net[2], net[3]);
d+= sprintf(d,"Gateway: %d.%d.%d.%d<br>\n", gw[0], gw[1], gw[2], gw[3]);
Serial.printf("Gateway: %d.%d.%d.%d\n", gw[0], gw[1], gw[2], gw[3]);
// System
d+= sprintf(d,"<h2>System</h2>\n");
int64_t sec = esp_timer_get_time() / 1000000;
int64_t upDays = int64_t(floor(sec/86400));
int upHours = int64_t(floor(sec/3600)) % 24;
int upMin = int64_t(floor(sec/60)) % 60;
int upSec = sec % 60;
d+= sprintf(d,"Up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)<br>\n", upDays, upHours, upMin, upSec);
Serial.printf("Up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)\n", upDays, upHours, upMin, upSec);
d+= sprintf(d,"Freq: %i MHz<br>\n", ESP.getCpuFreqMHz());
Serial.printf("Freq: %i MHz\n", ESP.getCpuFreqMHz());
d+= sprintf(d,"Heap: %i, free: %i, min free: %i, max block: %i<br>\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap());
Serial.printf("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<br>\n", ESP.getPsramSize(), ESP.getFreePsram(), ESP.getMinFreePsram(), ESP.getMaxAllocPsram());
Serial.printf("Psram: %i, free: %i, min free: %i, max block: %i\n", ESP.getPsramSize(), ESP.getFreePsram(), ESP.getMinFreePsram(), ESP.getMaxAllocPsram());
if (filesystem) {
d+= sprintf(d,"Spiffs: %i, used: %i<br>\n", SPIFFS.totalBytes(), SPIFFS.usedBytes());
Serial.printf("Spiffs: %i, used: %i\n", SPIFFS.totalBytes(), SPIFFS.usedBytes());
}
// Following is debug while implementing FaceDB dump
// d+= sprintf(d,"mtmn_config size: %u<br>ra_filter size: %u<br>id_list %u<br>\n", sizeof(mtmn_config), sizeof(ra_filter), sizeof(id_list));
// Serial.printf("mtmn_config size: %u<br>ra_filter size: %u<br>id_list %u\n", sizeof(mtmn_config), sizeof(ra_filter), sizeof(id_list));
// Footer
d+= sprintf(d,"<br><div class=\"input-group\">\n");
d+= sprintf(d,"<button title=\"Refresh this page\" onclick=\"location.replace(document.URL)\">Refresh</button>\n");
d+= sprintf(d,"<button title=\"Close this page\" onclick=\"javascript:window.close()\">Close</button>\n");
d+= sprintf(d,"</div>\n</body>\n</html>\n");
*d++ = 0;
httpd_resp_set_type(req, "text/html");
httpd_resp_set_hdr(req, "Content-Encoding", "identity");
char resp[] = "DEBUG: Preferences file Dumped to serial";
return httpd_resp_send(req, resp, strlen(resp));
return httpd_resp_send(req, dumpOut, strlen(dumpOut));
}
// /DEBUG


static esp_err_t style_handler(httpd_req_t *req){
httpd_resp_set_type(req, "text/css");
Expand Down Expand Up @@ -737,7 +807,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 = 10; // we use more than the default 8 (on port 80)
config.max_uri_handlers = 12; // we use more than the default 8 (on port 80)

httpd_uri_t index_uri = {
.uri = "/",
Expand Down Expand Up @@ -794,10 +864,10 @@ void startCameraServer(int hPort, int sPort){
.user_ctx = NULL
};
// DEBUG
httpd_uri_t dump_prefs_uri = {
httpd_uri_t dump_uri = {
.uri = "/dump",
.method = HTTP_GET,
.handler = dump_prefs_handler,
.handler = dump_handler,
.user_ctx = NULL
};
// DEBUG
Expand Down Expand Up @@ -835,11 +905,12 @@ void startCameraServer(int hPort, int sPort){
mtmn_config.o_threshold.nms = 0.7;
mtmn_config.o_threshold.candidate_number = 1;
face_id_init(&id_list, FACE_ID_SAVE_NUMBER, ENROLL_CONFIRM_TIMES);

config.server_port = hPort;
config.ctrl_port = hPort;
Serial.printf("Starting web server on port: '%d'\n", config.server_port);
if (httpd_start(&camera_httpd, &config) == ESP_OK) {
// Note; config.max_uri_handlers (above) must be >= the number of handlers
httpd_register_uri_handler(camera_httpd, &index_uri);
httpd_register_uri_handler(camera_httpd, &cmd_uri);
httpd_register_uri_handler(camera_httpd, &status_uri);
Expand All @@ -849,7 +920,7 @@ void startCameraServer(int hPort, int sPort){
httpd_register_uri_handler(camera_httpd, &favicon_16x16_uri);
httpd_register_uri_handler(camera_httpd, &favicon_32x32_uri);
httpd_register_uri_handler(camera_httpd, &favicon_ico_uri);
httpd_register_uri_handler(camera_httpd, &dump_prefs_uri); // DEBUG
httpd_register_uri_handler(camera_httpd, &dump_uri);
}


Expand All @@ -864,6 +935,4 @@ void startCameraServer(int hPort, int sPort){
httpd_register_uri_handler(stream_httpd, &favicon_32x32_uri);
httpd_register_uri_handler(stream_httpd, &favicon_ico_uri);
}

Serial.printf("mtmn_config size: %u :: ra_filter size: %u :: id_list %u\n", sizeof(mtmn_config), sizeof(ra_filter), sizeof(id_list));
}
4 changes: 0 additions & 4 deletions css.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,9 @@ section.main {
figure {
padding: 0px;
margin: 0;
-webkit-margin-before: 0;
margin-block-start: 0;
-webkit-margin-after: 0;
margin-block-end: 0;
-webkit-margin-start: 0;
margin-inline-start: 0;
-webkit-margin-end: 0;
margin-inline-end: 0
}

Expand Down
42 changes: 28 additions & 14 deletions esp32-cam-webserver.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,23 @@
/* This sketch is a extension/expansion/reork of the 'official' ESP32 Camera example
* sketch from Expressif:
* https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/Camera/CameraWebServer
*
*
* It is modified to allow control of Illumination LED Lamps's (present on some modules),
* greater feedback via a status LED, and the HTML contents are present in plain text
* for easy modification.
*
* for easy modification.
*
* A camera name can now be configured, and wifi details can be stored in an optional
* header file to allow easier updated of the repo.
*
* The web UI has had minor changes to add the lamp control when present, I have made the
* 'Start Stream' controls more accessible, and add feedback of the camera name/firmware.
*
*
* The web UI has had changes to add the lamp control, rotation, a standalone viewer,
* more feeedback, new controls and other tweaks and changes,
* note: Make sure that you have either selected ESP32 AI Thinker,
* or another board which has PSRAM enabled to use high resolution camera modes
*/


/*
* FOR NETWORK AND HARDWARE SETTINGS COPY OR RENAME 'myconfig.sample.h' to 'myconfig.h' AND EDIT THAT.
* FOR NETWORK AND HARDWARE SETTINGS COPY OR RENAME 'myconfig.sample.h' TO 'myconfig.h' AND EDIT THAT.
*
* By default this sketch will assume an AI-THINKER ESP-CAM and create
* an accesspoint called "ESP32-CAM-CONNECT" (password: "InsecurePassword")
Expand Down Expand Up @@ -51,6 +50,16 @@
// used for non-volatile camera settings and face DB store
#include "storage.h"

// Sketch Info
int sketchSize;
int sketchSpace;
String sketchMD5;

// IP address, netmask and gateway
IPAddress ip;
IPAddress net;
IPAddress gw;

// Declare external function from app_httpd.cpp
extern void startCameraServer(int hPort, int sPort);

Expand Down Expand Up @@ -102,7 +111,7 @@ int myRotation = CAM_ROTATION;
#endif
#else
int lampVal = -1; // no lamp pin assigned
#endif
#endif

int lampChannel = 7; // a free PWM channel (some channels used by camera)
const int pwmfreq = 50000; // 50K pwm frequency
Expand Down Expand Up @@ -213,7 +222,7 @@ void WifiSetup(){
delay(WIFI_WATCHDOG / 10);
Serial.print('.');
}

// If we have connected, show details
if (WiFi.status() == WL_CONNECTED) {
Serial.println(" Succeeded");
Expand Down Expand Up @@ -392,25 +401,30 @@ void setup() {
startCameraServer(httpPort, streamPort);

// find our IP address
IPAddress ip;
char httpURL[64] = {"Unknown"};
#if defined(WIFI_AP_ENABLE)
ip = WiFi.softAPIP();
#else
ip = WiFi.localIP();
#endif
net = WiFi.subnetMask();
gw = WiFi.gatewayIP();
// Construct the App URL
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]);
}
Serial.printf("\nCamera Ready!\nUse '%s' to connect\n", httpURL);
// Construct the Stream URL
sprintf(streamURL, "http://%d.%d.%d.%d:%d/", ip[0], ip[1], ip[2], ip[3], streamPort);
// Inform the user
Serial.printf("\nCamera Ready!\nUse '%s' to connect\n", httpURL);
Serial.printf("Stream viewer available at '%s/view'\n", streamURL);
Serial.printf("Raw stream URL is '%s'\n", streamURL);
Serial.printf("Stream viewer available at '%sview'\n", streamURL);

// Used when dumpung status; slow functions, so do them here
sketchSize = ESP.getSketchSize();
sketchSpace = ESP.getFreeSketchSpace();
sketchMD5 = ESP.getSketchMD5();
}

void loop() {
Expand Down
34 changes: 9 additions & 25 deletions index_ov2640.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,6 @@ const uint8_t index_ov2640_html[] = R"=====(
flex-wrap: nowrap;
align-items: stretch
}

figure img {
display: block;
max-width: 100%;
width: auto;
height: auto
}

figure {
padding: 0 0 0 0px;
margin: 0;
-webkit-margin-before: 0;
margin-block-start: 0;
-webkit-margin-after: 0;
margin-block-end: 0;
-webkit-margin-start: 0;
margin-inline-start: 0;
-webkit-margin-end: 0;
margin-inline-end: 0
}
}
</style>
</head>
Expand Down Expand Up @@ -274,7 +254,8 @@ const uint8_t index_ov2640_html[] = R"=====(
<button id="clear_prefs" title="Erase saved Preferences on camera module">Erase</button>
</div>
<div class="input-group" id="cam_name-group">
<label for="cam_name">Name:</label>
<label for="cam_name">
<a href="/dump" title="System Info" target="_blank">Name</a></label>
<div id="cam_name" class="default-action"></div>
</div>
<div class="input-group" id="code_ver-group">
Expand Down Expand Up @@ -303,6 +284,7 @@ const uint8_t index_ov2640_html[] = R"=====(
document.addEventListener('DOMContentLoaded', function (event) {
var baseHost = document.location.origin;
var streamURL = 'Undefined';
var viewerURL = 'Undefined';

const settings = document.getElementById('sidebar')
const waitSettings = document.getElementById('wait-settings')
Expand Down Expand Up @@ -391,14 +373,16 @@ const uint8_t index_ov2640_html[] = R"=====(
rotate.value = value;
applyRotation();
} else if(el.id === "stream_url"){
streamURL = value;
viewerURL = value + 'view';
stream_url.innerHTML = value;
stream_link.setAttribute("title", "Open stream viewer ( " + value + "view )");
stream_link.setAttribute("title", "Open stream viewer (" + viewerURL + ")");
stream_link.style.textDecoration = "underline";
stream_link.style.cursor = "pointer";
streamURL = value;
streamButton.setAttribute("title", `You can also browse to '${streamURL}' for a raw stream`);
show(streamGroup)
console.log('Stream URL set to:' + value);
console.log('Stream URL set to: ' + streamURL);
console.log('Stream Viewer URL set to: ' + viewerURL);
}
}
}
Expand Down Expand Up @@ -495,7 +479,7 @@ const uint8_t index_ov2640_html[] = R"=====(

streamLink.onclick = () => {
stopStream();
window.open(streamURL + "view", "_blank");
window.open(viewerURL, "_blank");
}

stillButton.onclick = () => {
Expand Down
Loading