2020-11-21 00:05:00 +08:00
// Original Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2019-11-15 00:01:37 +08:00
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2020-11-21 00:05:00 +08:00
# include <esp_http_server.h>
# include <esp_timer.h>
# include <esp_camera.h>
# include <esp_int_wdt.h>
# include <esp_task_wdt.h>
# include <Arduino.h>
2020-10-04 01:49:08 +08:00
# include <WiFi.h>
2019-11-15 00:01:37 +08:00
2020-09-13 21:28:38 +08:00
# include "index_ov2640.h"
# include "index_ov3660.h"
2020-10-07 08:08:18 +08:00
# include "index_other.h"
2020-09-13 21:28:38 +08:00
# include "css.h"
2020-09-30 21:41:42 +08:00
# include "src/favicons.h"
2020-10-07 08:08:18 +08:00
# include "src/logo.h"
2020-09-27 21:21:44 +08:00
# include "storage.h"
2019-11-15 00:01:37 +08:00
2020-09-09 08:57:37 +08:00
// Functions from the main .ino
2020-09-22 18:03:18 +08:00
extern void flashLED ( int flashtime ) ;
extern void setLamp ( int newVal ) ;
2021-06-09 02:42:14 +08:00
extern void printLocalTime ( bool extraData ) ;
2020-09-09 08:57:37 +08:00
2020-10-12 00:19:22 +08:00
// External variables declared in the main .ino
2020-10-04 01:49:08 +08:00
extern char myName [ ] ;
extern char myVer [ ] ;
2020-10-12 19:17:21 +08:00
extern char baseVersion [ ] ;
2020-10-07 18:19:19 +08:00
extern IPAddress ip ;
extern IPAddress net ;
extern IPAddress gw ;
extern bool accesspoint ;
extern char apName [ ] ;
extern bool captivePortal ;
extern int httpPort ;
extern int streamPort ;
extern char httpURL [ ] ;
extern char streamURL [ ] ;
2020-10-07 21:43:28 +08:00
extern char default_index [ ] ;
2020-10-26 07:04:21 +08:00
extern int8_t streamCount ;
2021-05-09 18:45:10 +08:00
extern unsigned long streamsServed ;
extern unsigned long imagesServed ;
2020-10-04 01:49:08 +08:00
extern int myRotation ;
2021-12-18 19:29:43 +08:00
extern int minFrameTime ;
2020-10-04 01:49:08 +08:00
extern int lampVal ;
2020-10-26 07:04:21 +08:00
extern bool autoLamp ;
2020-10-04 01:49:08 +08:00
extern bool filesystem ;
2020-11-21 00:05:00 +08:00
extern String critERR ;
2020-10-12 00:19:22 +08:00
extern bool debugData ;
2021-06-09 02:42:14 +08:00
extern bool haveTime ;
2020-10-04 01:49:08 +08:00
extern int sketchSize ;
extern int sketchSpace ;
extern String sketchMD5 ;
2021-09-03 20:13:40 +08:00
extern bool otaEnabled ;
extern char otaPassword [ ] ;
2022-03-08 18:34:45 +08:00
extern unsigned long xclk ;
2019-11-15 00:01:37 +08:00
typedef struct {
httpd_req_t * req ;
size_t len ;
} jpg_chunking_t ;
# define PART_BOUNDARY "123456789000000000000987654321"
static const char * _STREAM_CONTENT_TYPE = " multipart/x-mixed-replace;boundary= " PART_BOUNDARY ;
static const char * _STREAM_BOUNDARY = " \r \n -- " PART_BOUNDARY " \r \n " ;
static const char * _STREAM_PART = " Content-Type: image/jpeg \r \n Content-Length: %u \r \n \r \n " ;
httpd_handle_t stream_httpd = NULL ;
httpd_handle_t camera_httpd = NULL ;
2022-03-08 18:34:45 +08:00
// Flag that can be set to kill all active streams
bool streamKill ;
2021-09-03 20:13:40 +08:00
# ifdef __cplusplus
extern " C " {
# endif
uint8_t temprature_sens_read ( ) ;
# ifdef __cplusplus
}
# endif
2021-05-09 18:45:10 +08:00
void serialDump ( ) {
2021-06-09 02:42:14 +08:00
Serial . println ( ) ;
2021-05-09 18:45:10 +08:00
// Module
2021-05-12 02:09:17 +08:00
Serial . printf ( " Name: %s \r \n " , myName ) ;
2021-06-09 02:42:14 +08:00
if ( haveTime ) {
Serial . print ( " Time: " ) ;
printLocalTime ( true ) ;
}
2021-05-12 02:09:17 +08:00
Serial . printf ( " Firmware: %s (base: %s) \r \n " , myVer , baseVersion ) ;
2021-05-09 18:45:10 +08:00
float sketchPct = 100 * sketchSize / sketchSpace ;
2021-05-12 02:09:17 +08:00
Serial . printf ( " Sketch Size: %i (total: %i, %.1f%% used) \r \n " , sketchSize , sketchSpace , sketchPct ) ;
Serial . printf ( " MD5: %s \r \n " , sketchMD5 . c_str ( ) ) ;
Serial . printf ( " ESP sdk: %s \r \n " , ESP . getSdkVersion ( ) ) ;
2021-09-03 20:13:40 +08:00
if ( otaEnabled ) {
if ( strlen ( otaPassword ) ! = 0 ) {
Serial . printf ( " OTA: Enabled, Password: %s \n \r " , otaPassword ) ;
} else {
Serial . printf ( " OTA: Enabled, No Password! (insecure) \n \r " ) ;
}
} else {
Serial . printf ( " OTA: Disabled \n \r " ) ;
}
2021-05-09 18:45:10 +08:00
// Network
if ( accesspoint ) {
if ( captivePortal ) {
2021-05-12 02:09:17 +08:00
Serial . printf ( " WiFi Mode: AccessPoint with captive portal \r \n " ) ;
2021-05-09 18:45:10 +08:00
} else {
2021-05-12 02:09:17 +08:00
Serial . printf ( " WiFi Mode: AccessPoint \r \n " ) ;
2021-05-09 18:45:10 +08:00
}
2021-05-12 02:09:17 +08:00
Serial . printf ( " WiFi SSID: %s \r \n " , apName ) ;
2021-05-09 18:45:10 +08:00
} else {
2021-05-12 02:09:17 +08:00
Serial . printf ( " WiFi Mode: Client \r \n " ) ;
2021-05-09 18:45:10 +08:00
String ssidName = WiFi . SSID ( ) ;
2021-05-12 02:09:17 +08:00
Serial . printf ( " WiFi Ssid: %s \r \n " , ssidName . c_str ( ) ) ;
Serial . printf ( " WiFi Rssi: %i \r \n " , WiFi . RSSI ( ) ) ;
2021-05-09 18:45:10 +08:00
String bssid = WiFi . BSSIDstr ( ) ;
2021-05-12 02:09:17 +08:00
Serial . printf ( " WiFi BSSID: %s \r \n " , bssid . c_str ( ) ) ;
2021-05-09 18:45:10 +08:00
}
2021-05-12 02:09:17 +08:00
Serial . printf ( " WiFi IP address: %d.%d.%d.%d \r \n " , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] ) ;
2021-05-09 18:45:10 +08:00
if ( ! accesspoint ) {
2021-05-12 02:09:17 +08:00
Serial . printf ( " WiFi Netmask: %d.%d.%d.%d \r \n " , net [ 0 ] , net [ 1 ] , net [ 2 ] , net [ 3 ] ) ;
Serial . printf ( " WiFi Gateway: %d.%d.%d.%d \r \n " , gw [ 0 ] , gw [ 1 ] , gw [ 2 ] , gw [ 3 ] ) ;
2021-05-09 18:45:10 +08:00
}
2021-05-12 02:09:17 +08:00
Serial . printf ( " WiFi Http port: %i, Stream port: %i \r \n " , httpPort , streamPort ) ;
2021-05-09 18:45:10 +08:00
byte mac [ 6 ] ;
WiFi . macAddress ( mac ) ;
2021-05-12 02:09:17 +08:00
Serial . printf ( " WiFi MAC: %02X:%02X:%02X:%02X:%02X:%02X \r \n " , mac [ 0 ] , mac [ 1 ] , mac [ 2 ] , mac [ 3 ] , mac [ 4 ] , mac [ 5 ] ) ;
2021-05-09 18:45:10 +08:00
// System
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 ;
2021-09-03 20:13:40 +08:00
int McuTc = ( temprature_sens_read ( ) - 32 ) / 1.8 ; // celsius
int McuTf = temprature_sens_read ( ) ; // fahrenheit
2021-05-12 02:09:17 +08:00
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 ) ;
2022-03-08 18:34:45 +08:00
Serial . printf ( " CPU Freq: %i MHz, Xclk Freq: %i MHz \r \n " , ESP . getCpuFreqMHz ( ) , xclk ) ;
2021-09-03 20:13:40 +08:00
Serial . printf ( " MCU temperature : %i C, %i F (approximate) \r \n " , McuTc , McuTf ) ;
2021-05-12 02:09:17 +08:00
Serial . printf ( " Heap: %i, free: %i, min free: %i, max block: %i \r \n " , ESP . getHeapSize ( ) , ESP . getFreeHeap ( ) , ESP . getMinFreeHeap ( ) , ESP . getMaxAllocHeap ( ) ) ;
2021-09-26 17:27:05 +08:00
if ( psramFound ( ) ) {
Serial . printf ( " Psram: %i, free: %i, min free: %i, max block: %i \r \n " , ESP . getPsramSize ( ) , ESP . getFreePsram ( ) , ESP . getMinFreePsram ( ) , ESP . getMaxAllocPsram ( ) ) ;
} else {
Serial . printf ( " Psram: Not found; please check your board configuration. \r \n " ) ;
Serial . printf ( " - High resolution/quality settings will show incomplete frames to low memory. \r \n " ) ;
}
2021-06-09 02:42:14 +08:00
// Filesystems
2021-09-26 17:27:05 +08:00
if ( filesystem & & ( SPIFFS . totalBytes ( ) > 0 ) ) {
2021-05-12 02:09:17 +08:00
Serial . printf ( " Spiffs: %i, used: %i \r \n " , SPIFFS . totalBytes ( ) , SPIFFS . usedBytes ( ) ) ;
2021-09-26 17:27:05 +08:00
} else {
Serial . printf ( " Spiffs: No filesystem found, please check your board configuration. \r \n " ) ;
Serial . printf ( " - Saving and restoring camera settings will not function without this. \r \n " ) ;
2021-05-09 18:45:10 +08:00
}
2021-06-09 02:42:14 +08:00
Serial . println ( " Preferences file: " ) ;
dumpPrefs ( SPIFFS ) ;
if ( critERR . length ( ) > 0 ) {
Serial . printf ( " \r \n \r \n A critical error has occurred when initialising Camera Hardware, see startup megssages \r \n " ) ;
}
2021-05-09 18:45:10 +08:00
Serial . println ( ) ;
return ;
}
2019-11-15 00:01:37 +08:00
static esp_err_t capture_handler ( httpd_req_t * req ) {
camera_fb_t * fb = NULL ;
esp_err_t res = ESP_OK ;
2020-10-12 00:19:22 +08:00
Serial . println ( " Capture Requested " ) ;
2021-12-31 09:47:58 +08:00
if ( autoLamp & & ( lampVal ! = - 1 ) ) {
setLamp ( lampVal ) ;
delay ( 75 ) ; // coupled with the status led flash this gives ~150ms for lamp to settle.
}
2019-11-19 09:50:01 +08:00
flashLED ( 75 ) ; // little flash of status LED
2019-11-15 00:01:37 +08:00
int64_t fr_start = esp_timer_get_time ( ) ;
fb = esp_camera_fb_get ( ) ;
if ( ! fb ) {
2021-05-12 02:09:17 +08:00
Serial . println ( " CAPTURE: failed to acquire frame " ) ;
2019-11-15 00:01:37 +08:00
httpd_resp_send_500 ( req ) ;
2020-10-26 07:04:21 +08:00
if ( autoLamp & & ( lampVal ! = - 1 ) ) setLamp ( 0 ) ;
2019-11-15 00:01:37 +08:00
return ESP_FAIL ;
}
httpd_resp_set_type ( req , " image/jpeg " ) ;
httpd_resp_set_hdr ( req , " Content-Disposition " , " inline; filename=capture.jpg " ) ;
httpd_resp_set_hdr ( req , " Access-Control-Allow-Origin " , " * " ) ;
2021-06-08 21:49:10 +08:00
size_t fb_len = 0 ;
if ( fb - > format = = PIXFORMAT_JPEG ) {
fb_len = fb - > len ;
res = httpd_resp_send ( req , ( const char * ) fb - > buf , fb - > len ) ;
} else {
2021-09-03 21:17:04 +08:00
res = ESP_FAIL ;
Serial . println ( " Capture Error: Non-JPEG image returned by camera module " ) ;
2019-11-15 00:01:37 +08:00
}
esp_camera_fb_return ( fb ) ;
2021-12-31 09:47:58 +08:00
fb = NULL ;
2019-11-15 00:01:37 +08:00
int64_t fr_end = esp_timer_get_time ( ) ;
2020-10-12 00:19:22 +08:00
if ( debugData ) {
2021-06-08 21:49:10 +08:00
Serial . printf ( " JPG: %uB %ums \r \n " , ( uint32_t ) ( fb_len ) , ( uint32_t ) ( ( fr_end - fr_start ) / 1000 ) ) ;
2020-10-12 00:19:22 +08:00
}
2021-05-09 18:45:10 +08:00
imagesServed + + ;
2021-12-31 09:47:58 +08:00
if ( autoLamp & & ( lampVal ! = - 1 ) ) {
setLamp ( 0 ) ;
}
2019-11-15 00:01:37 +08:00
return res ;
}
static esp_err_t stream_handler ( httpd_req_t * req ) {
camera_fb_t * fb = NULL ;
esp_err_t res = ESP_OK ;
size_t _jpg_buf_len = 0 ;
uint8_t * _jpg_buf = NULL ;
char * part_buf [ 64 ] ;
2020-08-24 03:49:10 +08:00
2022-03-08 18:34:45 +08:00
streamKill = false ;
2020-10-12 00:19:22 +08:00
Serial . println ( " Stream requested " ) ;
2020-10-26 07:04:21 +08:00
if ( autoLamp & & ( lampVal ! = - 1 ) ) setLamp ( lampVal ) ;
2021-05-09 18:45:10 +08:00
streamCount = 1 ; // at present we only have one stream handler, so values are 0 or 1..
2020-10-26 07:04:21 +08:00
flashLED ( 75 ) ; // double flash of status LED
2020-09-27 21:21:44 +08:00
delay ( 75 ) ;
flashLED ( 75 ) ;
2019-11-19 09:50:01 +08:00
2019-11-15 00:01:37 +08:00
static int64_t last_frame = 0 ;
if ( ! last_frame ) {
last_frame = esp_timer_get_time ( ) ;
}
res = httpd_resp_set_type ( req , _STREAM_CONTENT_TYPE ) ;
if ( res ! = ESP_OK ) {
2021-05-09 18:45:10 +08:00
streamCount = 0 ;
2020-10-26 07:04:21 +08:00
if ( autoLamp & & ( lampVal ! = - 1 ) ) setLamp ( 0 ) ;
2021-05-12 02:09:17 +08:00
Serial . println ( " STREAM: failed to set HTTP response type " ) ;
2019-11-15 00:01:37 +08:00
return res ;
}
httpd_resp_set_hdr ( req , " Access-Control-Allow-Origin " , " * " ) ;
2021-12-19 07:12:10 +08:00
if ( res = = ESP_OK ) {
res = httpd_resp_send_chunk ( req , _STREAM_BOUNDARY , strlen ( _STREAM_BOUNDARY ) ) ;
}
2019-11-15 00:01:37 +08:00
while ( true ) {
fb = esp_camera_fb_get ( ) ;
if ( ! fb ) {
2021-05-12 02:09:17 +08:00
Serial . println ( " STREAM: failed to acquire frame " ) ;
2019-11-15 00:01:37 +08:00
res = ESP_FAIL ;
} else {
2021-06-08 21:49:10 +08:00
if ( fb - > format ! = PIXFORMAT_JPEG ) {
2021-09-03 21:17:04 +08:00
Serial . println ( " STREAM: Non-JPEG frame returned by camera module " ) ;
res = ESP_FAIL ;
2021-06-08 21:49:10 +08:00
} else {
_jpg_buf_len = fb - > len ;
_jpg_buf = fb - > buf ;
2019-11-15 00:01:37 +08:00
}
}
if ( res = = ESP_OK ) {
size_t hlen = snprintf ( ( char * ) part_buf , 64 , _STREAM_PART , _jpg_buf_len ) ;
res = httpd_resp_send_chunk ( req , ( const char * ) part_buf , hlen ) ;
}
if ( res = = ESP_OK ) {
res = httpd_resp_send_chunk ( req , ( const char * ) _jpg_buf , _jpg_buf_len ) ;
}
2021-12-19 05:08:16 +08:00
if ( res = = ESP_OK ) {
res = httpd_resp_send_chunk ( req , _STREAM_BOUNDARY , strlen ( _STREAM_BOUNDARY ) ) ;
}
2019-11-15 00:01:37 +08:00
if ( fb ) {
esp_camera_fb_return ( fb ) ;
fb = NULL ;
_jpg_buf = NULL ;
} else if ( _jpg_buf ) {
free ( _jpg_buf ) ;
_jpg_buf = NULL ;
}
2022-03-08 18:34:45 +08:00
if ( ( res ! = ESP_OK ) | | streamKill ) {
2021-05-12 02:09:17 +08:00
// 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.
2019-11-15 00:01:37 +08:00
break ;
}
2021-06-08 21:49:10 +08:00
int64_t frame_time = esp_timer_get_time ( ) - last_frame ;
2020-10-12 00:19:22 +08:00
frame_time / = 1000 ;
2021-12-18 19:29:43 +08:00
int32_t frame_delay = ( minFrameTime > frame_time ) ? minFrameTime - frame_time : 0 ;
2021-12-17 05:14:44 +08:00
delay ( frame_delay ) ;
2020-10-12 00:19:22 +08:00
if ( debugData ) {
2021-12-17 05:14:44 +08:00
Serial . printf ( " MJPG: %uB %ums, delay: %ums, framerate (%.1ffps) \r \n " ,
2021-06-08 21:49:10 +08:00
( uint32_t ) ( _jpg_buf_len ) ,
2021-12-17 05:14:44 +08:00
( uint32_t ) frame_time , frame_delay , 1000.0 / ( uint32_t ) ( frame_time + frame_delay ) ) ;
2020-10-12 00:19:22 +08:00
}
2021-12-17 05:14:44 +08:00
last_frame = esp_timer_get_time ( ) ;
2019-11-15 00:01:37 +08:00
}
2021-05-09 18:45:10 +08:00
streamsServed + + ;
streamCount = 0 ;
2020-10-26 07:04:21 +08:00
if ( autoLamp & & ( lampVal ! = - 1 ) ) setLamp ( 0 ) ;
Serial . println ( " Stream ended " ) ;
2019-11-15 00:01:37 +08:00
last_frame = 0 ;
return res ;
}
static esp_err_t cmd_handler ( httpd_req_t * req ) {
char * buf ;
size_t buf_len ;
char variable [ 32 ] = { 0 , } ;
char value [ 32 ] = { 0 , } ;
2021-09-26 09:00:15 +08:00
2020-09-27 21:21:44 +08:00
flashLED ( 75 ) ;
2019-11-15 00:01:37 +08:00
buf_len = httpd_req_get_url_query_len ( req ) + 1 ;
if ( buf_len > 1 ) {
buf = ( char * ) malloc ( buf_len ) ;
if ( ! buf ) {
httpd_resp_send_500 ( req ) ;
return ESP_FAIL ;
}
if ( httpd_req_get_url_query_str ( req , buf , buf_len ) = = ESP_OK ) {
if ( httpd_query_key_value ( buf , " var " , variable , sizeof ( variable ) ) = = ESP_OK & &
httpd_query_key_value ( buf , " val " , value , sizeof ( value ) ) = = ESP_OK ) {
} else {
free ( buf ) ;
httpd_resp_send_404 ( req ) ;
return ESP_FAIL ;
}
} else {
free ( buf ) ;
httpd_resp_send_404 ( req ) ;
return ESP_FAIL ;
}
free ( buf ) ;
} else {
httpd_resp_send_404 ( req ) ;
return ESP_FAIL ;
}
2020-09-29 02:32:12 +08:00
2019-11-15 00:01:37 +08:00
int val = atoi ( value ) ;
sensor_t * s = esp_camera_sensor_get ( ) ;
int res = 0 ;
if ( ! strcmp ( variable , " framesize " ) ) {
if ( s - > pixformat = = PIXFORMAT_JPEG ) res = s - > set_framesize ( s , ( framesize_t ) val ) ;
}
else if ( ! strcmp ( variable , " quality " ) ) res = s - > set_quality ( s , val ) ;
2022-03-08 18:34:45 +08:00
else if ( ! strcmp ( variable , " xclk " ) ) { xclk = val ; res = s - > set_xclk ( s , LEDC_TIMER_0 , val ) ; }
2019-11-15 00:01:37 +08:00
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 ) ;
else if ( ! strcmp ( variable , " gainceiling " ) ) res = s - > set_gainceiling ( s , ( gainceiling_t ) val ) ;
else if ( ! strcmp ( variable , " colorbar " ) ) res = s - > set_colorbar ( s , val ) ;
else if ( ! strcmp ( variable , " awb " ) ) res = s - > set_whitebal ( s , val ) ;
else if ( ! strcmp ( variable , " agc " ) ) res = s - > set_gain_ctrl ( s , val ) ;
else if ( ! strcmp ( variable , " aec " ) ) res = s - > set_exposure_ctrl ( s , val ) ;
else if ( ! strcmp ( variable , " hmirror " ) ) res = s - > set_hmirror ( s , val ) ;
else if ( ! strcmp ( variable , " vflip " ) ) res = s - > set_vflip ( s , val ) ;
else if ( ! strcmp ( variable , " awb_gain " ) ) res = s - > set_awb_gain ( s , val ) ;
else if ( ! strcmp ( variable , " agc_gain " ) ) res = s - > set_agc_gain ( s , val ) ;
else if ( ! strcmp ( variable , " aec_value " ) ) res = s - > set_aec_value ( s , val ) ;
else if ( ! strcmp ( variable , " aec2 " ) ) res = s - > set_aec2 ( s , val ) ;
else if ( ! strcmp ( variable , " dcw " ) ) res = s - > set_dcw ( s , val ) ;
else if ( ! strcmp ( variable , " bpc " ) ) res = s - > set_bpc ( s , val ) ;
else if ( ! strcmp ( variable , " wpc " ) ) res = s - > set_wpc ( s , val ) ;
else if ( ! strcmp ( variable , " raw_gma " ) ) res = s - > set_raw_gma ( s , val ) ;
else if ( ! strcmp ( variable , " lenc " ) ) res = s - > set_lenc ( s , val ) ;
else if ( ! strcmp ( variable , " special_effect " ) ) res = s - > set_special_effect ( s , val ) ;
else if ( ! strcmp ( variable , " wb_mode " ) ) res = s - > set_wb_mode ( s , val ) ;
else if ( ! strcmp ( variable , " ae_level " ) ) res = s - > set_ae_level ( s , val ) ;
2020-09-22 16:47:47 +08:00
else if ( ! strcmp ( variable , " rotate " ) ) myRotation = val ;
2021-12-18 19:29:43 +08:00
else if ( ! strcmp ( variable , " min_frame_time " ) ) minFrameTime = val ;
2020-10-26 07:04:21 +08:00
else if ( ! strcmp ( variable , " autolamp " ) & & ( lampVal ! = - 1 ) ) {
autoLamp = val ;
if ( autoLamp ) {
if ( streamCount > 0 ) setLamp ( lampVal ) ;
else setLamp ( 0 ) ;
} else {
setLamp ( lampVal ) ;
}
}
2019-11-16 22:24:25 +08:00
else if ( ! strcmp ( variable , " lamp " ) & & ( lampVal ! = - 1 ) ) {
2020-09-27 21:21:44 +08:00
lampVal = constrain ( val , 0 , 100 ) ;
2020-10-26 07:04:21 +08:00
if ( autoLamp ) {
if ( streamCount > 0 ) setLamp ( lampVal ) ;
else setLamp ( 0 ) ;
} else {
setLamp ( lampVal ) ;
}
2020-09-27 21:21:44 +08:00
}
else if ( ! strcmp ( variable , " save_prefs " ) ) {
if ( filesystem ) savePrefs ( SPIFFS ) ;
}
else if ( ! strcmp ( variable , " clear_prefs " ) ) {
if ( filesystem ) removePrefs ( SPIFFS ) ;
}
else if ( ! strcmp ( variable , " reboot " ) ) {
2022-03-09 18:40:40 +08:00
if ( lampVal ! = - 1 ) setLamp ( 0 ) ; // kill the lamp; otherwise it can remain on during the soft-reboot
2020-11-21 00:05:00 +08:00
esp_task_wdt_init ( 3 , true ) ; // schedule a a watchdog panic event for 3 seconds in the future
esp_task_wdt_add ( NULL ) ;
periph_module_disable ( PERIPH_I2C0_MODULE ) ; // try to shut I2C down properly
periph_module_disable ( PERIPH_I2C1_MODULE ) ;
periph_module_reset ( PERIPH_I2C0_MODULE ) ;
periph_module_reset ( PERIPH_I2C1_MODULE ) ;
2020-09-27 21:21:44 +08:00
Serial . print ( " REBOOT requested " ) ;
2020-11-21 00:05:00 +08:00
while ( true ) {
2020-09-30 21:41:42 +08:00
flashLED ( 50 ) ;
2020-10-06 19:29:54 +08:00
delay ( 150 ) ;
2020-09-27 21:21:44 +08:00
Serial . print ( ' . ' ) ;
}
2019-11-15 00:01:37 +08:00
}
else {
res = - 1 ;
}
if ( res ) {
return httpd_resp_send_500 ( req ) ;
}
httpd_resp_set_hdr ( req , " Access-Control-Allow-Origin " , " * " ) ;
return httpd_resp_send ( req , NULL , 0 ) ;
}
static esp_err_t status_handler ( httpd_req_t * req ) {
static char json_response [ 1024 ] ;
sensor_t * s = esp_camera_sensor_get ( ) ;
char * p = json_response ;
* p + + = ' { ' ;
2020-09-27 21:21:44 +08:00
p + = sprintf ( p , " \" lamp \" :%d, " , lampVal ) ;
2020-10-26 07:04:21 +08:00
p + = sprintf ( p , " \" autolamp \" :%d, " , autoLamp ) ;
2021-12-18 19:29:43 +08:00
p + = sprintf ( p , " \" min_frame_time \" :%d, " , minFrameTime ) ;
2019-11-15 00:01:37 +08:00
p + = sprintf ( p , " \" framesize \" :%u, " , s - > status . framesize ) ;
p + = sprintf ( p , " \" quality \" :%u, " , s - > status . quality ) ;
2022-03-08 18:34:45 +08:00
p + = sprintf ( p , " \" xclk \" :%u, " , xclk ) ;
2019-11-15 00:01:37 +08:00
p + = sprintf ( p , " \" brightness \" :%d, " , s - > status . brightness ) ;
p + = sprintf ( p , " \" contrast \" :%d, " , s - > status . contrast ) ;
p + = sprintf ( p , " \" saturation \" :%d, " , s - > status . saturation ) ;
p + = sprintf ( p , " \" sharpness \" :%d, " , s - > status . sharpness ) ;
p + = sprintf ( p , " \" special_effect \" :%u, " , s - > status . special_effect ) ;
p + = sprintf ( p , " \" wb_mode \" :%u, " , s - > status . wb_mode ) ;
p + = sprintf ( p , " \" awb \" :%u, " , s - > status . awb ) ;
p + = sprintf ( p , " \" awb_gain \" :%u, " , s - > status . awb_gain ) ;
p + = sprintf ( p , " \" aec \" :%u, " , s - > status . aec ) ;
p + = sprintf ( p , " \" aec2 \" :%u, " , s - > status . aec2 ) ;
p + = sprintf ( p , " \" ae_level \" :%d, " , s - > status . ae_level ) ;
p + = sprintf ( p , " \" aec_value \" :%u, " , s - > status . aec_value ) ;
p + = sprintf ( p , " \" agc \" :%u, " , s - > status . agc ) ;
p + = sprintf ( p , " \" agc_gain \" :%u, " , s - > status . agc_gain ) ;
p + = sprintf ( p , " \" gainceiling \" :%u, " , s - > status . gainceiling ) ;
p + = sprintf ( p , " \" bpc \" :%u, " , s - > status . bpc ) ;
p + = sprintf ( p , " \" wpc \" :%u, " , s - > status . wpc ) ;
p + = sprintf ( p , " \" raw_gma \" :%u, " , s - > status . raw_gma ) ;
p + = sprintf ( p , " \" lenc \" :%u, " , s - > status . lenc ) ;
p + = sprintf ( p , " \" vflip \" :%u, " , s - > status . vflip ) ;
p + = sprintf ( p , " \" hmirror \" :%u, " , s - > status . hmirror ) ;
p + = sprintf ( p , " \" dcw \" :%u, " , s - > status . dcw ) ;
p + = sprintf ( p , " \" colorbar \" :%u, " , s - > status . colorbar ) ;
2019-11-18 09:43:07 +08:00
p + = sprintf ( p , " \" cam_name \" : \" %s \" , " , myName ) ;
2020-08-22 00:36:36 +08:00
p + = sprintf ( p , " \" code_ver \" : \" %s \" , " , myVer ) ;
2020-09-22 16:47:47 +08:00
p + = sprintf ( p , " \" rotate \" : \" %d \" , " , myRotation ) ;
2020-09-15 06:04:45 +08:00
p + = sprintf ( p , " \" stream_url \" : \" %s \" " , streamURL ) ;
* p + + = ' } ' ;
* p + + = 0 ;
httpd_resp_set_type ( req , " application/json " ) ;
httpd_resp_set_hdr ( req , " Access-Control-Allow-Origin " , " * " ) ;
return httpd_resp_send ( req , json_response , strlen ( json_response ) ) ;
}
static esp_err_t info_handler ( httpd_req_t * req ) {
static char json_response [ 256 ] ;
char * p = json_response ;
* p + + = ' { ' ;
p + = sprintf ( p , " \" cam_name \" : \" %s \" , " , myName ) ;
2020-09-22 16:47:47 +08:00
p + = sprintf ( p , " \" rotate \" : \" %d \" , " , myRotation ) ;
2020-09-15 06:04:45 +08:00
p + = sprintf ( p , " \" stream_url \" : \" %s \" " , streamURL ) ;
2019-11-15 00:01:37 +08:00
* p + + = ' } ' ;
* p + + = 0 ;
httpd_resp_set_type ( req , " application/json " ) ;
httpd_resp_set_hdr ( req , " Access-Control-Allow-Origin " , " * " ) ;
return httpd_resp_send ( req , json_response , strlen ( json_response ) ) ;
}
2020-09-10 10:26:34 +08:00
static esp_err_t favicon_16x16_handler ( httpd_req_t * req ) {
httpd_resp_set_type ( req , " image/png " ) ;
httpd_resp_set_hdr ( req , " Content-Encoding " , " identity " ) ;
return httpd_resp_send ( req , ( const char * ) favicon_16x16_png , favicon_16x16_png_len ) ;
}
static esp_err_t favicon_32x32_handler ( httpd_req_t * req ) {
httpd_resp_set_type ( req , " image/png " ) ;
httpd_resp_set_hdr ( req , " Content-Encoding " , " identity " ) ;
return httpd_resp_send ( req , ( const char * ) favicon_32x32_png , favicon_32x32_png_len ) ;
}
static esp_err_t favicon_ico_handler ( httpd_req_t * req ) {
httpd_resp_set_type ( req , " image/x-icon " ) ;
httpd_resp_set_hdr ( req , " Content-Encoding " , " identity " ) ;
return httpd_resp_send ( req , ( const char * ) favicon_ico , favicon_ico_len ) ;
}
2020-10-07 08:08:18 +08:00
static esp_err_t logo_svg_handler ( httpd_req_t * req ) {
httpd_resp_set_type ( req , " image/svg+xml " ) ;
httpd_resp_set_hdr ( req , " Content-Encoding " , " identity " ) ;
return httpd_resp_send ( req , ( const char * ) logo_svg , logo_svg_len ) ;
}
2020-10-04 01:49:08 +08:00
static esp_err_t dump_handler ( httpd_req_t * req ) {
2020-09-27 21:21:44 +08:00
flashLED ( 75 ) ;
2022-03-08 18:34:45 +08:00
Serial . println ( " \r \n Dump requested via Web " ) ;
2021-05-09 18:45:10 +08:00
serialDump ( ) ;
2020-11-21 00:05:00 +08:00
static char dumpOut [ 2000 ] = " " ;
2020-10-04 01:49:08 +08:00
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 " ) ;
2020-11-21 00:05:00 +08:00
d + = sprintf ( d , " </head> \n " ) ;
d + = sprintf ( d , " <body> \n " ) ;
2022-03-09 15:40:00 +08:00
d + = sprintf ( d , " <img src= \" /logo.svg \" style= \" position: relative; float: right; \" > \n " ) ;
2020-11-21 00:05:00 +08:00
if ( critERR . length ( ) > 0 ) {
2021-09-26 17:27:05 +08:00
d + = sprintf ( d , " <span style= \" color:red; \" >%s<hr></span> \n " , critERR . c_str ( ) ) ;
d + = sprintf ( d , " <h2 style= \" color:red; \" >(the serial log may give more information)</h2><br> \n " ) ;
2020-11-21 00:05:00 +08:00
}
d + = sprintf ( d , " <h1>ESP32 Cam Webserver</h1> \n " ) ;
2020-10-04 01:49:08 +08:00
// Module
d + = sprintf ( d , " Name: %s<br> \n " , myName ) ;
2020-10-12 19:17:21 +08:00
d + = sprintf ( d , " Firmware: %s (base: %s)<br> \n " , myVer , baseVersion ) ;
2020-10-04 01:49:08 +08:00
float sketchPct = 100 * sketchSize / sketchSpace ;
d + = sprintf ( d , " Sketch Size: %i (total: %i, %.1f%% used)<br> \n " , sketchSize , sketchSpace , sketchPct ) ;
d + = sprintf ( d , " MD5: %s<br> \n " , sketchMD5 . c_str ( ) ) ;
d + = sprintf ( d , " ESP sdk: %s<br> \n " , ESP . getSdkVersion ( ) ) ;
// Network
d + = sprintf ( d , " <h2>WiFi</h2> \n " ) ;
2020-10-06 19:29:54 +08:00
if ( accesspoint ) {
if ( captivePortal ) {
d + = sprintf ( d , " Mode: AccessPoint with captive portal<br> \n " ) ;
} else {
d + = sprintf ( d , " Mode: AccessPoint<br> \n " ) ;
}
d + = sprintf ( d , " SSID: %s<br> \n " , apName ) ;
} else {
d + = sprintf ( d , " Mode: Client<br> \n " ) ;
String ssidName = WiFi . SSID ( ) ;
d + = sprintf ( d , " SSID: %s<br> \n " , ssidName . c_str ( ) ) ;
d + = sprintf ( d , " Rssi: %i<br> \n " , WiFi . RSSI ( ) ) ;
String bssid = WiFi . BSSIDstr ( ) ;
d + = sprintf ( d , " BSSID: %s<br> \n " , bssid . c_str ( ) ) ;
}
2020-10-04 01:49:08 +08:00
d + = sprintf ( d , " IP address: %d.%d.%d.%d<br> \n " , ip [ 0 ] , ip [ 1 ] , ip [ 2 ] , ip [ 3 ] ) ;
2020-10-06 19:29:54 +08:00
if ( ! accesspoint ) {
d + = sprintf ( d , " Netmask: %d.%d.%d.%d<br> \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 ] ) ;
}
d + = sprintf ( d , " Http port: %i, Stream port: %i<br> \n " , httpPort , streamPort ) ;
byte mac [ 6 ] ;
WiFi . macAddress ( mac ) ;
d + = sprintf ( d , " MAC: %02X:%02X:%02X:%02X:%02X:%02X<br> \n " , mac [ 0 ] , mac [ 1 ] , mac [ 2 ] , mac [ 3 ] , mac [ 4 ] , mac [ 5 ] ) ;
2020-10-04 01:49:08 +08:00
// System
d + = sprintf ( d , " <h2>System</h2> \n " ) ;
2021-06-09 02:42:14 +08:00
if ( haveTime ) {
struct tm timeinfo ;
if ( getLocalTime ( & timeinfo ) ) {
char timeStringBuff [ 50 ] ; //50 chars should be enough
strftime ( timeStringBuff , sizeof ( timeStringBuff ) , " %H:%M:%S, %A, %B %d %Y " , & timeinfo ) ;
//print like "const char*"
d + = sprintf ( d , " Time: %s<br> \n " , timeStringBuff ) ;
}
}
2020-10-04 01:49:08 +08:00
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 ;
2021-09-03 20:13:40 +08:00
int McuTc = ( temprature_sens_read ( ) - 32 ) / 1.8 ; // celsius
int McuTf = temprature_sens_read ( ) ; // fahrenheit
2020-10-04 01:49:08 +08:00
d + = sprintf ( d , " Up: % " PRId64 " :%02i:%02i:%02i (d:h:m:s)<br> \n " , upDays , upHours , upMin , upSec ) ;
2021-05-09 21:04:00 +08:00
d + = sprintf ( d , " Active streams: %i, Previous streams: %lu, Images captured: %lu<br> \n " , streamCount , streamsServed , imagesServed ) ;
2022-03-08 18:34:45 +08:00
d + = sprintf ( d , " CPU Freq: %i MHz, Xclk Freq: %i MHz<br> \n " , ESP . getCpuFreqMHz ( ) , xclk ) ;
2021-09-03 20:13:40 +08:00
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 °C, %i °F</span> \n <br> " , McuTc , McuTf ) ;
2020-10-04 01:49:08 +08:00
d + = sprintf ( d , " Heap: %i, free: %i, min free: %i, max block: %i<br> \n " , ESP . getHeapSize ( ) , ESP . getFreeHeap ( ) , ESP . getMinFreeHeap ( ) , ESP . getMaxAllocHeap ( ) ) ;
2021-09-26 17:27:05 +08:00
if ( psramFound ( ) ) {
d + = sprintf ( d , " Psram: %i, free: %i, min free: %i, max block: %i<br> \n " , ESP . getPsramSize ( ) , ESP . getFreePsram ( ) , ESP . getMinFreePsram ( ) , ESP . getMaxAllocPsram ( ) ) ;
} else {
d + = sprintf ( d , " Psram: <span style= \" color:red; \" >Not found</span>, please check your board configuration.<br> \n " ) ;
d + = sprintf ( d , " - High resolution/quality images & streams will show incomplete frames due to low memory.<br> \n " ) ;
}
if ( filesystem & & ( SPIFFS . totalBytes ( ) > 0 ) ) {
2020-10-04 01:49:08 +08:00
d + = sprintf ( d , " Spiffs: %i, used: %i<br> \n " , SPIFFS . totalBytes ( ) , SPIFFS . usedBytes ( ) ) ;
2021-09-26 17:27:05 +08:00
} else {
d + = sprintf ( d , " Spiffs: <span style= \" color:red; \" >No filesystem found</span>, please check your board configuration.<br> \n " ) ;
d + = sprintf ( d , " - saving and restoring camera settings will not function without this.<br> \n " ) ;
2020-10-04 01:49:08 +08:00
}
2020-10-12 00:19:22 +08:00
2020-10-04 01:49:08 +08:00
// Footer
d + = sprintf ( d , " <br><div class= \" input-group \" > \n " ) ;
2020-11-21 00:05:00 +08:00
d + = sprintf ( d , " <button title= \" Instant Refresh; the page reloads every minute anyway \" onclick= \" location.replace(document.URL) \" >Refresh</button> \n " ) ;
2022-03-08 18:34:45 +08:00
d + = sprintf ( d , " <button title= \" Stop any active streams \" onclick= \" let throwaway = fetch('stop');setTimeout(function(){ \n location.replace(document.URL); \n }, 200); \" >Stop Stream</button> \n " ) ;
2020-10-04 01:49:08 +08:00
d + = sprintf ( d , " <button title= \" Close this page \" onclick= \" javascript:window.close() \" >Close</button> \n " ) ;
2020-11-21 00:05:00 +08:00
d + = sprintf ( d , " </div> \n </body> \n " ) ;
// A javascript timer to refresh the page every minute.
d + = sprintf ( d , " <script> \n setTimeout(function(){ \n location.replace(document.URL); \n }, 60000); \n " ) ;
d + = sprintf ( d , " </script> \n </html> \n " ) ;
2020-10-04 01:49:08 +08:00
* d + + = 0 ;
httpd_resp_set_type ( req , " text/html " ) ;
2020-09-27 21:21:44 +08:00
httpd_resp_set_hdr ( req , " Content-Encoding " , " identity " ) ;
2020-10-04 01:49:08 +08:00
return httpd_resp_send ( req , dumpOut , strlen ( dumpOut ) ) ;
2020-09-27 21:21:44 +08:00
}
2022-03-08 18:34:45 +08:00
static esp_err_t stop_handler ( httpd_req_t * req ) {
flashLED ( 75 ) ;
Serial . println ( " \r \n Stream stop requested via Web " ) ;
streamKill = true ;
httpd_resp_set_hdr ( req , " Access-Control-Allow-Origin " , " * " ) ;
return httpd_resp_send ( req , NULL , 0 ) ;
}
2020-09-13 21:28:38 +08:00
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 " ) ;
return httpd_resp_send ( req , ( const char * ) style_css , style_css_len ) ;
}
2020-09-15 06:04:45 +08:00
static esp_err_t streamviewer_handler ( httpd_req_t * req ) {
flashLED ( 75 ) ;
2022-03-08 18:34:45 +08:00
Serial . println ( " Stream viewer requested " ) ;
2020-09-15 06:04:45 +08:00
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 ) ;
}
2020-11-21 00:05:00 +08:00
static esp_err_t error_handler ( httpd_req_t * req ) {
flashLED ( 75 ) ;
2022-03-08 18:34:45 +08:00
Serial . println ( " Sending error page " ) ;
2020-11-21 00:05:00 +08:00
std : : string s ( error_html ) ;
size_t index ;
while ( ( index = s . find ( " <APPURL> " ) ) ! = std : : string : : npos )
s . replace ( index , strlen ( " <APPURL> " ) , httpURL ) ;
while ( ( index = s . find ( " <CAMNAME> " ) ) ! = std : : string : : npos )
s . replace ( index , strlen ( " <CAMNAME> " ) , myName ) ;
while ( ( index = s . find ( " <ERRORTEXT> " ) ) ! = std : : string : : npos )
s . replace ( index , strlen ( " <ERRORTEXT> " ) , critERR . c_str ( ) ) ;
httpd_resp_set_type ( req , " text/html " ) ;
httpd_resp_set_hdr ( req , " Content-Encoding " , " identity " ) ;
return httpd_resp_send ( req , ( const char * ) s . c_str ( ) , s . length ( ) ) ;
}
2019-11-15 00:01:37 +08:00
static esp_err_t index_handler ( httpd_req_t * req ) {
2020-10-07 08:08:18 +08:00
char * buf ;
size_t buf_len ;
char view [ 32 ] = { 0 , } ;
2019-11-19 09:50:01 +08:00
flashLED ( 75 ) ;
2020-10-07 18:19:19 +08:00
// See if we have a specific target (full/simple/portal) and serve as appropriate
2020-10-07 08:08:18 +08:00
buf_len = httpd_req_get_url_query_len ( req ) + 1 ;
if ( buf_len > 1 ) {
buf = ( char * ) malloc ( buf_len ) ;
if ( ! buf ) {
httpd_resp_send_500 ( req ) ;
return ESP_FAIL ;
}
if ( httpd_req_get_url_query_str ( req , buf , buf_len ) = = ESP_OK ) {
if ( httpd_query_key_value ( buf , " view " , view , sizeof ( view ) ) = = ESP_OK ) {
} else {
free ( buf ) ;
httpd_resp_send_404 ( req ) ;
return ESP_FAIL ;
}
} else {
free ( buf ) ;
httpd_resp_send_404 ( req ) ;
return ESP_FAIL ;
}
free ( buf ) ;
} else {
// no target specified; default.
2020-10-07 21:43:28 +08:00
strcpy ( view , default_index ) ;
// If captive portal is active send that instead
2020-10-07 08:08:18 +08:00
if ( captivePortal ) {
strcpy ( view , " portal " ) ;
}
}
if ( strncmp ( view , " simple " , sizeof ( view ) ) = = 0 ) {
Serial . println ( " Simple index page requested " ) ;
httpd_resp_set_type ( req , " text/html " ) ;
httpd_resp_set_hdr ( req , " Content-Encoding " , " identity " ) ;
return httpd_resp_send ( req , ( const char * ) index_simple_html , index_simple_html_len ) ;
} else if ( strncmp ( view , " full " , sizeof ( view ) ) = = 0 ) {
Serial . println ( " Full index page requested " ) ;
httpd_resp_set_type ( req , " text/html " ) ;
httpd_resp_set_hdr ( req , " Content-Encoding " , " identity " ) ;
sensor_t * s = esp_camera_sensor_get ( ) ;
if ( s - > id . PID = = OV3660_PID ) {
return httpd_resp_send ( req , ( const char * ) index_ov3660_html , index_ov3660_html_len ) ;
}
return httpd_resp_send ( req , ( const char * ) index_ov2640_html , index_ov2640_html_len ) ;
} else if ( strncmp ( view , " portal " , sizeof ( view ) ) = = 0 ) {
//Prototype captive portal landing page.
Serial . println ( " Portal page requested " ) ;
2020-10-07 18:19:19 +08:00
std : : string s ( portal_html ) ;
size_t index ;
while ( ( index = s . find ( " <APPURL> " ) ) ! = std : : string : : npos )
s . replace ( index , strlen ( " <APPURL> " ) , httpURL ) ;
while ( ( index = s . find ( " <STREAMURL> " ) ) ! = std : : string : : npos )
s . replace ( index , strlen ( " <STREAMURL> " ) , streamURL ) ;
while ( ( index = s . find ( " <CAMNAME> " ) ) ! = std : : string : : npos )
s . replace ( index , strlen ( " <CAMNAME> " ) , myName ) ;
2020-10-07 08:08:18 +08:00
httpd_resp_set_type ( req , " text/html " ) ;
httpd_resp_set_hdr ( req , " Content-Encoding " , " identity " ) ;
2020-10-07 18:19:19 +08:00
return httpd_resp_send ( req , ( const char * ) s . c_str ( ) , s . length ( ) ) ;
2020-10-07 08:08:18 +08:00
} else {
Serial . print ( " Unknown page requested: " ) ;
Serial . println ( view ) ;
httpd_resp_send_404 ( req ) ;
return ESP_FAIL ;
2019-11-15 00:01:37 +08:00
}
}
2020-09-09 08:57:37 +08:00
void startCameraServer ( int hPort , int sPort ) {
2019-11-15 00:01:37 +08:00
httpd_config_t config = HTTPD_DEFAULT_CONFIG ( ) ;
2022-03-08 18:34:45 +08:00
config . max_uri_handlers = 16 ; // we use more than the default 8 (on port 80)
2019-11-15 00:01:37 +08:00
httpd_uri_t index_uri = {
. uri = " / " ,
. method = HTTP_GET ,
. handler = index_handler ,
. user_ctx = NULL
} ;
httpd_uri_t status_uri = {
. uri = " /status " ,
. method = HTTP_GET ,
. handler = status_handler ,
. user_ctx = NULL
} ;
httpd_uri_t cmd_uri = {
. uri = " /control " ,
. method = HTTP_GET ,
. handler = cmd_handler ,
. user_ctx = NULL
} ;
httpd_uri_t capture_uri = {
. uri = " /capture " ,
. method = HTTP_GET ,
. handler = capture_handler ,
. user_ctx = NULL
} ;
2020-09-13 21:28:38 +08:00
httpd_uri_t style_uri = {
. uri = " /style.css " ,
. method = HTTP_GET ,
. handler = style_handler ,
. user_ctx = NULL
} ;
2020-09-10 10:26:34 +08:00
httpd_uri_t favicon_16x16_uri = {
. uri = " /favicon-16x16.png " ,
. method = HTTP_GET ,
. handler = favicon_16x16_handler ,
. user_ctx = NULL
} ;
httpd_uri_t favicon_32x32_uri = {
. uri = " /favicon-32x32.png " ,
. method = HTTP_GET ,
. handler = favicon_32x32_handler ,
. user_ctx = NULL
} ;
httpd_uri_t favicon_ico_uri = {
. uri = " /favicon.ico " ,
. method = HTTP_GET ,
. handler = favicon_ico_handler ,
. user_ctx = NULL
} ;
2020-10-07 08:08:18 +08:00
httpd_uri_t logo_svg_uri = {
. uri = " /logo.svg " ,
. method = HTTP_GET ,
. handler = logo_svg_handler ,
. user_ctx = NULL
} ;
2020-10-04 01:49:08 +08:00
httpd_uri_t dump_uri = {
2020-09-27 21:21:44 +08:00
. uri = " /dump " ,
. method = HTTP_GET ,
2020-10-04 01:49:08 +08:00
. handler = dump_handler ,
2020-09-27 21:21:44 +08:00
. user_ctx = NULL
} ;
2022-03-08 18:34:45 +08:00
httpd_uri_t stop_uri = {
. uri = " /stop " ,
. method = HTTP_GET ,
. handler = stop_handler ,
. user_ctx = NULL
} ;
2020-09-22 18:03:18 +08:00
httpd_uri_t stream_uri = {
2020-09-09 08:57:37 +08:00
. uri = " / " ,
2019-11-15 00:01:37 +08:00
. method = HTTP_GET ,
. handler = stream_handler ,
. user_ctx = NULL
} ;
2020-09-15 06:04:45 +08:00
httpd_uri_t streamviewer_uri = {
. uri = " /view " ,
. method = HTTP_GET ,
. handler = streamviewer_handler ,
. user_ctx = NULL
} ;
httpd_uri_t info_uri = {
. uri = " /info " ,
. method = HTTP_GET ,
. handler = info_handler ,
. user_ctx = NULL
} ;
2020-11-21 00:05:00 +08:00
httpd_uri_t error_uri = {
. uri = " / " ,
. method = HTTP_GET ,
. handler = error_handler ,
. user_ctx = NULL
} ;
httpd_uri_t viewerror_uri = {
. uri = " /view " ,
. method = HTTP_GET ,
. handler = error_handler ,
. user_ctx = NULL
} ;
2019-11-15 00:01:37 +08:00
2020-11-21 00:05:00 +08:00
// Request Handlers; config.max_uri_handlers (above) must be >= the number of handlers
2020-09-09 08:57:37 +08:00
config . server_port = hPort ;
config . ctrl_port = hPort ;
2021-05-12 02:09:17 +08:00
Serial . printf ( " Starting web server on port: '%d' \r \n " , config . server_port ) ;
2019-11-15 00:01:37 +08:00
if ( httpd_start ( & camera_httpd , & config ) = = ESP_OK ) {
2020-11-21 00:05:00 +08:00
if ( critERR . length ( ) > 0 ) {
httpd_register_uri_handler ( camera_httpd , & error_uri ) ;
} else {
httpd_register_uri_handler ( camera_httpd , & index_uri ) ;
httpd_register_uri_handler ( camera_httpd , & cmd_uri ) ;
httpd_register_uri_handler ( camera_httpd , & status_uri ) ;
httpd_register_uri_handler ( camera_httpd , & capture_uri ) ;
}
2020-09-13 21:28:38 +08:00
httpd_register_uri_handler ( camera_httpd , & style_uri ) ;
2020-09-10 10:26:34 +08:00
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 ) ;
2020-10-07 08:08:18 +08:00
httpd_register_uri_handler ( camera_httpd , & logo_svg_uri ) ;
2020-10-04 01:49:08 +08:00
httpd_register_uri_handler ( camera_httpd , & dump_uri ) ;
2022-03-08 18:34:45 +08:00
httpd_register_uri_handler ( camera_httpd , & stop_uri ) ;
2019-11-15 00:01:37 +08:00
}
2020-09-09 08:57:37 +08:00
config . server_port = sPort ;
config . ctrl_port = sPort ;
2021-05-12 02:09:17 +08:00
Serial . printf ( " Starting stream server on port: '%d' \r \n " , config . server_port ) ;
2019-11-15 00:01:37 +08:00
if ( httpd_start ( & stream_httpd , & config ) = = ESP_OK ) {
2020-11-21 00:05:00 +08:00
if ( critERR . length ( ) > 0 ) {
httpd_register_uri_handler ( camera_httpd , & error_uri ) ;
httpd_register_uri_handler ( camera_httpd , & viewerror_uri ) ;
} else {
httpd_register_uri_handler ( stream_httpd , & stream_uri ) ;
httpd_register_uri_handler ( stream_httpd , & info_uri ) ;
httpd_register_uri_handler ( stream_httpd , & streamviewer_uri ) ;
}
2020-09-10 10:26:34 +08:00
httpd_register_uri_handler ( stream_httpd , & favicon_16x16_uri ) ;
httpd_register_uri_handler ( stream_httpd , & favicon_32x32_uri ) ;
httpd_register_uri_handler ( stream_httpd , & favicon_ico_uri ) ;
2019-11-15 00:01:37 +08:00
}
}