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

4.0 release #229

Merged
merged 29 commits into from
Mar 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
158575a
Add framerate limit, print delay in debug dump.
Dec 16, 2021
1cda0e2
Add max fps control in full index page for ovh2640.
Dec 16, 2021
a63bcc3
Add max fps control for ov3660 index page.
Dec 16, 2021
69888bd
Update API documentation.
Dec 18, 2021
721e825
Use better name for framerate limit variables.
Dec 18, 2021
fdd9209
Change UI to show the same values of framerate control as used in com…
Dec 18, 2021
2846665
Merge branch 'easytarget:master' into framerate_limit
15498th Dec 18, 2021
a75627a
Merge branch 'framerate_limit' of https://github.com/15498th/esp32-ca…
Dec 18, 2021
1b836c5
Apply framerate limiting delay after serving content boundary.
Dec 18, 2021
20f4c24
Fix delay before first frame by sending first request boundary before
Dec 18, 2021
de01547
Xclock in gui and stream stop button
easytarget Mar 8, 2022
6d82527
Fail if no PSRAM, fix #196
easytarget Mar 8, 2022
9402cdf
remove the beta warning
easytarget Mar 8, 2022
2be6d0b
Start SPIFFS before camera module, #214
easytarget Mar 8, 2022
3fc9389
fix doc
easytarget Mar 9, 2022
322187c
Strip trailing whitespace everywhere
easytarget Mar 9, 2022
cb78162
lamp default state fix #204
easytarget Mar 9, 2022
f4bde8b
autolamp value in prefs should be bool
easytarget Mar 9, 2022
04a94ed
[ci skip] Add link to common issues in discussions
easytarget Mar 9, 2022
d064e88
Merge branch 'master' into 4-0-rc1
easytarget Mar 9, 2022
cfe81b0
Merge branch '4-0-rc1' into framerate_limit
easytarget Mar 9, 2022
9426f3f
Merge pull request #195 from 15498th/framerate_limit
easytarget Mar 9, 2022
273fdf6
note stream stop uri in API
easytarget Mar 10, 2022
a796676
fix build
easytarget Mar 10, 2022
fccbd75
mdns name and tooltips
easytarget Mar 10, 2022
4f58ba7
[ci skip] Comment change
easytarget Mar 10, 2022
c149e28
[skip ci] re-order troubleshooting section
easytarget Mar 10, 2022
31c381d
[ci skip] trivial update API doc
easytarget Mar 10, 2022
44042e0
Fix OTA and seperate camera init
easytarget Mar 11, 2022
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
4 changes: 3 additions & 1 deletion API.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The WebUI and camera server communicate entirely via HTTP requests and responses
* `/status` - Returns a JSON string with all camera status <key>/<value> pairs listed
* `/control?var=<key>&val=<val>` - Set `<key>` to `<val>`
* `/dump` - Status page
* `/stop` - End all active streams

### Stream Port
* `/` - Raw stream
Expand All @@ -26,6 +27,7 @@ Call `/control?var=<key>&val=<val>` with a settings key and value to set camera
```
lamp - Lamp value in percent; integer, 0 - 100 (-1 = disabled)
framesize - See below
min_frame_time - Minimal frame duration in ms; used to limit max FPS. Must be positive integer
quality - 10 to 63 (ov3660: 4 to 10)
contrast - -2 to 2 (ov3660: -3 to 3)
brightness - -2 to 2 (ov3660: -3 to 3)
Expand Down Expand Up @@ -101,7 +103,7 @@ reboot - Reboots the camera
* All settings are returned via single `status` call in [JSON](https://www.json.org/) format.
* `http://<IP-ADDRESS>/status`
* Returns:
``` {"lamp":0,"autolamp":0,"framesize":10,"quality":10,"brightness":0,"contrast":0,"saturation":0,"sharpness":0,"special_effect":0,"wb_mode":0,"awb":1,"awb_gain":1,"aec":1,"aec2":0,"ae_level":0,"aec_value":168,"agc":1,"agc_gain":0,"gainceiling":0,"bpc":0,"wpc":1,"raw_gma":1,"lenc":1,"vflip":0,"hmirror":0,"dcw":1,"colorbar":0,"face_detect":0,"face_enroll":0,"face_recognize":0,"cam_name":"General","code_ver":"Mar 6 2021 @ 17:54:00","rotate":"0","stream_url":"http://10.0.0.190:81/"}```
``` {"lamp":0,"autolamp":0,"min_frame_time":0,"framesize":9,"quality":10,"xclk":8,"brightness":0,"contrast":0,"saturation":0,"sharpness":0,"special_effect":0,"wb_mode":0,"awb":1,"awb_gain":1,"aec":1,"aec2":0,"ae_level":0,"aec_value":204,"agc":1,"agc_gain":0,"gainceiling":0,"bpc":0,"wpc":1,"raw_gma":1,"lenc":1,"vflip":1,"hmirror":1,"dcw":1,"colorbar":0,"cam_name":"ESP32 test camera","code_ver":"Mar 10 2022 @ 14:00:45","rotate":"0","stream_url":"http://10.0.0.181:81/"}```
* Reboot the camera
* `http://<IP-ADDRESS>/control?var=reboot&val=0`

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Pull requests are the best way to propose changes to the codebase (I use [Github
1. Fork the repo and create your branch from `master`.
2. Give your branch a clear descriptive name and do your changes there.
3. If you've changed the HTTP APIs, update the documentation.
4. Issue a pull request against a branch *of the same name* in the main repo.
4. Issue a pull request against the master branch in the main repo.
5. Clearly describe your changes and the reason for them in the pull request.

## Any contributions you make will be under the GNU Lesser General Public License v2.1
Expand Down
23 changes: 11 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,21 @@ https://wiki.ai-thinker.com/esp32-cam

## Troubleshooting:

Please read this excellent guide for help with some common issues seen with the camera modules:
A lot of common issues with this sketch are discussed and covered in the discussion forums:

https://github.com/easytarget/esp32-cam-webserver/discussions/categories/common-issues

The existing [issues list](https://github.com/easytarget/esp32-cam-webserver/issues?q=is%3Aissue) on Github is a good place to start if you have a specific issue not covered above or in the forums.

There is also this excellent guide for help with some common issues seen with the camera modules:
https://randomnerdtutorials.com/esp32-cam-troubleshooting-guide/

### Known Issues

The ESP itself is susceptible to the usual list of WiFi problems, not helped by having small antennas, older designs, congested airwaves and demanding users. The majority of disconnects, stutters and other comms problems are simply due to 'WiFi issues'. The AI-THINKER camera module & esp32 combination is quite susceptible to power supply problems affecting both WiFi conctivity and Video quality; short cabling and decent power supplies are your friend here; also well cooled cases and, if you have the time, decoupling capacitors on the power lines.
The ESP32 itself is susceptible to the usual list of WiFi problems, not helped by having small antennas, older designs, congested airwaves and demanding users. The majority of disconnects, stutters and other comms problems are simply due to 'WiFi issues'. The AI-THINKER camera module & esp32 combination is quite susceptible to power supply problems affecting both WiFi conctivity and Video quality; short cabling and decent power supplies are your friend here; also well cooled cases and, if you have the time, decoupling capacitors on the power lines.

A basic limitation of the sketch is that it can can only support one stream at a time. If you try to connect to a cam that is already streaming (or attempting to stream) you will get no response and, eventually, a timeout. The stream itself is a [MJPEG stream](https://en.wikipedia.org/wiki/Motion_JPEG), which relies on the client (the web browser) to hold the connection open and request each new frame in turn via javascript. This can cause errors when browsers run into Javascript or caching problem, fail to request new frames or refuse to close the connection.
* You can check the `/dump` page of the cam to see if it currently reports the camera as streaming or not.

The existing [issues list](https://github.com/easytarget/esp32-cam-webserver/issues?q=is%3Aissue) on Github is a good place to start if you have a specific issue not covered above.
* If you cannot start the stream you can check the `/dump` page of the cam to see if it currently reports the camera as streaming or not.

Note that I do not respond to any Private Messages (via github, hackaday, or wherever) for support.

Expand All @@ -74,7 +78,7 @@ Is pretty simple, You just need jumper wires, no soldering really required, see
Download the latest release of the sketch from https://github.com/easytarget/esp32-cam-webserver/releases/latest
- You can get the latest stable development release by cloning / downloading the `master` branch of the repo.

This will give you an archive file with the Version number in it, eg.`esp32-cam-webserver-3.0.zip`. Tou need to unpack this into your Arduino sketch folder, and then you need to rename the folder you just extracted to remove the version number, eg.`esp32-cam-webserver-3.0` becomes `esp32-cam-webserver`.
This will give you an archive file with the Version number in it, eg.`esp32-cam-webserver-4.0.zip`. You need to unpack this into your Arduino sketch folder, and then you need to **rename the folder you extracted to remove the version number**, eg.`esp32-cam-webserver-4.0` becomes `esp32-cam-webserver`.

Once you have done that you can open the sketch in the IDE by going to the `esp32-cam-webserver` sketch folder and selecting `esp32-cam-webserver.ino`.

Expand Down Expand Up @@ -142,14 +146,9 @@ Contributions are welcome; please see the [Contribution guidelines](CONTRIBUTING
Time allowing; my Current plan is:

V4
* Remove face recognition entirely;
* **Done**, see the `NoFace` branch :sunglasses:
* Not optional, this is a code and maintenance nightmare. V3 can be maintained on a branch for those who need it.
* Investigate using SD card to capture images
* Implement OTA and a better network stack for remembering multiple AP's, auto-config etc.
* **Basic OTA is Done**, see the `NoFace` branch.
* Implement a better network stack for remembering multiple AP's, auto-config etc.
* Advanced (web upload) OTA might be nice to have if possible
* For the Network setup I want to implement https://github.com/Hieromon/AutoConnect
* UI Skinning/Theming
* OSD
* Temperature/humidity/pressure sensor support (bme20,dht11)
Expand Down
68 changes: 51 additions & 17 deletions app_httpd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ extern int8_t streamCount;
extern unsigned long streamsServed;
extern unsigned long imagesServed;
extern int myRotation;
extern int minFrameTime;
extern int lampVal;
extern bool autoLamp;
extern bool filesystem;
Expand All @@ -63,7 +64,7 @@ extern int sketchSpace;
extern String sketchMD5;
extern bool otaEnabled;
extern char otaPassword[];
extern unsigned long xclkFreqHz;
extern unsigned long xclk;

typedef struct {
httpd_req_t *req;
Expand All @@ -78,6 +79,9 @@ static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %
httpd_handle_t stream_httpd = NULL;
httpd_handle_t camera_httpd = NULL;

// Flag that can be set to kill all active streams
bool streamKill;

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -141,10 +145,9 @@ void serialDump() {
int upSec = sec % 60;
int McuTc = (temprature_sens_read() - 32) / 1.8; // celsius
int McuTf = temprature_sens_read(); // fahrenheit
float xclk = xclkFreqHz/1000000;
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);
Serial.printf("CPU Freq: %i MHz, Xclk Freq: %.1f MHz\r\n", ESP.getCpuFreqMHz(), xclk);
Serial.printf("CPU Freq: %i MHz, Xclk Freq: %i MHz\r\n", ESP.getCpuFreqMHz(), xclk);
Serial.printf("MCU temperature : %i C, %i F (approximate)\r\n", McuTc, McuTf);
Serial.printf("Heap: %i, free: %i, min free: %i, max block: %i\r\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap());
if(psramFound()) {
Expand Down Expand Up @@ -223,6 +226,8 @@ static esp_err_t stream_handler(httpd_req_t *req){
uint8_t * _jpg_buf = NULL;
char * part_buf[64];

streamKill = false;

Serial.println("Stream requested");
if (autoLamp && (lampVal != -1)) setLamp(lampVal);
streamCount = 1; // at present we only have one stream handler, so values are 0 or 1..
Expand All @@ -245,6 +250,10 @@ static esp_err_t stream_handler(httpd_req_t *req){

httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");

if(res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}

while(true){
fb = esp_camera_fb_get();
if (!fb) {
Expand All @@ -259,16 +268,16 @@ static esp_err_t stream_handler(httpd_req_t *req){
_jpg_buf = fb->buf;
}
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
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);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if(fb){
esp_camera_fb_return(fb);
fb = NULL;
Expand All @@ -277,19 +286,22 @@ static esp_err_t stream_handler(httpd_req_t *req){
free(_jpg_buf);
_jpg_buf = NULL;
}
if(res != ESP_OK){
if((res != ESP_OK) || streamKill){
// 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.
break;
}
int64_t frame_time = esp_timer_get_time() - last_frame;
last_frame = esp_timer_get_time();;
frame_time /= 1000;
int32_t frame_delay = (minFrameTime > frame_time) ? minFrameTime - frame_time : 0;
delay(frame_delay);

if (debugData) {
Serial.printf("MJPG: %uB %ums (%.1ffps)\r\n",
Serial.printf("MJPG: %uB %ums, delay: %ums, framerate (%.1ffps)\r\n",
(uint32_t)(_jpg_buf_len),
(uint32_t)frame_time, 1000.0 / (uint32_t)frame_time);
(uint32_t)frame_time, frame_delay, 1000.0 / (uint32_t)(frame_time + frame_delay));
}
last_frame = esp_timer_get_time();
}

streamsServed++;
Expand Down Expand Up @@ -341,6 +353,7 @@ static esp_err_t cmd_handler(httpd_req_t *req){
if(s->pixformat == PIXFORMAT_JPEG) res = s->set_framesize(s, (framesize_t)val);
}
else if(!strcmp(variable, "quality")) res = s->set_quality(s, val);
else if(!strcmp(variable, "xclk")) { xclk = val; res = s->set_xclk(s, LEDC_TIMER_0, val); }
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);
Expand All @@ -364,6 +377,7 @@ static esp_err_t cmd_handler(httpd_req_t *req){
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);
else if(!strcmp(variable, "rotate")) myRotation = val;
else if(!strcmp(variable, "min_frame_time")) minFrameTime = val;
else if(!strcmp(variable, "autolamp") && (lampVal != -1)) {
autoLamp = val;
if (autoLamp) {
Expand All @@ -389,6 +403,7 @@ static esp_err_t cmd_handler(httpd_req_t *req){
if (filesystem) removePrefs(SPIFFS);
}
else if(!strcmp(variable, "reboot")) {
if (lampVal != -1) setLamp(0); // kill the lamp; otherwise it can remain on during the soft-reboot
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
Expand Down Expand Up @@ -419,8 +434,10 @@ static esp_err_t status_handler(httpd_req_t *req){
*p++ = '{';
p+=sprintf(p, "\"lamp\":%d,", lampVal);
p+=sprintf(p, "\"autolamp\":%d,", autoLamp);
p+=sprintf(p, "\"min_frame_time\":%d,", minFrameTime);
p+=sprintf(p, "\"framesize\":%u,", s->status.framesize);
p+=sprintf(p, "\"quality\":%u,", s->status.quality);
p+=sprintf(p, "\"xclk\":%u,", xclk);
p+=sprintf(p, "\"brightness\":%d,", s->status.brightness);
p+=sprintf(p, "\"contrast\":%d,", s->status.contrast);
p+=sprintf(p, "\"saturation\":%d,", s->status.saturation);
Expand Down Expand Up @@ -495,7 +512,7 @@ static esp_err_t logo_svg_handler(httpd_req_t *req){

static esp_err_t dump_handler(httpd_req_t *req){
flashLED(75);
Serial.println("\r\nDump Requested via Web");
Serial.println("\r\nDump requested via Web");
serialDump();
static char dumpOut[2000] = "";
char * d = dumpOut;
Expand All @@ -508,7 +525,7 @@ static esp_err_t dump_handler(httpd_req_t *req){
d+= sprintf(d,"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">\n");
d+= sprintf(d,"</head>\n");
d+= sprintf(d,"<body>\n");
d+= sprintf(d,"<img src=\"/logo.svg\" style=\"position: relative; float: right;\">\n");
d+= sprintf(d,"<img src=\"/logo.svg\" style=\"position: relative; float: right;\">\n");
if (critERR.length() > 0) {
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");
Expand Down Expand Up @@ -566,11 +583,10 @@ static esp_err_t dump_handler(httpd_req_t *req){
int upSec = sec % 60;
int McuTc = (temprature_sens_read() - 32) / 1.8; // celsius
int McuTf = temprature_sens_read(); // fahrenheit
float xclk = xclkFreqHz/1000000;

d+= sprintf(d,"Up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)<br>\n", upDays, upHours, upMin, upSec);
d+= sprintf(d,"Active streams: %i, Previous streams: %lu, Images captured: %lu<br>\n", streamCount, streamsServed, imagesServed);
d+= sprintf(d,"CPU Freq: %i MHz, Xclk Freq: %.1f MHz<br>\n", ESP.getCpuFreqMHz(), xclk);
d+= sprintf(d,"CPU Freq: %i MHz, Xclk Freq: %i MHz<br>\n", ESP.getCpuFreqMHz(), xclk);
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 &deg;C, %i &deg;F</span>\n<br>", McuTc, McuTf);
d+= sprintf(d,"Heap: %i, free: %i, min free: %i, max block: %i<br>\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap());
Expand All @@ -590,6 +606,8 @@ static esp_err_t dump_handler(httpd_req_t *req){
// Footer
d+= sprintf(d,"<br><div class=\"input-group\">\n");
d+= sprintf(d,"<button title=\"Instant Refresh; the page reloads every minute anyway\" onclick=\"location.replace(document.URL)\">Refresh</button>\n");
d+= sprintf(d,"<button title=\"Force-stop all active streams on the camera module\" ");
d+= sprintf(d,"onclick=\"let throwaway = fetch('stop');setTimeout(function(){\nlocation.replace(document.URL);\n}, 200);\">Kill Stream</button>\n");
d+= sprintf(d,"<button title=\"Close this page\" onclick=\"javascript:window.close()\">Close</button>\n");
d+= sprintf(d,"</div>\n</body>\n");
// A javascript timer to refresh the page every minute.
Expand All @@ -601,6 +619,15 @@ static esp_err_t dump_handler(httpd_req_t *req){
return httpd_resp_send(req, dumpOut, strlen(dumpOut));
}

static esp_err_t stop_handler(httpd_req_t *req){
flashLED(75);
Serial.println("\r\nStream stop requested via Web");
streamKill = true;
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}


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");
Expand All @@ -609,15 +636,15 @@ static esp_err_t style_handler(httpd_req_t *req){

static esp_err_t streamviewer_handler(httpd_req_t *req){
flashLED(75);
Serial.println("Stream Viewer requested");
Serial.println("Stream viewer requested");
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);
}

static esp_err_t error_handler(httpd_req_t *req){
flashLED(75);
Serial.println("Sending Error page");
Serial.println("Sending error page");
std::string s(error_html);
size_t index;
while ((index = s.find("<APPURL>")) != std::string::npos)
Expand Down Expand Up @@ -705,7 +732,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 = 12; // we use more than the default 8 (on port 80)
config.max_uri_handlers = 16; // we use more than the default 8 (on port 80)

httpd_uri_t index_uri = {
.uri = "/",
Expand Down Expand Up @@ -767,6 +794,12 @@ void startCameraServer(int hPort, int sPort){
.handler = dump_handler,
.user_ctx = NULL
};
httpd_uri_t stop_uri = {
.uri = "/stop",
.method = HTTP_GET,
.handler = stop_handler,
.user_ctx = NULL
};
httpd_uri_t stream_uri = {
.uri = "/",
.method = HTTP_GET,
Expand Down Expand Up @@ -817,6 +850,7 @@ void startCameraServer(int hPort, int sPort){
httpd_register_uri_handler(camera_httpd, &favicon_ico_uri);
httpd_register_uri_handler(camera_httpd, &logo_svg_uri);
httpd_register_uri_handler(camera_httpd, &dump_uri);
httpd_register_uri_handler(camera_httpd, &stop_uri);
}

config.server_port = sPort;
Expand Down
10 changes: 5 additions & 5 deletions camera_pins.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*
/*
* Pin definitions for some common ESP-CAM modules
*
*
* Select the module to use in myconfig.h
* Defaults to AI-THINKER CAM module
*
*
*/
#if defined(CAMERA_MODEL_AI_THINKER)
//
Expand Down Expand Up @@ -33,7 +33,7 @@

#elif defined(CAMERA_MODEL_WROVER_KIT)
//
// ESP WROVER
// ESP WROVER
// https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_SCH-2.pdf
//
#define PWDN_GPIO_NUM -1
Expand Down Expand Up @@ -189,7 +189,7 @@

#elif defined(CAMERA_MODEL_TTGO_T_JOURNAL)
//
// LilyGO TTGO T-Journal ESP32; with OLED! but not used here.. :-(
// LilyGO TTGO T-Journal ESP32; with OLED! but not used here.. :-(
#define PWDN_GPIO_NUM 0
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
Expand Down
2 changes: 1 addition & 1 deletion css.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Master CSS file for the camera pages
*/

const uint8_t style_css[] = R"=====(/*
const uint8_t style_css[] = R"=====(/*
* CSS for the esp32 cam webserver
*/

Expand Down
Loading