forked from external-repos/esp32cam-rtsp
Added additional information in the status overview
This commit is contained in:
248
html/index.html
248
html/index.html
@@ -10,7 +10,7 @@
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>{{ThingName}}</h1>
|
||||
<h1 class="text-center">{{ThingName}}</h1>
|
||||
<hr>
|
||||
|
||||
{{#ConfigChanged}}
|
||||
@@ -21,121 +21,165 @@
|
||||
</div>
|
||||
{{/ConfigChanged}}
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">ESP32</h5>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-4">CPU model:</div>
|
||||
<div class="col-8">{{ChipModel}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">CPU speed:</div>
|
||||
<div class="col-8">{{CpuFreqMHz}}Mhz</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Mac address:</div>
|
||||
<div class="col-8">{{MacAddress}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">IPv4 address:</div>
|
||||
<div class="col-8">{{IpV4}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">IPv6 address:</div>
|
||||
<div class="col-8">{{IpV6}}</div>
|
||||
</div>
|
||||
{{#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}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">Settings</h5>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-4">Camera type:</div>
|
||||
<div class="col-8">{{CameraType}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Frame rate:</div>
|
||||
<div class="col-8">{{FrameDuration}} ms ({{FrameFrequency}} f/s)</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Frame size:</div>
|
||||
<div class="col-8">{{FrameSize}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Frame buffer location:</div>
|
||||
<div class="col-8">{{FrameBufferLocation}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Frame buffers:</div>
|
||||
<div class="col-8">{{FrameBuffers}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p class="col-4">JPEG quality:</p>
|
||||
<div class="progress col-8">
|
||||
<div class="progress-bar" role="progressbar" style="width: 25%;" aria-valuenow="{{JpegQuality}}"
|
||||
aria-valuemin="0" aria-valuemax="100">
|
||||
{{JpegQuality}}
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">ESP32</h5>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-4">CPU model:</div>
|
||||
<div class="col-8">{{ChipModel}} rev. {{ChipRevision}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">CPU speed:</div>
|
||||
<div class="col-8">{{CpuFreqMHz}} Mhz</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">CPU cores:</div>
|
||||
<div class="col-8">{{CpuCores}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">RAM size:</div>
|
||||
<div class="col-8">{{HeapSize}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">PSRAM size:</div>
|
||||
<div class="col-8">{{PsRamSize}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Flash size:</div>
|
||||
<div class="col-8">{{FlashSize}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{#CameraInitialized}}
|
||||
<div class="alert alert-success" role="alert">
|
||||
<p>Camera was initialized successfully!</p>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">Diagnostics</h5>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-4">Uptime:</div>
|
||||
<div class="col-8">{{Uptime}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">RTSP sessions:</div>
|
||||
<div class="col-8">{{NumRTSPSessions}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Free heap:</div>
|
||||
<div class="col-8">{{FreeHeap}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Max free block:</div>
|
||||
<div class="col-8">{{MaxAllocHeap}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</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">
|
||||
<div class="row">
|
||||
<div class="col-4">Uptime:</div>
|
||||
<div class="col-8">{{Uptime}}</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">Network</h5>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-4">Mac address:</div>
|
||||
<div class="col-8">{{MacAddress}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Wifi mode:</div>
|
||||
<div class="col-8">{{WifiMode}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Access point:</div>
|
||||
<div class="col-8">{{AccessPoint}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Signal strength:</div>
|
||||
<div class="col-8">{{SignalStrength}} dbm</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">IPv4 address:</div>
|
||||
<div class="col-8">{{IpV4}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">IPv6 address:</div>
|
||||
<div class="col-8">{{IpV6}}</div>
|
||||
</div>
|
||||
{{#NetworkState.ApMode}}
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<p>Not connected to an access point. Consider configuring the access point.</p>
|
||||
</div>
|
||||
{{/NetworkState.ApMode}}
|
||||
{{#NetworkState.OnLine}}
|
||||
<div class="alert alert-success" role="alert">
|
||||
<p>Connected to the access point</p>
|
||||
</div>
|
||||
{{/NetworkState.OnLine}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">RTSP sessions:</div>
|
||||
<div class="col-8">{{NumRTSPSessions}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Free heap:</div>
|
||||
<div class="col-8">{{FreeHeap}}b</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Max free block:</div>
|
||||
<div class="col-8">{{MaxAllocHeap}}b</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="card bg-light mb-3">
|
||||
<h5 class="card-header">Settings</h5>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-4">Camera type:</div>
|
||||
<div class="col-8">{{CameraType}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Frame rate:</div>
|
||||
<div class="col-8">{{FrameDuration}} ms ({{FrameFrequency}} f/s)</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Frame size:</div>
|
||||
<div class="col-8">{{FrameSize}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Frame buffer location:</div>
|
||||
<div class="col-8">{{FrameBufferLocation}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">Frame buffers:</div>
|
||||
<div class="col-8">{{FrameBuffers}}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p class="col-4">JPEG quality:</p>
|
||||
<div class="col-8">{{JpegQuality}} (0-100)</div>
|
||||
</div>
|
||||
{{#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>
|
||||
<button type="button" class="btn btn-danger"
|
||||
onclick="location.href='restart'">Restart</button>
|
||||
</div>
|
||||
{{/CameraInitialized}}
|
||||
</div>
|
||||
</div>
|
||||
</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 class="row">
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-warning" onclick="location.href='config'">Settings</button>
|
||||
<div class="d-grid gap-2 col-6 mx-auto">
|
||||
<button type="button" class="btn btn-lg btn-warning" onclick="location.href='config'">Settings</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,19 +5,21 @@
|
||||
<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=/">
|
||||
<meta http-equiv="refresh" content="30;url=/index.html">
|
||||
<title>{{AppTitle}} v{{AppVersion}}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>{{ThingName}}</h1>
|
||||
<h1 class="text-center">{{ThingName}}</h1>
|
||||
<hr>
|
||||
|
||||
<div class="jumbotron bg-light">
|
||||
<h1 class="display-4">Restart</h1>
|
||||
<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>
|
||||
<h1 class="display-4 text-center">Restart</h1>
|
||||
<p class="lead text-center">The device is restarting.</p>
|
||||
<hr class="my-4 ">
|
||||
<p class="text-center">In some cases, the device requires a hard reset (power cycle).</p>
|
||||
<p class="text-center">If this page takes longer than a minute, consider performing a power cycle.</p>
|
||||
<div class="d-flex justify-content-center">
|
||||
<div class="spinner-border text-danger" role="status">
|
||||
<span class="visually-hidden">Restarting...</span>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
String format_value(float value)
|
||||
String format_value(double value)
|
||||
{
|
||||
if (value == 0.0)
|
||||
return "0";
|
||||
@@ -13,11 +13,15 @@ String format_value(float value)
|
||||
// No decimal places
|
||||
if (value >= 1)
|
||||
return String(value, 0);
|
||||
if (value < 0.001f)
|
||||
if (value < 0.00001)
|
||||
return String(value, 6);
|
||||
if (value < 0.0001)
|
||||
return String(value, 5);
|
||||
if (value < 0.001)
|
||||
return String(value, 4);
|
||||
if (value < 0.01f)
|
||||
if (value < 0.01)
|
||||
return String(value, 3);
|
||||
if (value < 0.1f)
|
||||
if (value < 0.1)
|
||||
return String(value, 2);
|
||||
return String(value, 1);
|
||||
}
|
||||
@@ -32,7 +36,7 @@ String format_si(double value, int decimal_places = 2)
|
||||
|
||||
auto value_abs = fabs(value);
|
||||
if (value_abs < 1E-9)
|
||||
return String(value * 1E9, decimal_places) + "p";
|
||||
return String(value * 1E12, decimal_places) + "p";
|
||||
if (value_abs < 1E-6)
|
||||
return String(value * 1E9, decimal_places) + "n";
|
||||
if (value_abs < 1E-3)
|
||||
@@ -49,6 +53,20 @@ String format_si(double value, int decimal_places = 2)
|
||||
return String(value / 1E9, decimal_places) + "G";
|
||||
if (value_abs < 1E15)
|
||||
return String(value / 1E12, decimal_places) + "T";
|
||||
|
||||
|
||||
return "NaN";
|
||||
}
|
||||
|
||||
String format_memory(size_t bytes, int decimal_places = 2)
|
||||
{
|
||||
const char *suffix[] = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
|
||||
auto val = (double)bytes;
|
||||
auto suffix_index = 0;
|
||||
while (val >= 1024.0)
|
||||
{
|
||||
val /= 1024;
|
||||
suffix_index++;
|
||||
}
|
||||
|
||||
return String(val, decimal_places) + " " + suffix[suffix_index];
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
37
src/main.cpp
37
src/main.cpp
@@ -8,7 +8,7 @@
|
||||
#include <frame_size.h>
|
||||
#include <camera_config.h>
|
||||
#include <format_duration.h>
|
||||
#include <format_si.h>
|
||||
#include <format_number.h>
|
||||
#include <template_render.h>
|
||||
#include <html_data.h>
|
||||
#include <settings.h>
|
||||
@@ -55,15 +55,32 @@ void handle_root()
|
||||
if (iotWebConf.handleCaptivePortal())
|
||||
return;
|
||||
|
||||
const char *wifi_modes[] = {"NULL", "STA", "AP", "STA+AP"};
|
||||
|
||||
const template_variable_t substitutions[] = {
|
||||
// Config Changed?
|
||||
{"ConfigChanged", String(config_changed)},
|
||||
// Version / CPU
|
||||
{"AppTitle", APP_TITLE},
|
||||
{"AppVersion", APP_VERSION},
|
||||
{"ThingName", iotWebConf.getThingName()},
|
||||
{"ChipModel", ESP.getChipModel()},
|
||||
{"ChipRevision", String(ESP.getChipRevision())},
|
||||
{"CpuFreqMHz", String(ESP.getCpuFreqMHz())},
|
||||
{"CpuCores", String(ESP.getChipCores())},
|
||||
{"FlashSize", format_memory(ESP.getFlashChipSize(), 0)},
|
||||
{"HeapSize", format_memory(ESP.getHeapSize())},
|
||||
{"PsRamSize", format_memory(ESP.getPsramSize(), 0)},
|
||||
// Network
|
||||
{"MacAddress", WiFi.macAddress()},
|
||||
{"AccessPoint", WiFi.SSID()},
|
||||
{"SignalStrength", String(WiFi.RSSI())},
|
||||
{"IpV4", WiFi.localIP().toString()},
|
||||
{"IpV6", WiFi.localIPv6().toString()},
|
||||
{"WifiMode", wifi_modes[WiFi.getMode()]},
|
||||
{"NetworkState.ApMode", String(iotWebConf.getState() == iotwebconf::NetworkState::ApMode)},
|
||||
{"NetworkState.OnLine", String(iotWebConf.getState() == iotwebconf::NetworkState::OnLine)},
|
||||
// Camera
|
||||
{"CameraType", camera_config_val},
|
||||
{"FrameSize", frame_size_val},
|
||||
{"FrameDuration", frame_duration_val},
|
||||
@@ -71,17 +88,16 @@ void handle_root()
|
||||
{"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)},
|
||||
{"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)},
|
||||
{"NumRTSPSessions", camera_server != nullptr ? String(camera_server->num_connected()) : "N/A"}};
|
||||
// Diagnostics
|
||||
{"Uptime", String(format_duration(millis() / 1000))},
|
||||
{"FreeHeap", format_memory(ESP.getFreeHeap())},
|
||||
{"MaxAllocHeap", format_memory(ESP.getMaxAllocHeap())},
|
||||
{"NumRTSPSessions", camera_server != nullptr ? String(camera_server->num_connected()) : "N/A"},
|
||||
// URL
|
||||
{"RtspPort", String(RTSP_PORT)}};
|
||||
|
||||
web_server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
auto html = template_render(file_data_index_html, substitutions);
|
||||
@@ -91,7 +107,8 @@ void handle_root()
|
||||
void handle_restart()
|
||||
{
|
||||
log_v("Handle restart");
|
||||
if (!config_changed)
|
||||
// If configuration is not changed and camera working, do not allow a restart
|
||||
if (!config_changed && camera_init_result == ESP_OK)
|
||||
{
|
||||
// Redirect to root page
|
||||
web_server.sendHeader("Location", "/", true);
|
||||
|
||||
Reference in New Issue
Block a user