From 0db0a5d4797255309998701c938ca8ca6618482d Mon Sep 17 00:00:00 2001 From: Rene Zeldenthuis Date: Tue, 5 Jul 2022 15:49:07 +0200 Subject: [PATCH] Additional Diagnostics --- include/format_duration.h | 11 ++++++++ include/format_si.h | 54 +++++++++++++++++++++++++++++++++++++++ src/main.cpp | 37 ++++++++++++++++++++++++--- 3 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 include/format_duration.h create mode 100644 include/format_si.h diff --git a/include/format_duration.h b/include/format_duration.h new file mode 100644 index 0000000..a2dbb2d --- /dev/null +++ b/include/format_duration.h @@ -0,0 +1,11 @@ +#pragma once + +String format_duration(time_t seconds) +{ + auto days = seconds / (60 * 60 * 24); + auto tm = gmtime(&seconds); + String duration = days > 0 ? String(days) + " days, " : ""; + char time_buff[9]; + strftime(time_buff, 9, "%H:%M:%S", tm); + return duration + time_buff; +} \ No newline at end of file diff --git a/include/format_si.h b/include/format_si.h new file mode 100644 index 0000000..bf67093 --- /dev/null +++ b/include/format_si.h @@ -0,0 +1,54 @@ +#pragma once + +#include + +String format_value(float value) +{ + if (value == 0.0) + return "0"; + + if (value < 0) + return "-" + format_value(-value); + + // No decimal places + if (value >= 1) + return String(value, 0); + if (value < 0.001f) + return String(value, 4); + if (value < 0.01f) + return String(value, 3); + if (value < 0.1f) + return String(value, 2); + return String(value, 1); +} + +String format_si(double value, int decimal_places = 2) +{ + if (value == 0.0) + return "0"; + + if (value < 0) + return "-" + format_si(-value, decimal_places); + + auto value_abs = fabs(value); + if (value_abs < 1E-9) + return String(value * 1E9, decimal_places) + "p"; + if (value_abs < 1E-6) + return String(value * 1E9, decimal_places) + "n"; + if (value_abs < 1E-3) + return String(value * 1E6, decimal_places) + "u"; + if (value_abs < 1) + return String(value * 1E3, decimal_places) + "m"; + if (value_abs < 1E3) + return String(value, decimal_places); + if (value_abs < 1E6) + return String(value / 1E3, decimal_places) + "k"; + if (value_abs < 1E9) + return String(value / 1E6, decimal_places) + "M"; + if (value_abs < 1E12) + return String(value / 1E9, decimal_places) + "G"; + if (value_abs < 1E15) + return String(value / 1E12, decimal_places) + "T"; + + return "NaN"; +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index adbb099..be8934f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include char camera_config_val[sizeof(camera_config_entry)]; @@ -45,6 +47,7 @@ void handle_root() html += "" APP_TITLE " v" APP_VERSION ""; html += ""; html += "

Status page for " + String(iotWebConf.getThingName()) + "


"; + html += "

ESP32

"; html += "
    "; html += "
  • CPU model: " + String(ESP.getChipModel()) + "
  • "; @@ -53,13 +56,22 @@ void handle_root() html += "
  • IPv4 address: " + WiFi.localIP().toString() + "
  • "; html += "
  • IPv6 address: " + WiFi.localIPv6().toString() + "
  • "; html += "
"; + html += "

Settings

"; html += "
    "; html += "
  • Camera type: " + String(camera_config_val) + "
  • "; html += "
  • Frame size: " + String(frame_size_val) + "
  • "; - html += "
  • Frame rate: " + String(frame_rate_val) + " ms
  • "; + html += "
  • Frame rate: " + String(frame_rate_val) + " ms (" + String(1000.0 / atol(frame_rate_val), 1) + " f/s)
  • "; html += "
  • JPEG quality: " + String(jpeg_quality_val) + " (0-100)
  • "; html += "
"; + + html += "

Diagnostics

"; + html += "
    "; + html += "
  • Uptime: " + String(format_duration(millis() / 1000)) + "
  • "; + html += "
  • Free heap: " + format_si(ESP.getFreeHeap()) + "b
  • "; + html += "
  • Max free block: " + format_si(ESP.getMaxAllocHeap()) + "b
  • "; + html += "
"; + html += "
camera stream: " + url + ""; html += "
"; html += "
Go to configure page to change settings."; @@ -84,14 +96,14 @@ void handle_restart() html += "" APP_TITLE " v" APP_VERSION ""; html += ""; web_server.send(200, "text/html", html); - log_v("Restarting..."); + log_v("Restarting... Press refresh to connect again"); sleep(250); ESP.restart(); } else { // Redirect to root page. - web_server.sendHeader("Location", "/", true ); + web_server.sendHeader("Location", "/", true); web_server.send(302, "text/plain", ""); } } @@ -102,6 +114,24 @@ void on_config_saved() config_changed = true; } +bool form_validator(iotwebconf::WebRequestWrapper *webRequestWrapper) +{ + log_v("Validating form"); + auto frame_rate = webRequestWrapper->arg(config_frame_rate.getId()).toInt(); + if (frame_rate <= 10) + { + log_w("Frame rate must be greater than 10 ms (100 f/s)"); + return false; + } + + auto jpeg_quality = webRequestWrapper->arg(config_jpg_quality.getId()).toInt(); + if (jpeg_quality < 1 || jpeg_quality > 100) + { + log_w("JPEG quality must be between 1 and 100"); + return false; + } +} + void initialize_camera() { log_v("Initialize camera"); @@ -159,6 +189,7 @@ void setup() config_group_stream_settings.addItem(&config_frame_size); config_group_stream_settings.addItem(&config_jpg_quality); iotWebConf.addParameterGroup(&config_group_stream_settings); + iotWebConf.setFormValidator(form_validator); iotWebConf.getApTimeoutParameter()->visible = true; iotWebConf.setConfigSavedCallback(on_config_saved); iotWebConf.setWifiConnectionCallback(on_connected);