Added additional information in the status overview

This commit is contained in:
Rene Zeldenthuis
2022-09-17 11:37:07 +02:00
parent dbea1c947e
commit ba712ad170
5 changed files with 207 additions and 126 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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);