Add ESP171 which save camera frame to SD

This commit is contained in:
Luc 2022-06-27 17:46:27 +08:00
parent fa20ebcec7
commit ab9f3c1236
8 changed files with 211 additions and 30 deletions

View File

@ -82,7 +82,10 @@ The json format is {
* Get/Set Camera command value / list all values in JSON/plain * Get/Set Camera command value / list all values in JSON/plain
label can be: light/framesize/quality/contrast/brightness/saturation/gainceiling/colorbar/awb/agc/aec/hmirror/vflip/awb_gain/agc_gain/aec_value/aec2/cw/bpc/wpc/raw_gma/lenc/special_effect/wb_mode/ae_level label can be: light/framesize/quality/contrast/brightness/saturation/gainceiling/colorbar/awb/agc/aec/hmirror/vflip/awb_gain/agc_gain/aec_value/aec2/cw/bpc/wpc/raw_gma/lenc/special_effect/wb_mode/ae_level
[ESP170]<plain><label=value> json=<no> pwd=<admin password> [ESP170]<label=value> json=<no> pwd=<admin password>
* Save frame to target path and filename (default target = today date, default name=timestamp.jpg)
[ESP171] <path=target path> <filename=target filename>
* Get/Set Ftp state which can be ON, OFF, CLOSE * Get/Set Ftp state which can be ON, OFF, CLOSE
[ESP180]<state> json=<no> pwd=<admin password> [ESP180]<state> json=<no> pwd=<admin password>

View File

@ -492,11 +492,16 @@ bool Commands::execute_internal_command (int cmd, const char* cmd_params, level_
#endif //WS_DATA_FEATURE #endif //WS_DATA_FEATURE
#ifdef CAMERA_DEVICE #ifdef CAMERA_DEVICE
//Get/Set Camera command value / list all values in JSON/plain //Get/Set Camera command value / list all values in JSON/plain
//[ESP170]label=<value>pwd=<admin password> //[ESP170]label=<value> pwd=<admin/user password>
//label can be: light/framesize/quality/contrast/brightness/saturation/gainceiling/colorbar/awb/agc/aec/hmirror/vflip/awb_gain/agc_gain/aec_value/aec2/cw/bpc/wpc/raw_gma/lenc/special_effect/wb_mode/ae_level //label can be: light/framesize/quality/contrast/brightness/saturation/gainceiling/colorbar/awb/agc/aec/hmirror/vflip/awb_gain/agc_gain/aec_value/aec2/cw/bpc/wpc/raw_gma/lenc/special_effect/wb_mode/ae_level
case 170: case 170:
response = ESP170(cmd_params, auth_type, output); response = ESP170(cmd_params, auth_type, output);
break; break;
//Save frame to target path and filename (default target = today date, default name=timestamp.jpg)
//[ESP171]path=<target path> filename=<target filename> pwd=<admin/user password>
case 171:
response = ESP171(cmd_params, auth_type, output);
break;
#endif //CAMERA_DEVICE #endif //CAMERA_DEVICE
#ifdef FTP_FEATURE #ifdef FTP_FEATURE
//Set Ftp state which can be ON, OFF //Set Ftp state which can be ON, OFF

View File

@ -85,6 +85,7 @@ public:
#endif //WS_DATA_FEATURE #endif //WS_DATA_FEATURE
#if defined(CAMERA_DEVICE) #if defined(CAMERA_DEVICE)
bool ESP170(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); bool ESP170(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output);
bool ESP171(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output);
#endif //CAMERA_DEVICE #endif //CAMERA_DEVICE
#if defined(FTP_FEATURE) #if defined(FTP_FEATURE)
bool ESP180(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output); bool ESP180(const char* cmd_params, level_authenticate_type auth_level, ESP3DOutput * output);

View File

@ -67,7 +67,8 @@ const char * help[]= {"[ESP] (id) - display this help",
"[ESP161](Port) - display/set WebSocket port", "[ESP161](Port) - display/set WebSocket port",
#endif //WS_DATA_FEATURE #endif //WS_DATA_FEATURE
#if defined(CAMERA_DEVICE) #if defined(CAMERA_DEVICE)
"[ESP170](plain) (label=value) - display(JSON/plain)/set Camera commands", "[ESP170](json) (label=value) - display/set Camera commands",
"[ESP171] (path=<target path>) (filename=<target filename>) Save frame to target path and filename",
#endif //CAMERA_DEVICE #endif //CAMERA_DEVICE
#if defined(FTP_FEATURE) #if defined(FTP_FEATURE)
"[ESP180](State) - display/set FTP state which can be ON, OFF", "[ESP180](State) - display/set FTP state which can be ON, OFF",
@ -203,6 +204,7 @@ const uint cmdlist[]= {0,
#endif //WS_DATA_FEATURE #endif //WS_DATA_FEATURE
#if defined(CAMERA_DEVICE) #if defined(CAMERA_DEVICE)
170, 170,
171,
#endif //CAMERA_DEVICE #endif //CAMERA_DEVICE
#if defined(FTP_FEATURE) #if defined(FTP_FEATURE)
180, 180,

View File

@ -0,0 +1,114 @@
/*
ESP122.cpp - ESP3D command class
Copyright (c) 2014 Luc Lebosse. All rights reserved.
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "../../include/esp3d_config.h"
#if defined (CAMERA_DEVICE)
#include "../commands.h"
#include "../esp3doutput.h"
#include "esp_camera.h"
#include "../settings_esp3d.h"
#include "../../modules/authentication/authentication_service.h"
#include "../../modules/camera/camera.h"
#include <time.h>
#define COMMANDID 171
//Save frame to target path and filename (default target = today date, default name=timestamp.jpg)
//[ESP171]path=<target path> filename=<target filename> pwd=<admin/user password>
bool Commands::ESP171(const char* cmd_params, level_authenticate_type auth_type, ESP3DOutput * output)
{
bool noError = true;
bool json = has_tag (cmd_params, "json");
String response;
String parameter;
int errorCode = 200; //unless it is a server error use 200 as default and set error in json instead
String path;
String filename;
#ifdef AUTHENTICATION_FEATURE
if (auth_type == LEVEL_GUEST) {
response = format_response(COMMANDID, json, false, "Guest user can't use this command");
noError = false;
errorCode = 401;
}
#else
(void)auth_type;
#endif //AUTHENTICATION_FEATURE
if(noError) {
if (!esp3d_camera.started()) {
response = format_response(COMMANDID, json, false, "No camera initialized");
noError = false;
} else {
parameter = clean_param(get_param (cmd_params, "path="));
//get path
if (parameter.length() != 0) {
path = parameter;
}
parameter = clean_param(get_param (cmd_params, "filename="));
//get filename
if (parameter.length() != 0) {
filename = parameter;
}
//if nothing provided, use default filename / path
if (path.length()==0) {
struct tm tmstruct;
time_t now;
path = "";
time(&now);
localtime_r(&now, &tmstruct);
path = String((tmstruct.tm_year)+1900) + "-";
if (((tmstruct.tm_mon)+1) < 10) {
path +="0";
}
path += String(( tmstruct.tm_mon)+1) + "-";
if (tmstruct.tm_mday < 10) {
path +="0";
}
path += String(tmstruct.tm_mday);
}
if(filename.length()==0) {
struct tm tmstruct;
time_t now;
time(&now);
localtime_r(&now, &tmstruct);
filename = String(now) + ".jpg";
}
//now send command
if(noError) {
noError = esp3d_camera.handle_snap(nullptr,path.c_str(), filename.c_str());
if(noError) {
response = format_response(COMMANDID, json, true, "Snapshot taken");
} else {
response = format_response(COMMANDID, json, false, "Error taking snapshot");
}
}
}
}
if (noError) {
if (json) {
output->printLN (response.c_str() );
} else {
output->printMSG (response.c_str() );
}
} else {
output->printERROR(response.c_str(), errorCode);
}
return noError;
}
#endif //CAMERA_DEVICE

View File

@ -22,7 +22,7 @@
#define _VERSION_ESP3D_H #define _VERSION_ESP3D_H
//version and sources location //version and sources location
#define FW_VERSION "3.0.0.a200" #define FW_VERSION "3.0.0.a201"
#define REPOSITORY "https://github.com/luc-github/ESP3D/tree/3.0" #define REPOSITORY "https://github.com/luc-github/ESP3D/tree/3.0"
#endif //_VERSION_ESP3D_H #endif //_VERSION_ESP3D_H

View File

@ -26,8 +26,10 @@
#include <esp_camera.h> #include <esp_camera.h>
#include <soc/soc.h> //not sure this one is needed #include <soc/soc.h> //not sure this one is needed
#include <soc/rtc_cntl_reg.h> #include <soc/rtc_cntl_reg.h>
#include <WebServer.h> #include <WebServer.h>
#if defined (SD_DEVICE)
#include "../filesystem/esp_sd.h"
#endif //SD_DEVICE
#define DEFAULT_FRAME_SIZE FRAMESIZE_SVGA #define DEFAULT_FRAME_SIZE FRAMESIZE_SVGA
@ -35,15 +37,18 @@
Camera esp3d_camera; Camera esp3d_camera;
void Camera::handle_snap(WebServer * webserver) bool Camera::handle_snap(WebServer * webserver, const char *path, const char* filename)
{ {
log_esp3d("Camera stream reached"); log_esp3d("Camera stream reached");
if (!_initialised) { if (!_initialised) {
log_esp3d("Camera not started"); log_esp3d("Camera not started");
if (webserver) {
webserver->send (500, "text/plain", "Camera not started"); webserver->send (500, "text/plain", "Camera not started");
return; }
return false;
} }
sensor_t * s = esp_camera_sensor_get(); sensor_t * s = esp_camera_sensor_get();
if (webserver) {
if (webserver->hasArg ("framesize") ) { if (webserver->hasArg ("framesize") ) {
if(s->status.framesize != webserver->arg ("framesize").toInt()) { if(s->status.framesize != webserver->arg ("framesize").toInt()) {
command("framesize", webserver->arg ("framesize").c_str()); command("framesize", webserver->arg ("framesize").c_str());
@ -61,19 +66,25 @@ void Camera::handle_snap(WebServer * webserver)
#ifdef ESP_ACCESS_CONTROL_ALLOW_ORIGIN #ifdef ESP_ACCESS_CONTROL_ALLOW_ORIGIN
webserver->enableCrossOrigin(true); webserver->enableCrossOrigin(true);
#endif //ESP_ACCESS_CONTROL_ALLOw_ORIGIN #endif //ESP_ACCESS_CONTROL_ALLOw_ORIGIN
}
camera_fb_t * fb = NULL; camera_fb_t * fb = NULL;
bool res_error = false; bool res_error = false;
size_t _jpg_buf_len = 0; size_t _jpg_buf_len = 0;
uint8_t * _jpg_buf = NULL; uint8_t * _jpg_buf = NULL;
if (webserver) {
webserver->sendHeader(String(F("Content-Type")), String(F("image/jpeg")),true); webserver->sendHeader(String(F("Content-Type")), String(F("image/jpeg")),true);
webserver->sendHeader(String(F("Content-Disposition")), String(F("inline; filename=capture.jpg")),true); webserver->sendHeader(String(F("Content-Disposition")), String(F("inline; filename=capture.jpg")),true);
webserver->setContentLength(CONTENT_LENGTH_UNKNOWN); webserver->setContentLength(CONTENT_LENGTH_UNKNOWN);
webserver->send(200); webserver->send(200);
}
log_esp3d("Camera capture ongoing"); log_esp3d("Camera capture ongoing");
fb = esp_camera_fb_get(); fb = esp_camera_fb_get();
if (!fb) { if (!fb) {
log_esp3d("Camera capture failed"); log_esp3d("Camera capture failed");
if (webserver) {
webserver->send (500, "text/plain", "Capture failed"); webserver->send (500, "text/plain", "Capture failed");
}
res_error=true;
} else { } else {
if(fb->format != PIXFORMAT_JPEG) { if(fb->format != PIXFORMAT_JPEG) {
bool jpeg_converted = frame2jpg(fb, JPEG_COMPRESSION, &_jpg_buf, &_jpg_buf_len); bool jpeg_converted = frame2jpg(fb, JPEG_COMPRESSION, &_jpg_buf, &_jpg_buf_len);
@ -89,8 +100,50 @@ void Camera::handle_snap(WebServer * webserver)
} }
} }
if (!res_error) { if (!res_error) {
if(webserver) {
webserver->sendContent_P ((const char *)_jpg_buf, _jpg_buf_len); webserver->sendContent_P ((const char *)_jpg_buf, _jpg_buf_len);
} }
#if defined (SD_DEVICE)
if (filename!=nullptr && path!=nullptr) {
if (!ESP_SD::accessFS()) {
res_error = true;
log_esp3d("SD not available");
} else {
if (ESP_SD::getState(true) == ESP_SDCARD_NOT_PRESENT) {
res_error = true;
log_esp3d("No SD");
} else {
ESP_SD::setState(ESP_SDCARD_BUSY );
String wpath = path[0]=='/' ? path : String("/")+path;
if (!ESP_SD::exists(wpath.c_str())) {
res_error = !ESP_SD::mkdir(wpath.c_str());
}
if (!res_error) {
if (wpath[wpath.length()-1]!='/') {
wpath += "/";
}
wpath +=filename ;
ESP_SDFile f = ESP_SD::open(wpath.c_str(), ESP_FILE_WRITE);
if (f) {
f.write((const uint8_t *)_jpg_buf, _jpg_buf_len);
f.close();
log_esp3d("Camera capture done");
} else {
res_error = true;
log_esp3d("Failed to open file for writing");
}
}
}
ESP_SD::releaseFS();
}
}
#endif //SD_DEVICE
if (!webserver && filename==nullptr && path==nullptr) {
log_esp3d("No output defined");
res_error = true;
}
}
if(fb) { if(fb) {
esp_camera_fb_return(fb); esp_camera_fb_return(fb);
@ -100,7 +153,10 @@ void Camera::handle_snap(WebServer * webserver)
free(_jpg_buf); free(_jpg_buf);
_jpg_buf = NULL; _jpg_buf = NULL;
} }
if(webserver) {
webserver->sendContent(""); webserver->sendContent("");
}
return !res_error;
} }
Camera::Camera() Camera::Camera()

View File

@ -33,7 +33,7 @@ public:
void end(); void end();
bool initHardware(); bool initHardware();
bool stopHardware(); bool stopHardware();
void handle_snap(WebServer * webserver); bool handle_snap(WebServer * webserver, const char *path=NULL, const char* filename=NULL);
void handle(); void handle();
int command(const char * param, const char * value); int command(const char * param, const char * value);
uint8_t GetModel(); uint8_t GetModel();