Add demo mode (#1720)

* move main part to cam file

* added demo mode

* .

* add a define to configure the logfile handling (#1709)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Move Logfile Switch to define.h

* Update Reboot Algo

* Update server_ota.cpp

* Avoid loading of status infos twice (#1711)

* Force a reboot even reboot task cannot be created due to lack of heap (#1713)

* Deinit all components before reboot

* Update

* Update

* Force reboot when reboot task cannot be created

* Improve log message when web UI is incomplete (#1716)

* improve warning if version.txt is missing

* typo

* show round duration in log

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* .

* .

* .

* creade demo dir

* fix static IP in UP, improve explanation for HA (#1719)

* fix static IP in UP, improve explanation for HA

* Update edit_config_param.html

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Create demo folder at startup (if not present)

* move demo files

* Update defines.h (#1726)

* updated description

* moved to expert section

* fixed broken enabled state

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: Slider0007 <115730895+Slider0007@users.noreply.github.com>
This commit is contained in:
CaCO3
2022-12-30 21:57:56 +01:00
committed by GitHub
parent 4121416743
commit 58cbd680e8
26 changed files with 178 additions and 15 deletions

View File

@@ -27,6 +27,7 @@
#include "esp_camera.h" #include "esp_camera.h"
#include "driver/ledc.h" #include "driver/ledc.h"
#include "server_tflite.h"
static const char *TAG = "CAM"; static const char *TAG = "CAM";
@@ -66,16 +67,33 @@ static camera_config_t camera_config = {
}; };
CCamera Camera; CCamera Camera;
uint8_t *demoImage = NULL; // Buffer holding the demo image in bytes
#define DEMO_IMAGE_SIZE 30000 // Max size of demo image in bytes
typedef struct { typedef struct {
httpd_req_t *req; httpd_req_t *req;
size_t len; size_t len;
} jpg_chunking_t; } jpg_chunking_t;
bool CCamera::testCamera(void) {
bool success;
camera_fb_t *fb = esp_camera_fb_get();
if (fb) {
success = true;
}
else {
success = false;
}
esp_camera_fb_return(fb);
return success;
}
void CCamera::ledc_init(void) void CCamera::ledc_init(void)
{ {
#ifdef USE_PWM_LEDFLASH #ifdef USE_PWM_LEDFLASH
@@ -219,6 +237,7 @@ void CCamera::EnableAutoExposure(int flash_duration)
esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay) esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay)
{ {
string ftype; string ftype;
int _size;
uint8_t *zwischenspeicher = NULL; uint8_t *zwischenspeicher = NULL;
@@ -255,7 +274,12 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay)
return ESP_FAIL; return ESP_FAIL;
} }
int _size = fb->len; if (demoMode) { // Use images stored on SD-Card instead of camera image
/* Replace Framebuffer with image from SD-Card */
loadNextDemoImage(fb);
}
_size = fb->len;
zwischenspeicher = (uint8_t*) malloc(_size); zwischenspeicher = (uint8_t*) malloc(_size);
if (!zwischenspeicher) if (!zwischenspeicher)
{ {
@@ -454,14 +478,23 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay)
} }
if(res == ESP_OK){ if(res == ESP_OK){
if(fb->format == PIXFORMAT_JPEG){ if (demoMode) { // Use images stored on SD-Card instead of camera image
fb_len = fb->len; LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Using Demo image!");
/* Replace Framebuffer with image from SD-Card */
loadNextDemoImage(fb);
res = httpd_resp_send(req, (const char *)fb->buf, fb->len); res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
} else { }
jpg_chunking_t jchunk = {req, 0}; else {
res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL; if(fb->format == PIXFORMAT_JPEG){
httpd_resp_send_chunk(req, NULL, 0); fb_len = fb->len;
fb_len = jchunk.len; res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
} else {
jpg_chunking_t jchunk = {req, 0};
res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL;
httpd_resp_send_chunk(req, NULL, 0);
fb_len = jchunk.len;
}
} }
} }
esp_camera_fb_return(fb); esp_camera_fb_return(fb);
@@ -640,3 +673,84 @@ bool CCamera::getCameraInitSuccessful()
{ {
return CameraInitSuccessful; return CameraInitSuccessful;
} }
std::vector<std::string> demoFiles;
void CCamera::useDemoMode()
{
char line[50];
FILE *fd = fopen("/sdcard/demo/files.txt", "r");
if (!fd) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Please provide the demo files first!");
return;
}
demoImage = (uint8_t*)malloc(DEMO_IMAGE_SIZE);
if (demoImage == NULL) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Unable to acquire required memory for demo image!");
return;
}
while (fgets(line, sizeof(line), fd) != NULL) {
line[strlen(line) - 1] = '\0';
demoFiles.push_back(line);
}
fclose(fd);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Using Demo mode (" + std::to_string(demoFiles.size()) +
" files) instead of real camera image!");
for (auto file : demoFiles) {
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, file);
}
demoMode = true;
}
bool CCamera::loadNextDemoImage(camera_fb_t *fb) {
char filename[50];
int readBytes;
long fileSize;
snprintf(filename, sizeof(filename), "/sdcard/demo/%s", demoFiles[getCountFlowRounds() % demoFiles.size()].c_str());
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Using " + std::string(filename) + " as demo image");
/* Inject saved image */
FILE * fp = fopen(filename, "rb");
if (!fp) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to read file: " + std::string(filename) +"!");
return false;
}
fileSize = GetFileSize(filename);
if (fileSize > DEMO_IMAGE_SIZE) {
char buf[100];
snprintf(buf, sizeof(buf), "Demo Image (%d bytes) is larger than provided buffer (%d bytes)!",
(int)fileSize, DEMO_IMAGE_SIZE);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, std::string(buf));
return false;
}
readBytes = fread(demoImage, 1, DEMO_IMAGE_SIZE, fp);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "read " + std::to_string(readBytes) + " bytes");
fclose(fp);
fb->buf = demoImage; // Update pointer
fb->len = readBytes;
// ToDo do we also need to set height, width, format and timestamp?
return true;
}
long CCamera::GetFileSize(std::string filename)
{
struct stat stat_buf;
long rc = stat(filename.c_str(), &stat_buf);
return rc == 0 ? stat_buf.st_size : -1;
}

View File

@@ -26,6 +26,10 @@ class CCamera {
void ledc_init(void); void ledc_init(void);
bool CameraInitSuccessful = false; bool CameraInitSuccessful = false;
bool demoMode = false;
bool loadNextDemoImage(camera_fb_t *fb);
long GetFileSize(std::string filename);
public: public:
int image_height, image_width; int image_height, image_width;
@@ -40,8 +44,10 @@ class CCamera {
bool SetBrightnessContrastSaturation(int _brightness, int _contrast, int _saturation); bool SetBrightnessContrastSaturation(int _brightness, int _contrast, int _saturation);
void GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol); void GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol);
void SetLEDIntensity(float _intrel); void SetLEDIntensity(float _intrel);
bool testCamera(void);
void EnableAutoExposure(int flash_duration); void EnableAutoExposure(int flash_duration);
bool getCameraInitSuccessful(); bool getCameraInitSuccessful();
void useDemoMode(void);
framesize_t TextToFramesize(const char * text); framesize_t TextToFramesize(const char * text);

View File

@@ -140,6 +140,12 @@ bool ClassFlowMakeImage::ReadParameter(FILE* pfile, string& aktparamgraph)
ledintensity = max((float) 0, ledintensity); ledintensity = max((float) 0, ledintensity);
Camera.SetLEDIntensity(ledintensity); Camera.SetLEDIntensity(ledintensity);
} }
if ((toUpper(splitted[0]) == "DEMO") && (splitted.size() > 1))
{
if (toUpper(splitted[1]) == "TRUE")
Camera.useDemoMode();
}
} }
Camera.SetBrightnessContrastSaturation(_brightness, _contrast, _saturation); Camera.SetBrightnessContrastSaturation(_brightness, _contrast, _saturation);

View File

@@ -272,9 +272,8 @@ extern "C" void app_main(void)
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Check that your camera module is working and connected properly!"); LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Check that your camera module is working and connected properly!");
setSystemStatusFlag(SYSTEM_STATUS_CAM_BAD); setSystemStatusFlag(SYSTEM_STATUS_CAM_BAD);
} }
} else { // Test Camera } else { // Test Camera
camera_fb_t * fb = esp_camera_fb_get(); if (!Camera.testCamera()) {
if (!fb) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera Framebuffer cannot be initialized!"); LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera Framebuffer cannot be initialized!");
/* Easiest would be to simply restart here and try again, /* Easiest would be to simply restart here and try again,
how ever there seem to be systems where it fails at startup but still work corectly later. how ever there seem to be systems where it fails at startup but still work corectly later.
@@ -282,7 +281,6 @@ extern "C" void app_main(void)
setSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD); setSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD);
} }
else { else {
esp_camera_fb_return(fb);
Camera.LightOnOff(false); Camera.LightOnOff(false);
} }
} }

View File

@@ -339,6 +339,7 @@ esp_err_t upload_post_handlerAP(httpd_req_t *req)
MakeDir("/sdcard/html"); MakeDir("/sdcard/html");
MakeDir("/sdcard/img_tmp"); MakeDir("/sdcard/img_tmp");
MakeDir("/sdcard/log"); MakeDir("/sdcard/log");
MakeDir("/sdcard/demo");
printf("Nach Start des Post Handlers\n"); printf("Nach Start des Post Handlers\n");
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "upload_post_handlerAP"); LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "upload_post_handlerAP");

2
demo-images/readme.md Normal file
View File

@@ -0,0 +1,2 @@
# Images for Demo Mode
See https://github.com/jomjol/AI-on-the-edge-device/wiki/Demo-Mode for details

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -0,0 +1,15 @@
520.8983.jpg
520.9086.jpg
520.9351.jpg
520.9787.jpg
521.0213.jpg
521.0465.jpg
521.0929.jpg
521.1232.jpg
521.1708.jpg
521.2043.jpg
521.2170.jpg
521.2413.jpg
521.2575.jpg
521.2853.jpg
521.3027.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -9,6 +9,7 @@ LEDIntensity = 50
ImageQuality = 12 ImageQuality = 12
ImageSize = VGA ImageSize = VGA
FixedExposure = false FixedExposure = false
;Demo = false
[Alignment] [Alignment]
InitialRotate = 179 InitialRotate = 179

View File

@@ -121,6 +121,23 @@ textarea {
<td class="description"> <td class="description">
Time to keep the raw image (in days, resp. "0" = forever) Time to keep the raw image (in days, resp. "0" = forever)
</td> </td>
</tr>
<tr class="expert" id="ex1">
<td class="indent1">
<input type="checkbox" id="MakeImage_Demo_enabled" value="1" onclick = 'InvertEnableItem("MakeImage", "Demo")' unchecked >
<label for=MakeImage_Demo_enabled><class id="MakeImage_Demo_text" style="color:black;">Demo Mode</class></label>
</td>
<td>
<select id="MakeImage_Demo_value1">
<option value="true">true</option>
<option value="false" selected>false</option>
</select>
</td>
<td style="font-size: 80%;">
Enable to use demo images instead of the real camera images.<br>
Make sore to have a demo folder on your SD-Card!
See Details on <a href="https://github.com/jomjol/AI-on-the-edge-device/wiki/Demo-Mode" target="_blank">Demo Mode</a>.
</td>
</tr> </tr>
<tr class="expert" id="ex1"> <tr class="expert" id="ex1">
@@ -1778,6 +1795,7 @@ function UpdateInput() {
WriteParameter(param, category, "MakeImage", "LogImageLocation", true); WriteParameter(param, category, "MakeImage", "LogImageLocation", true);
WriteParameter(param, category, "MakeImage", "LogfileRetentionInDays", true); WriteParameter(param, category, "MakeImage", "LogfileRetentionInDays", true);
WriteParameter(param, category, "MakeImage", "Demo", true);
WriteParameter(param, category, "MakeImage", "WaitBeforeTakingPicture", false); WriteParameter(param, category, "MakeImage", "WaitBeforeTakingPicture", false);
WriteParameter(param, category, "MakeImage", "ImageQuality", false); WriteParameter(param, category, "MakeImage", "ImageQuality", false);
WriteParameter(param, category, "MakeImage", "Brightness", false); WriteParameter(param, category, "MakeImage", "Brightness", false);
@@ -1897,7 +1915,8 @@ function ReadParameterAll()
category["GPIO"]["enabled"] = document.getElementById("Category_GPIO_enabled").checked; category["GPIO"]["enabled"] = document.getElementById("Category_GPIO_enabled").checked;
ReadParameter(param, "MakeImage", "LogImageLocation", true); ReadParameter(param, "MakeImage", "LogImageLocation", true);
ReadParameter(param, "MakeImage", "LogfileRetentionInDays", true); ReadParameter(param, "MakeImage", "LogfileRetentionInDays", true);
ReadParameter(param, "MakeImage", "Demo", true);
ReadParameter(param, "MakeImage", "WaitBeforeTakingPicture", false); ReadParameter(param, "MakeImage", "WaitBeforeTakingPicture", false);
ReadParameter(param, "MakeImage", "ImageQuality", false); ReadParameter(param, "MakeImage", "ImageQuality", false);
ReadParameter(param, "MakeImage", "Brightness", false); ReadParameter(param, "MakeImage", "Brightness", false);

View File

@@ -119,6 +119,7 @@ function ParseConfig() {
ParamAddValue(param, catname, "LogImageLocation"); ParamAddValue(param, catname, "LogImageLocation");
ParamAddValue(param, catname, "WaitBeforeTakingPicture"); ParamAddValue(param, catname, "WaitBeforeTakingPicture");
ParamAddValue(param, catname, "LogfileRetentionInDays"); ParamAddValue(param, catname, "LogfileRetentionInDays");
ParamAddValue(param, catname, "Demo");
ParamAddValue(param, catname, "Brightness"); ParamAddValue(param, catname, "Brightness");
ParamAddValue(param, catname, "Contrast"); ParamAddValue(param, catname, "Contrast");
ParamAddValue(param, catname, "Saturation"); ParamAddValue(param, catname, "Saturation");