Skip to content

Commit b931cdc

Browse files
authored
v10.8.3
1 parent 8573c72 commit b931cdc

File tree

7 files changed

+82
-20
lines changed

7 files changed

+82
-20
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ The ESP32 cannot support all of the features as it will run out of heap space. F
2929
***This is a complex app and some users are raising issues when the app reports a warning, but this is the app notifying the user that there is an problem with their setup, which only the user can fix. Be aware that some clone boards have different specs to the original, eg PSRAM size. Please only raise issues for actual bugs (ERR messages, unhandled library error or crash). Thanks.
3030
To suggest an improvement or enhancement use Discussions.***
3131

32-
Changes for version 10.8.2:
32+
Changes for version 10.8.3:
3333
* Addition of [Ethernet](#configuration-web-page) network selection instead of Wifi
3434
* Pins added for [`CAMERA_MODEL_Waveshare_ESP32_S3_ETH`](https://www.waveshare.com/wiki/ESP32-S3-ETH)
3535
* Define pins for external W5500 Ethernet controller
3636
* Fix for issue [#650](https://github.com/s60sc/ESP32-CAM_MJPEG2SD/issues/650)
3737

3838
## Purpose
3939

40-
The application enables video capture of motion detection or continuous recording. Examples include security cameras, wildlife monitoring, rocket flight monitoring, FPV vehicle control. This [instructable](https://www.instructables.com/How-to-Make-a-WiFi-Security-Camera-ESP32-CAM-DIY-R/) by [Max Imagination](https://www.instructables.com/member/Max+Imagination/) shows how to build a WiFi Security Camera using an earlier version of this code, plus a later video on how to [install and use](https://www.youtube.com/watch?v=k_PJLkfqDuI&t=247s) the app.
40+
The application enables video capture of motion detection or continuous recording. Examples include security cameras, wildlife monitoring, rocket flight monitoring, FPV vehicle control.
4141

4242
Saving a set of JPEGs as a single file is faster than as individual files and is easier to manage, particularly for small image sizes. Actual rate depends on quality and size of SD card and complexity and quality of images. A no-name 4GB SDHC labelled as Class 6 was 3 times slower than a genuine Sandisk 4GB SDHC Class 2. The following recording rates were achieved on a freshly formatted Sandisk 4GB SDHC Class 2 on a AI Thinker OV2640 board, set to maximum JPEG quality and clock rate of 20MHz. With a clock rate of 24Mhz on ESP32S3, the maximum frame rates can increase 50->60, 25->30 but it may be necessary to reduce JPEG quality.
4343

appGlobals.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828

2929
// User's ESP32S3 cam board
3030
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
31-
#define CAMERA_MODEL_FREENOVE_ESP32S3_CAM
32-
//#define CAMERA_MODEL_ESP32_S3_CAM
31+
#define CAMERA_MODEL_ESP32_S3_CAM
32+
//#define CAMERA_MODEL_FREENOVE_ESP32S3_CAM
3333
//#define CAMERA_MODEL_XIAO_ESP32S3
3434
//#define CAMERA_MODEL_NEW_ESPS3_RE1_0
3535
//#define CAMERA_MODEL_M5STACK_CAMS3_UNIT
@@ -105,7 +105,7 @@
105105
#define USE_IP6 false // if true use IPv6 when available, else use IPv4
106106

107107

108-
/*********************** Fixed defines leave as is ***********************/
108+
/*********************** Fixed defines leave as is ************************/
109109
/** Do not change anything below here unless you know what you are doing **/
110110

111111
#ifndef AUXILIARY
@@ -121,7 +121,7 @@
121121
#define DOT_MAX 50
122122
#define HOSTNAME_GRP 99
123123

124-
#define APP_VER "10.8.2"
124+
#define APP_VER "10.8.3"
125125

126126
#if defined(AUXILIARY)
127127
#define APP_NAME "ESP-CAM_AUX" // max 15 chars
@@ -162,7 +162,7 @@
162162
#define ISCAM // cam specific code in generic cpp files
163163

164164
// to determine if newer data files need to be loaded
165-
#define CFG_VER 32
165+
#define CFG_VER 33
166166

167167
#define AVI_EXT "avi"
168168
#define CSV_EXT "csv"

camera_pins.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@
374374
#define SD_MMC_CLK 39
375375
#define SD_MMC_CMD 38
376376
#define SD_MMC_D0 40
377-
#if defined(CAMERA_MODEL_PCBFUN_ESP32S3_CAM)
377+
#if defined(CAMERA_MODEL_ESP32_S3_CAM)
378378
// uncomment following pins for SD MMC 4 bit mode
379379
//#define SD_MMC_D1 41
380380
//#define SD_MMC_D2 14

globals.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@
9797
#define USECS 1000000
9898
#define MAGIC_NUM 987654321
9999
#define MAX_FAIL 5
100+
#define SSESEP "\r\n\r\n" // SSE event separator
101+
#define PANIC_DELAY 5 // seconds before restart after panic
100102

101103
// global mandatory app specific functions, in appSpecific.cpp
102104
bool appDataFiles();
@@ -108,7 +110,8 @@ void appSpecificTelegramTask(void* p);
108110
void buildAppJsonString(bool filter);
109111
bool updateAppStatus(const char* variable, const char* value, bool fromUser = true);
110112

111-
// global general utility functions in utils.cpp / utilsFS.cpp / peripherals.cpp
113+
// global general utility functions in utils.cpp / utilsFS.cpp / peripherals.cpp etc
114+
void appPanicHandler(arduino_panic_info_t *info, void *arg);
112115
void buildJsonString(uint8_t filter);
113116
bool calcProgress(int progressVal, int totalVal, int percentReport, uint8_t &pcProgress);
114117
bool changeExtension(char* fileName, const char* newExt);
@@ -184,6 +187,7 @@ void resetWatchDog(int wdIndex, uint32_t wdTimeout = 1);
184187
bool retrieveConfigVal(const char* variable, char* value);
185188
void runTaskStats();
186189
esp_err_t sendChunks(File df, httpd_req_t *req, bool endChunking = true);
190+
void sendSSE(const char* statusData);
187191
void setFolderName(const char* fname, char* fileName);
188192
void setPeripheralResponse(const byte pinNum, const uint32_t responseData);
189193
void setupADC();
@@ -330,7 +334,6 @@ extern uint8_t alarmHour;
330334
extern char* jsonBuff;
331335
extern bool dbgVerbose;
332336
extern bool sdLog;
333-
extern char alertMsg[];
334337
extern int logType;
335338
extern char messageLog[];
336339
extern uint16_t mlogEnd;

prefs.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,6 @@ void buildJsonString(uint8_t filter) {
412412
buildAppJsonString((bool)filter);
413413
p += strlen(jsonBuff) - 1;
414414
p += sprintf(p, "\"cfgGroup\":\"-1\",");
415-
p += sprintf(p, "\"alertMsg\":\"%s\",", alertMsg);
416-
alertMsg[0] = 0;
417415
// generic footer
418416
currEpoch = getEpoch();
419417
p += sprintf(p, "\"clockUTC\":\"%lu\",", (uint32_t)currEpoch);

utils.cpp

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,11 @@ static uint32_t counter_write = 0;
903903
// RAM memory based logging in RTC slow memory (cannot init)
904904
RTC_NOINIT_ATTR char messageLog[RAM_LOG_LEN];
905905
RTC_NOINIT_ATTR uint16_t mlogEnd;
906+
static RTC_NOINIT_ATTR uint32_t backtrace[60]; // backtrace addresses array
907+
static RTC_NOINIT_ATTR size_t btLen;
908+
static RTC_NOINIT_ATTR char btReason[50];
909+
static RTC_NOINIT_ATTR int btCore;
910+
static RTC_NOINIT_ATTR uint32_t haveTrace;
906911

907912
static void ramLogClear() {
908913
mlogEnd = 0;
@@ -990,10 +995,11 @@ void logPrint(const char *format, ...) {
990995
// output to monitor console if attached
991996
size_t msgLen = strlen(outBuf);
992997
if (outBuf[msgLen - 2] == '~') {
993-
// set up alert message for browser
994-
outBuf[msgLen - 2] = ' ';
995-
strncpy(alertMsg, outBuf, MAX_OUT - 1);
996-
alertMsg[msgLen - 2] = 0;
998+
// set up alert message for browser using SSE
999+
outBuf[msgLen - 2] = ' '; // remove '~'
1000+
snprintf(alertMsg, MAX_OUT - 1, "event: alert\ndata: %s%s", outBuf, SSESEP);
1001+
sendSSE(alertMsg);
1002+
alertMsg[0] = 0;
9971003
}
9981004
ramLogStore(msgLen); // store in rtc ram
9991005
if (monitorOpen) Serial.print(outBuf);
@@ -1029,6 +1035,7 @@ int vprintfRedirect(const char* format, va_list args) {
10291035

10301036
void logSetup() {
10311037
// prep logging environment
1038+
set_arduino_panic_handler(appPanicHandler, NULL);
10321039
Serial.begin(115200);
10331040
Serial.setDebugOutput(DBG_ON);
10341041
printf("\n\n");
@@ -1044,8 +1051,8 @@ void logSetup() {
10441051
xSemaphoreGive(logMutex);
10451052
xTaskCreate(logTask, "logTask", LOG_STACK_SIZE, NULL, LOG_PRI, &logHandle);
10461053
if (mlogEnd >= RAM_LOG_LEN) ramLogClear(); // init
1047-
LOG_INF("Setup RAM based log, size %u, starting from %u\n\n", RAM_LOG_LEN, mlogEnd);
1048-
LOG_INF("=============== %s %s ===============", APP_NAME, APP_VER);
1054+
logPrint("\n\n=============== %s %s ===============\n", APP_NAME, APP_VER);
1055+
LOG_INF("Setup RAM based log, size %u, starting from %u", RAM_LOG_LEN, mlogEnd);
10491056
initBrownout();
10501057
prepInternalTemp();
10511058
boardInfo();
@@ -1261,7 +1268,7 @@ static void printGpioInfo() {
12611268
}
12621269

12631270

1264-
/****************** send device to sleep (light or deep) & watchdog ******************/
1271+
/****************** send device to sleep (light or deep), watchdog, panics ******************/
12651272

12661273
#include <esp_wifi.h>
12671274
#include <driver/gpio.h>
@@ -1281,6 +1288,32 @@ static esp_sleep_wakeup_cause_t printWakeupReason() {
12811288
return wakeup_reason;
12821289
}
12831290

1291+
void appPanicHandler(arduino_panic_info_t *info, void *arg) {
1292+
// store crash backtrace and delay reboot to avoid thrashing
1293+
// https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-misc.c
1294+
strncpy(btReason, info->reason, sizeof(btReason) - 1);
1295+
btCore = info->core;
1296+
btLen = info->backtrace_len;
1297+
for (int i = 0; i < info->backtrace_len; i++) backtrace[i] = info->backtrace[i];
1298+
haveTrace = MAGIC_NUM; // flag that backtrace available
1299+
esp_rom_delay_us(PANIC_DELAY * 1000 * 1000);
1300+
}
1301+
1302+
static void showBacktrace() {
1303+
// display backtrace following a panic
1304+
if (haveTrace == MAGIC_NUM) {
1305+
haveTrace = 0;
1306+
char bt[220];
1307+
sprintf(bt, "%s on core %d", btReason, btCore);
1308+
LOG_WRN("%s", bt);
1309+
bt[0] = 0;
1310+
for (int i = 0; i < btLen; i++) {
1311+
snprintf(bt + strlen(bt), sizeof(bt) - strlen(bt) - 11, "0x%08x ", (unsigned int)backtrace[i]); // 11 is size of new trace hex
1312+
}
1313+
LOG_WRN("Paste backtrace below into Arduino Exception Decoder:\n");
1314+
logPrint("Backtrace: %s\n\n", bt);
1315+
}
1316+
}
12841317

12851318
static esp_reset_reason_t printResetReason() {
12861319
esp_reset_reason_t bootReason = esp_reset_reason();
@@ -1303,6 +1336,7 @@ static esp_reset_reason_t printResetReason() {
13031336
case ESP_RST_SDIO: LOG_INF("Reset over SDIO"); break;
13041337
default: LOG_WRN("Unhandled reset reason"); break;
13051338
}
1339+
showBacktrace();
13061340
return bootReason;
13071341
}
13081342

webServer.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ int refreshVal = 5000; // msecs
1414

1515
static httpd_handle_t httpServer = NULL; // web server port
1616
static int fdWs = -1; // websocket sockfd
17+
static httpd_handle_t sseSocketHD; // SSE support
18+
static int sseSocketFD;
1719
bool useHttps = false;
1820
bool useSecure = false;
1921
bool heartBeatDone = false;
@@ -37,6 +39,7 @@ esp_err_t sendChunks(File df, httpd_req_t *req, bool endChunking) {
3739
if (res != ESP_OK) {
3840
snprintf(startupFailure, SF_LEN, "Failed to send to browser: %s, err %s", inFileName, espErrMsg(res));
3941
LOG_WRN("%s", startupFailure);
42+
checkMemory();
4043
OTAprereq(); // free up memory
4144
}
4245
return res;
@@ -110,7 +113,7 @@ static esp_err_t indexHandler(httpd_req_t* req) {
110113
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
111114
// first check if a startup failure needs to be reported
112115
if (strlen(startupFailure)) {
113-
httpd_resp_set_type(req, "text/html");
116+
httpd_resp_set_type(req, "text/html");
114117
httpd_resp_sendstr_chunk(req, failPageS_html);
115118
httpd_resp_sendstr_chunk(req, startupFailure);
116119
httpd_resp_sendstr_chunk(req, failPageE_html);
@@ -257,6 +260,28 @@ bool parseJson(int rxSize) {
257260
return retAction;
258261
}
259262

263+
static esp_err_t sseHandler(httpd_req_t *req) {
264+
// enable Server Sent Events
265+
const char* sseHeader = "HTTP/1.1 200 OK\r\n"
266+
"Cache-Control: no-store\r\n"
267+
"Connection: keep-alive\r\n"
268+
"Content-Type: text/event-stream\r\n\r\n";
269+
sseSocketHD = req->handle;
270+
sseSocketFD = httpd_req_to_sockfd(req);
271+
httpd_socket_send(sseSocketHD, sseSocketFD, sseHeader, strlen(sseHeader), 0);
272+
sendSSE("event: open\ndata: opened" SSESEP);
273+
return ESP_OK;
274+
}
275+
276+
void sendSSE(const char* statusData) {
277+
// send statusData to browser
278+
if (sseSocketFD > 0) {
279+
int res = httpd_socket_send(sseSocketHD, sseSocketFD, statusData, strlen(statusData), 0);
280+
if (res == HTTPD_SOCK_ERR_TIMEOUT) LOG_WRN("Timeout/interrupted while using socket");
281+
if (res == HTTPD_SOCK_ERR_FAIL) LOG_WRN("Unrecoverable error while using socket");
282+
} else LOG_WRN("SSE not initiated");
283+
}
284+
260285
static esp_err_t updateHandler(httpd_req_t *req) {
261286
// bulk update of config, extract key pairs from received json string
262287
size_t rxSize = min(req->content_len, (size_t)JSON_BUFF_LEN);
@@ -546,6 +571,7 @@ void startWebServer() {
546571
httpd_uri_t statusUri = {.uri = "/status", .method = HTTP_GET, .handler = statusHandler, .user_ctx = NULL};
547572
httpd_uri_t uploadUri = {.uri = "/upload", .method = HTTP_POST, .handler = uploadHandler, .user_ctx = NULL};
548573
httpd_uri_t wifiUri = {.uri = "/wifi", .method = HTTP_GET, .handler = setupHandler, .user_ctx = NULL};
574+
httpd_uri_t sseUri = {.uri = "/sse", .method = HTTP_GET, .handler = sseHandler, .user_ctx = NULL};
549575
httpd_uri_t wsUri = {.uri = "/ws", .method = HTTP_GET, .handler = wsHandler, .user_ctx = NULL, .is_websocket = true};
550576
httpd_uri_t sustainUri = {.uri = "/sustain", .method = HTTP_GET, .handler = appSpecificSustainHandler, .user_ctx = NULL};
551577
httpd_uri_t checkUri = {.uri = "/sustain", .method = HTTP_HEAD, .handler = appSpecificSustainHandler, .user_ctx = NULL};
@@ -557,6 +583,7 @@ void startWebServer() {
557583
httpd_register_uri_handler(httpServer, &updateUri);
558584
httpd_register_uri_handler(httpServer, &statusUri);
559585
httpd_register_uri_handler(httpServer, &uploadUri);
586+
httpd_register_uri_handler(httpServer, &sseUri);
560587
httpd_register_uri_handler(httpServer, &wifiUri);
561588
httpd_register_uri_handler(httpServer, &wsUri);
562589
httpd_register_uri_handler(httpServer, &sustainUri);

0 commit comments

Comments
 (0)