forked from external-repos/esp32cam-rtsp
- Moved html from SPIFF to code
- Added script to process html - Added WRover and MStack camera's - Automatic detection PSRAM - Added setting for # frame buffers - Feedback of camera initialization value - Added connected feedback
This commit is contained in:
23
README.md
23
README.md
@@ -3,7 +3,7 @@
|
||||

|
||||
|
||||
Simple [RTSP](https://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol) server.
|
||||
Easy configuration through the web interface. Stable.
|
||||
Easy configuration through the web interface.
|
||||
|
||||
Flashing this software on a esp32cam module will make it a **RTSP streaming camera** server.
|
||||
This allows CCTV systems and applications like **VLC** to connect directly to the ESP32CAM camera stream.
|
||||
@@ -24,6 +24,7 @@ This software provides a **configuration web server**, that can be used to:
|
||||
- Select the board type,
|
||||
- Select the image size,
|
||||
- Select the frame rate,
|
||||
- Select number of frame buffers
|
||||
- Select the JPEG quality
|
||||
|
||||
The software provides contains also a mDNS server to be easily discoverable on the local network.
|
||||
@@ -80,17 +81,15 @@ There are to flavours to do this; using the command line or the graphical interf
|
||||
|
||||
### Using the command line
|
||||
|
||||
First the source code and SPIFF partition (data) has to be compiled. Type:
|
||||
First the source code has to be compiled. Type:
|
||||
```
|
||||
pio run
|
||||
pio run buildfs
|
||||
```
|
||||
|
||||
When finished, the SPIFF partition and software have to be uploaded.
|
||||
When finished, firmware has to be uploaded.
|
||||
Make sure the ESP32-CAM is in download mode (see previous section) and type:
|
||||
```
|
||||
pio run -t upload
|
||||
pio run -t uploadfs
|
||||
```
|
||||
|
||||
When done remove the jumper when using a FTDI adapter or press the reset button on the ESP32-CAM.
|
||||
@@ -101,11 +100,9 @@ To monitor the output, start a terminal using:
|
||||
|
||||
### Using Visual studio
|
||||
|
||||
Open the project in a new window. Run the following tasks using the ```Terminal -> Run Task``` or CTRL+ALT+T command in the menu. Make sure the ESP32-CAM is in download mode during the uploads.
|
||||
Open the project in a new window. Run the following tasks using the ```Terminal -> Run Task``` or CTRL+ALT+T command in the menu (or use the icons below on the toolbar). Make sure the ESP32-CAM is in download mode during the uploads.
|
||||
|
||||
- PlatformIO: Build Filesystem Image (esp32cam)
|
||||
- PlatformIO: Build (esp32cam)
|
||||
- PlatformIO: Upload Filesystem Image (esp32cam)
|
||||
- PlatformIO: Upload (esp32cam)
|
||||
|
||||
To monitor the behavior run the task, run:
|
||||
@@ -113,7 +110,7 @@ To monitor the behavior run the task, run:
|
||||
|
||||
## Setting up the ESP32CAM-RTSP
|
||||
After the programming of the ESP32, there is no configuration present. This needs to be added.
|
||||
To connect initially to the device open the WiFi connections and select the WiFi network / accesspoint called **ESP32CAM-RTSP**.
|
||||
To connect initially to the device open the WiFi connections and select the WiFi network / access point called **ESP32CAM-RTSP**.
|
||||
Initially there is no password present.
|
||||
|
||||
After connecting, the browser should automatically open the status page.
|
||||
@@ -151,6 +148,14 @@ This link can be opened with for example [VLC](https://www.videolan.org/vlc/).
|
||||
|
||||
:warning: **Please be aware that there is no password present on the stream!**
|
||||
|
||||
## Issues observed
|
||||
|
||||
### Power
|
||||
Make sure the power is 5 volts and stable.
|
||||
|
||||
### PSRAM
|
||||
Some esp32cam modules have additional ram on the board. This allows to use this ram as frame buffer.
|
||||
|
||||
## Credits
|
||||
esp32cam-ready depends on PlatformIO, Bootstap5 and Micro-RTSP by Kevin Hester.
|
||||
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="stylesheet" href="bootstrap.min.css">
|
||||
<title>{{AppTitle}} v{{AppVersion}}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>{{ThingName}}</h1>
|
||||
<hr>
|
||||
|
||||
{{#ConfigChanged}}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<p>The configuration has been changed. It is recommended to restart the device</p>
|
||||
<p>This can be done by pressing the restart button below</p>
|
||||
<button type="button" class="btn btn-danger" onclick="location.href='restart'">Restart</button>
|
||||
</div>
|
||||
{{/ConfigChanged}}
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">ESP32</h5>
|
||||
<div class="card-body">
|
||||
<p>CPU model: {{ChipModel}}</p>
|
||||
<p>CPU speed: {{CpuFreqMHz}}Mhz</p>
|
||||
<p>Mac address: {{MacAddress}}</p>
|
||||
<p>IPv4 address: {{IpV4}}</p>
|
||||
<p>IPv6 address: {{IpV6}}</p>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">Settings</h5>
|
||||
<div class="card-body">
|
||||
<p>Camera type: {{CameraType}}</p>
|
||||
<p>Frame size: {{FrameSize}}</p>
|
||||
<p>Frame rate: {{FrameDuration}} ms ({{FrameFrequency}} f/s)</p>
|
||||
<p>JPEG quality: {{JpegQuality}} (0-100)</p>
|
||||
{{#CameraInitialized}}
|
||||
<div class="alert alert-success" role="alert">
|
||||
Camera was initialized successfully!
|
||||
</div>
|
||||
{{/CameraInitialized}}
|
||||
{{^CameraInitialized}}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
Failed to initialize the camera! No streaming possible. Please change the camera settings and
|
||||
restart
|
||||
</div>
|
||||
{{/CameraInitialized}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">Diagnostics</h5>
|
||||
<div class="card-body">
|
||||
<p>Uptime: {{Uptime}}</p>
|
||||
<p>Free heap: {{FreeHeap}}b</p>
|
||||
<p>Max free block: {{MaxAllocHeap}}b</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">Camera stream</h5>
|
||||
<div class="card-body">
|
||||
The camera stream can be found at the following location:
|
||||
<a
|
||||
href="rtsp://{{ThingName}}.local:{{RtspPort}}/mjpeg/1">rtsp://{{ThingName}}.local:{{RtspPort}}/mjpeg/1</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-lg btn-warning" onclick="location.href='config'">Change
|
||||
configuration</button>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
4
generate_html.ps1
Normal file
4
generate_html.ps1
Normal file
@@ -0,0 +1,4 @@
|
||||
. python3 -m pip install --upgrade pip setuptools wheel
|
||||
. python3 -m pip install htmlmin
|
||||
|
||||
. python3 ./html_to_cpp.py ./html ./include/html_data.h
|
||||
5
generate_html.sh
Executable file
5
generate_html.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
python3 -m pip install --upgrade pip setuptools wheel
|
||||
python3 -m pip install htmlmin
|
||||
|
||||
python3 ./html_to_cpp.py ./html ./include/html_data.h
|
||||
112
html/index.html
Normal file
112
html/index.html
Normal file
@@ -0,0 +1,112 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="stylesheet" href="bootstrap.min.css">
|
||||
<title>{{AppTitle}} v{{AppVersion}}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>{{ThingName}}</h1>
|
||||
<hr>
|
||||
|
||||
{{#ConfigChanged}}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<p>The configuration has been changed.</p>
|
||||
<p>It is recommended to restart the device.</p>
|
||||
<button type="button" class="btn btn-danger" onclick="location.href='restart'">Restart</button>
|
||||
</div>
|
||||
{{/ConfigChanged}}
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">ESP32</h5>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>CPU model: {{ChipModel}}</li>
|
||||
<li>CPU speed: {{CpuFreqMHz}}Mhz</li>
|
||||
<li>Mac address: {{MacAddress}}</li>
|
||||
<li>IPv4 address: {{IpV4}}</li>
|
||||
<li>IPv6 address: {{IpV6}}</li>
|
||||
</ul>
|
||||
{{#NetworkState.ApMode}}
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<p>Not connected to an access point. Please configure!</p>
|
||||
</div>
|
||||
{{/NetworkState.ApMode}}
|
||||
{{#NetworkState.OnLine}}
|
||||
<div class="alert alert-success" role="alert">
|
||||
<p>Connected to the access point</p>
|
||||
</div>
|
||||
{{/NetworkState.OnLine}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">Settings</h5>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Camera type: {{CameraType}}</li>
|
||||
<li>Frame rate: {{FrameDuration}} ms ({{FrameFrequency}} f/s)</li>
|
||||
<li>Frame size: {{FrameSize}}</li>
|
||||
<li>Frame buffer location: {{FrameBufferLocation}}</li>
|
||||
<li>Frame buffers: {{FrameBuffers}}</li>
|
||||
<li>
|
||||
<div class="d-flex justify-content-start">
|
||||
JPEG quality:
|
||||
</div>
|
||||
<div class="d-flex justify-content-end">
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar" style="width: 25%;"
|
||||
aria-valuenow="{{JpegQuality}}" aria-valuemin="0" aria-valuemax="100">
|
||||
{{JpegQuality}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
{{#CameraInitialized}}
|
||||
<div class="alert alert-success" role="alert">
|
||||
<p>Camera was initialized successfully!</p>
|
||||
</div>
|
||||
{{/CameraInitialized}}
|
||||
{{^CameraInitialized}}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<p>Failed to initialize the camera!</p>
|
||||
<p>Result: {{CameraInitResultText}} ({{CameraInitResult}})</p>
|
||||
<p>Please check hardware or correct the camera settings and restart.</p>
|
||||
</div>
|
||||
{{/CameraInitialized}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">Diagnostics</h5>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Uptime: {{Uptime}}</li>
|
||||
<li>Free heap: {{FreeHeap}}b</li>
|
||||
<li>Max free block: {{MaxAllocHeap}}b</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">Camera stream</h5>
|
||||
<div class="card-body">
|
||||
</p>The camera stream can be found at the following location:</p>
|
||||
<a
|
||||
href="rtsp://{{ThingName}}.local:{{RtspPort}}/mjpeg/1">rtsp://{{ThingName}}.local:{{RtspPort}}/mjpeg/1</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-warning" onclick="location.href='config'">Settings</button>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -5,6 +5,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="stylesheet" href="bootstrap.min.css">
|
||||
<meta http-equiv="refresh" content="10;url=/">
|
||||
<title>{{AppTitle}} v{{AppVersion}}</title>
|
||||
</head>
|
||||
|
||||
@@ -14,7 +15,7 @@
|
||||
<hr>
|
||||
<div class="jumbotron bg-light">
|
||||
<h1 class="display-4">Restart</h1>
|
||||
<p class="lead">The device is currently restarting. Please stand by...</p>
|
||||
<p class="lead">The device is restarting.</p>
|
||||
<hr class="my-4">
|
||||
<p>In some cases, the device requires a hard reset (power cycle).</p>
|
||||
<div class="d-flex justify-content-center">
|
||||
46
html_to_cpp.py
Normal file
46
html_to_cpp.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# pip install Pillow
|
||||
|
||||
import os
|
||||
import sys
|
||||
import htmlmin
|
||||
|
||||
if (len(sys.argv) <= 2):
|
||||
print('Usage: html_to_cpp.py <input_dir> <file.h>')
|
||||
sys.exit(1)
|
||||
|
||||
input_dir = sys.argv[1]
|
||||
file_h = sys.argv[2]
|
||||
|
||||
file_names = os.listdir(input_dir)
|
||||
file_names = filter(lambda x: x[0] != '.' and os.path.isfile(os.path.join(input_dir, x)), file_names)
|
||||
file_names = sorted(file_names)
|
||||
|
||||
output_file = open(file_h, 'w')
|
||||
output_file.write('//*******************************************************************************\n')
|
||||
output_file.write('// HTML import\n')
|
||||
output_file.write('// Machine generated file\n')
|
||||
output_file.write('// ******************************************************************************\n')
|
||||
output_file.write('\n')
|
||||
|
||||
for file_name in file_names:
|
||||
print(f'Processing: {file_name}... ')
|
||||
|
||||
file_path = os.path.join(input_dir, file_name)
|
||||
file_data_name = f'file_data_{file_name}'.replace('.', '_')
|
||||
|
||||
file = open(file_path, 'r')
|
||||
html = file.read()
|
||||
file.close()
|
||||
|
||||
html_mimified = htmlmin.minify(html, remove_empty_space=True)
|
||||
|
||||
output_file.write('\n')
|
||||
output_file.write('constexpr char ' + file_data_name + '[] = "')
|
||||
# escape "
|
||||
html_mimified_escaped = html_mimified.replace('"', '\\"')
|
||||
output_file.write(html_mimified_escaped)
|
||||
output_file.write('";\n')
|
||||
|
||||
output_file.close()
|
||||
|
||||
print('Done.')
|
||||
@@ -86,11 +86,63 @@ constexpr camera_config_t esp32cam_ttgo_t_settings = {
|
||||
.jpeg_quality = 12,
|
||||
.fb_count = 2};
|
||||
|
||||
constexpr camera_config_t esp32cam_m5stack_settings = {
|
||||
.pin_pwdn = -1,
|
||||
.pin_reset = 15,
|
||||
.pin_xclk = 27,
|
||||
.pin_sscb_sda = 25,
|
||||
.pin_sscb_scl = 23,
|
||||
.pin_d7 = 19,
|
||||
.pin_d6 = 36,
|
||||
.pin_d5 = 18,
|
||||
.pin_d4 = 39,
|
||||
.pin_d3 = 5,
|
||||
.pin_d2 = 34,
|
||||
.pin_d1 = 35,
|
||||
.pin_d0 = 32,
|
||||
.pin_vsync = 22,
|
||||
.pin_href = 26,
|
||||
.pin_pclk = 21,
|
||||
.xclk_freq_hz = 20000000,
|
||||
.ledc_timer = LEDC_TIMER_0,
|
||||
.ledc_channel = LEDC_CHANNEL_0,
|
||||
.pixel_format = PIXFORMAT_JPEG,
|
||||
.frame_size = FRAMESIZE_SVGA,
|
||||
.jpeg_quality = 12,
|
||||
.fb_count = 2};
|
||||
|
||||
constexpr camera_config_t esp32cam_wrover_kit_settings = {
|
||||
.pin_pwdn = -1,
|
||||
.pin_reset = -1,
|
||||
.pin_xclk = 21,
|
||||
.pin_sscb_sda = 26,
|
||||
.pin_sscb_scl = 27,
|
||||
.pin_d7 = 35,
|
||||
.pin_d6 = 34,
|
||||
.pin_d5 = 39,
|
||||
.pin_d4 = 36,
|
||||
.pin_d3 = 19,
|
||||
.pin_d2 = 18,
|
||||
.pin_d1 = 5,
|
||||
.pin_d0 = 4,
|
||||
.pin_vsync = 25,
|
||||
.pin_href = 23,
|
||||
.pin_pclk = 22,
|
||||
.xclk_freq_hz = 20000000,
|
||||
.ledc_timer = LEDC_TIMER_0,
|
||||
.ledc_channel = LEDC_CHANNEL_0,
|
||||
.pixel_format = PIXFORMAT_JPEG,
|
||||
.frame_size = FRAMESIZE_SVGA,
|
||||
.jpeg_quality = 12,
|
||||
.fb_count = 2};
|
||||
|
||||
constexpr const camera_config_entry_t camera_configs[] = {
|
||||
|
||||
{"ESP32CAM", esp32cam_settings},
|
||||
{"AI THINKER", esp32cam_aithinker_settings},
|
||||
{"TTGO T-CAM", esp32cam_ttgo_t_settings}};
|
||||
{"TTGO T-CAM", esp32cam_ttgo_t_settings},
|
||||
{"M5 STACK", esp32cam_m5stack_settings},
|
||||
{"WROVER KIT", esp32cam_wrover_kit_settings}};
|
||||
|
||||
const camera_config_t lookup_camera_config(const char *pin)
|
||||
{
|
||||
|
||||
11
include/html_data.h
Normal file
11
include/html_data.h
Normal file
File diff suppressed because one or more lines are too long
@@ -9,6 +9,7 @@
|
||||
|
||||
#define RTSP_PORT 554
|
||||
#define DEFAULT_CAMERA_CONFIG "AI THINKER"
|
||||
#define DEFAULT_FRAMEDURATION "20"
|
||||
#define DEFAULT_FRAMESIZE "SVGA (800x600)"
|
||||
#define DEFAULT_FRAME_DURATION "20"
|
||||
#define DEFAULT_FRAME_BUFFERS "2"
|
||||
#define DEFAULT_FRAME_SIZE "SVGA (800x600)"
|
||||
#define DEFAULT_JPEG_QUALITY "12"
|
||||
57
src/main.cpp
57
src/main.cpp
@@ -9,19 +9,21 @@
|
||||
#include <camera_config.h>
|
||||
#include <format_duration.h>
|
||||
#include <format_si.h>
|
||||
#include <SPIFFS.h>
|
||||
#include <template_render.h>
|
||||
#include <html_data.h>
|
||||
#include <settings.h>
|
||||
|
||||
char camera_config_val[sizeof(camera_config_entry)];
|
||||
char frame_duration_val[6];
|
||||
char frame_size_val[sizeof(frame_size_entry_t)];
|
||||
char frame_buffers_val[3];
|
||||
char jpeg_quality_val[4];
|
||||
|
||||
auto config_group_stream_settings = iotwebconf::ParameterGroup("settings", "Streaming settings");
|
||||
auto config_camera_config = iotwebconf::SelectParameter("Camera config", "config", camera_config_val, sizeof(camera_config_val), (const char *)camera_configs, (const char *)camera_configs, sizeof(camera_configs) / sizeof(camera_configs[0]), sizeof(camera_configs[0]), DEFAULT_CAMERA_CONFIG);
|
||||
auto config_frame_rate = iotwebconf::NumberParameter("Frame duration (ms)", "fd", frame_duration_val, sizeof(frame_duration_val), DEFAULT_FRAMEDURATION, nullptr, "min=\"10\"");
|
||||
auto config_frame_size = iotwebconf::SelectParameter("Frame size", "fs", frame_size_val, sizeof(frame_size_val), (const char *)frame_sizes, (const char *)frame_sizes, sizeof(frame_sizes) / sizeof(frame_sizes[0]), sizeof(frame_sizes[0]), DEFAULT_FRAMESIZE);
|
||||
auto config_frame_rate = iotwebconf::NumberParameter("Frame duration (ms)", "fd", frame_duration_val, sizeof(frame_duration_val), DEFAULT_FRAME_DURATION, nullptr, "min=\"10\"");
|
||||
auto config_frame_size = iotwebconf::SelectParameter("Frame size", "fs", frame_size_val, sizeof(frame_size_val), (const char *)frame_sizes, (const char *)frame_sizes, sizeof(frame_sizes) / sizeof(frame_sizes[0]), sizeof(frame_sizes[0]), DEFAULT_FRAME_SIZE);
|
||||
auto config_frame_buffers = iotwebconf::NumberParameter("Frame buffers", "fb", frame_buffers_val, sizeof(frame_buffers_val), DEFAULT_FRAME_BUFFERS, nullptr, "min=\"1\" max=\"16\"");
|
||||
auto config_jpg_quality = iotwebconf::NumberParameter("JPEG quality", "q", jpeg_quality_val, sizeof(jpeg_quality_val), DEFAULT_JPEG_QUALITY, nullptr, "min=\"1\" max=\"100\"");
|
||||
|
||||
// Camera
|
||||
@@ -36,16 +38,14 @@ IotWebConf iotWebConf(WIFI_SSID, &dnsServer, &web_server, WIFI_PASSWORD, CONFIG_
|
||||
|
||||
// Keep track of config changes. This will allow a reset of the device
|
||||
bool config_changed = false;
|
||||
// Check if camera is initialized
|
||||
bool camera_initialized = false;
|
||||
// Camera initialization result
|
||||
esp_err_t camera_init_result;
|
||||
|
||||
void stream_file(const char *spiffs_file, const char *mime_type)
|
||||
void stream_text_file(const char *contents, const char *mime_type)
|
||||
{
|
||||
// Cache for 86400 seconds (one day)
|
||||
web_server.sendHeader("Cache-Control", "max-age=86400");
|
||||
auto file = SPIFFS.open(spiffs_file);
|
||||
web_server.streamFile(file, mime_type);
|
||||
file.close();
|
||||
web_server.send(200, mime_type, contents);
|
||||
}
|
||||
|
||||
void handle_root()
|
||||
@@ -68,18 +68,22 @@ void handle_root()
|
||||
{"FrameSize", frame_size_val},
|
||||
{"FrameDuration", frame_duration_val},
|
||||
{"FrameFrequency", String(1000.0 / atol(frame_duration_val), 1)},
|
||||
{"FrameBufferLocation", psramFound() ? "PSRAM" : "DRAM)"},
|
||||
{"FrameBuffers", frame_buffers_val},
|
||||
{"JpegQuality", jpeg_quality_val},
|
||||
{"Uptime", String(format_duration(millis() / 1000))},
|
||||
{"FreeHeap", format_si(ESP.getFreeHeap())},
|
||||
{"MaxAllocHeap", format_si(ESP.getMaxAllocHeap())},
|
||||
{"RtspPort", String(RTSP_PORT)},
|
||||
{"ConfigChanged", String(config_changed)},
|
||||
{"CameraInitialized", String(camera_initialized)}};
|
||||
{"NetworkState.ApMode", String(iotWebConf.getState() == iotwebconf::NetworkState::ApMode)},
|
||||
{"NetworkState.OnLine", String(iotWebConf.getState() == iotwebconf::NetworkState::OnLine)},
|
||||
{"CameraInitialized", String(camera_init_result == ESP_OK)},
|
||||
{"CameraInitResult", "0x" + String(camera_init_result, 16)},
|
||||
{"CameraInitResultText", esp_err_to_name(camera_init_result)}};
|
||||
|
||||
web_server.sendHeader("Cache-Control", "no-cache");
|
||||
auto file = SPIFFS.open("/index.html");
|
||||
auto html = template_render(file.readString(), substitutions);
|
||||
file.close();
|
||||
auto html = template_render(file_data_index_html, substitutions);
|
||||
web_server.send(200, "text/html", html);
|
||||
}
|
||||
|
||||
@@ -100,12 +104,10 @@ void handle_restart()
|
||||
{"ThingName", iotWebConf.getThingName()}};
|
||||
|
||||
web_server.sendHeader("Cache-Control", "no-cache");
|
||||
auto file = SPIFFS.open("/restart.html");
|
||||
auto html = template_render(file.readString(), substitutions);
|
||||
file.close();
|
||||
auto html = template_render(file_data_restart_html, substitutions);
|
||||
web_server.send(200, "text/html", html);
|
||||
log_v("Restarting... Press refresh to connect again");
|
||||
sleep(1000);
|
||||
sleep(100);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
@@ -115,29 +117,34 @@ void on_config_saved()
|
||||
config_changed = true;
|
||||
}
|
||||
|
||||
bool initialize_camera()
|
||||
esp_err_t initialize_camera()
|
||||
{
|
||||
log_v("initialize_camera");
|
||||
log_i("Camera config: %s", camera_config_val);
|
||||
auto camera_config = lookup_camera_config(camera_config_val);
|
||||
log_i("Frame size: %s", frame_size_val);
|
||||
auto frame_size = lookup_frame_size(frame_size_val);
|
||||
log_i("Frame buffers: %s", frame_buffers_val);
|
||||
auto frame_buffers = atoi(frame_buffers_val);
|
||||
log_i("JPEG quality: %s", jpeg_quality_val);
|
||||
auto jpeg_quality = atoi(jpeg_quality_val);
|
||||
log_i("Frame rate: %s ms", frame_duration_val);
|
||||
|
||||
camera_config.frame_size = frame_size;
|
||||
camera_config.fb_count = frame_buffers;
|
||||
camera_config.fb_location = psramFound() ? CAMERA_FB_IN_PSRAM : CAMERA_FB_IN_DRAM;
|
||||
camera_config.jpeg_quality = jpeg_quality;
|
||||
return cam.init(camera_config) == ESP_OK;
|
||||
|
||||
return cam.init(camera_config);
|
||||
}
|
||||
|
||||
void start_rtsp_server()
|
||||
{
|
||||
log_v("start_rtsp_server");
|
||||
camera_initialized = initialize_camera();
|
||||
if (!camera_initialized)
|
||||
camera_init_result = initialize_camera();
|
||||
if (camera_init_result != ESP_OK)
|
||||
{
|
||||
log_e("Failed to initialize camera. Type: %s, frame size: %s, frame rate: %s ms, jpeg quality: %s", camera_config_val, frame_size_val, frame_duration_val, jpeg_quality_val);
|
||||
log_e("Failed to initialize camera: 0x%0xd. Type: %s, frame size: %s, frame buffers: %s, frame rate: %s ms, jpeg quality: %s", camera_init_result, camera_config_val, frame_size_val, frame_buffers_val, frame_duration_val, jpeg_quality_val);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -171,12 +178,10 @@ void setup()
|
||||
log_i("Free heap: %d bytes", ESP.getFreeHeap());
|
||||
log_i("Starting " APP_TITLE "...");
|
||||
|
||||
if (!SPIFFS.begin())
|
||||
log_e("Error while mounting SPIFFS. Please upload the filesystem");
|
||||
|
||||
config_group_stream_settings.addItem(&config_camera_config);
|
||||
config_group_stream_settings.addItem(&config_frame_rate);
|
||||
config_group_stream_settings.addItem(&config_frame_size);
|
||||
config_group_stream_settings.addItem(&config_frame_buffers);
|
||||
config_group_stream_settings.addItem(&config_jpg_quality);
|
||||
iotWebConf.addParameterGroup(&config_group_stream_settings);
|
||||
iotWebConf.getApTimeoutParameter()->visible = true;
|
||||
@@ -192,7 +197,7 @@ void setup()
|
||||
|
||||
// bootstrap
|
||||
web_server.on("/bootstrap.min.css", HTTP_GET, []()
|
||||
{ stream_file("/bootstrap.min.css", "text/css"); });
|
||||
{ stream_text_file(file_data_bootstrap_min_css, "text/css"); });
|
||||
|
||||
web_server.onNotFound([]()
|
||||
{ iotWebConf.handleNotFound(); });
|
||||
|
||||
Reference in New Issue
Block a user