From 806e307af819618113d5fe40c56157b38fb2e2e9 Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 17 Dec 2023 12:33:10 +0100 Subject: [PATCH 01/21] add class id --- src/IotWebConfParameter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IotWebConfParameter.cpp b/src/IotWebConfParameter.cpp index 83aa153..b41cff3 100644 --- a/src/IotWebConfParameter.cpp +++ b/src/IotWebConfParameter.cpp @@ -337,7 +337,7 @@ String TextParameter::renderHtml( "{c}", current->customHtml == nullptr ? "" : current->customHtml); pitem.replace( "{s}", - current->errorMessage == nullptr ? "" : "de"); // Div style class. + current->errorMessage == nullptr ? current->getId() : "de"); // Div style class. pitem.replace( "{e}", current->errorMessage == nullptr ? "" : current->errorMessage); From 26dcd165c1336b49671c8c573b91d01a75100c0c Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 28 Dec 2023 15:55:49 +0100 Subject: [PATCH 02/21] Date and Time parameter class added --- src/IotWebConfParameter.h | 56 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/IotWebConfParameter.h b/src/IotWebConfParameter.h index 1f83691..5d79ac5 100644 --- a/src/IotWebConfParameter.h +++ b/src/IotWebConfParameter.h @@ -432,6 +432,62 @@ class SelectParameter : public OptionsParameter friend class IotWebConf; }; +/////////////////////////////////////////////////////////////////////////////// + +/** + * Date parameter is an option parameter, that rendered as HTML Date picker. + */ +class DateParameter : public iotwebconf::TextParameter { +public: + /** + * (See TextParameter for arguments!) + */ + DateParameter( + const char* label, const char* id, char* valueBuffer, int length, + const char* defaultValue = nullptr) + : iotwebconf::TextParameter( + label, id, valueBuffer, length, defaultValue, nullptr, nullptr) { + } + +protected: + virtual String renderHtml( + bool dataArrived, bool hasValueFromPost, String valueFromPost) override + { + return TextParameter::renderHtml("date", hasValueFromPost, valueFromPost); + }; + +private: + friend class IotWebConf; +}; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Time parameter is an option parameter, that rendered as HTML time picker. + */ +class TimeParameter : public iotwebconf::TextParameter { +public: + /** + * (See TextParameter for arguments!) + */ + TimeParameter( + const char* label, const char* id, char* valueBuffer, int length, + const char* defaultValue = nullptr) + : iotwebconf::TextParameter( + label, id, valueBuffer, length, defaultValue, nullptr, nullptr) { + } + +protected: + virtual String renderHtml( + bool dataArrived, bool hasValueFromPost, String valueFromPost) override + { + return TextParameter::renderHtml("time", hasValueFromPost, valueFromPost); + }; + +private: + friend class IotWebConf; +}; + /** * This class is here just to make some nice indents on debug output * for group tree. From 82958eca0a377414d9288abbbbab0b9afcb14f4b Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 28 Dec 2023 15:58:51 +0100 Subject: [PATCH 03/21] file updated --- .gitignore | 412 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 411 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ae095a1..f3aa2c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,412 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# Files built by +/sch/*.b#* +/sch/*.pro +/sch/*.s#* + + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ +__vm/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc +*.vcxproj +*.filters +*.user + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace .vscode -examples-pio \ No newline at end of file +examples-pio + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +*.heic + From 15d6cf01109a2c80bee98afbb4f94e021b3c6c3d Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 28 Dec 2023 16:59:28 +0100 Subject: [PATCH 04/21] fixed typo in new classes --- src/IotWebConfParameter.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IotWebConfParameter.h b/src/IotWebConfParameter.h index 5d79ac5..b5cf265 100644 --- a/src/IotWebConfParameter.h +++ b/src/IotWebConfParameter.h @@ -437,7 +437,7 @@ class SelectParameter : public OptionsParameter /** * Date parameter is an option parameter, that rendered as HTML Date picker. */ -class DateParameter : public iotwebconf::TextParameter { +class DateParameter : public TextParameter { public: /** * (See TextParameter for arguments!) @@ -465,7 +465,7 @@ class DateParameter : public iotwebconf::TextParameter { /** * Time parameter is an option parameter, that rendered as HTML time picker. */ -class TimeParameter : public iotwebconf::TextParameter { +class TimeParameter : public TextParameter { public: /** * (See TextParameter for arguments!) From 4175f41875689f43e5bd0dc672c09a4d86982cf4 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 10 May 2024 08:37:38 +0200 Subject: [PATCH 05/21] url updated --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 2c50c84..67dbf36 100644 --- a/library.properties +++ b/library.properties @@ -5,6 +5,6 @@ maintainer=Balazs Kelemen sentence=ESP8266/ESP32 non-blocking WiFi/AP web configuration. paragraph=IotWebConf will start up in AP (access point) mode, and provide a config portal for entering WiFi connection and other user-settings. The configuration is persisted in EEPROM. The config portal will stay available after WiFi connection was made. A WiFiManager alternative. category=Communication -url=https://github.com/prampec/IotWebConf +url=https://github.com/minou65/IotWebConf architectures=esp8266,esp32 includes=IotWebConf.h From d6da95b69b894cc1a10b94fa36b3018d5c6c27f2 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 10 May 2024 08:38:29 +0200 Subject: [PATCH 06/21] updated --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index f3aa2c2..9a3c7f1 100644 --- a/.gitignore +++ b/.gitignore @@ -410,3 +410,5 @@ examples-pio *.sln.iml *.heic +/IotWebConf.sln +/IotWebConf.vcxitems From fcc4718aef65a80de616212772a3af85b3045fdd Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 1 Oct 2024 07:44:09 +0200 Subject: [PATCH 07/21] fixed errors in stop() --- src/IotWebConf.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/IotWebConf.cpp b/src/IotWebConf.cpp index 61935d7..3afa7f9 100644 --- a/src/IotWebConf.cpp +++ b/src/IotWebConf.cpp @@ -302,15 +302,21 @@ void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) #ifdef IOTWEBCONF_DEBUG_TO_SERIAL Serial.println("Rendering parameters:"); - this->_systemParameters.debugTo(&Serial); - this->_customParameterGroups.debugTo(&Serial); + //this->_systemParameters.debugTo(&Serial); + //this->_customParameterGroups.debugTo(&Serial); #endif + Serial.println("=========================Add parameters to the form"); + + // -- Add parameters to the form this->_systemParameters.renderHtml(dataArrived, webRequestWrapper); + Serial.println("=========================_systemParameters"); this->_customParameterGroups.renderHtml(dataArrived, webRequestWrapper); + Serial.println("=========================_customParameterGroups"); content = htmlFormatProvider->getFormEnd(); + Serial.println("=========================updatePath"); if (this->_updatePath != nullptr) { String pitem = htmlFormatProvider->getUpdate(); @@ -319,6 +325,7 @@ void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) } // -- Fill config version string; + Serial.println("=========================Fill config version string"); { String pitem = htmlFormatProvider->getConfigVer(); pitem.replace("{v}", this->_configVersion); From 3939be49ce6d44134b598c2ecd261e8d7c6ba76f Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 1 Oct 2024 11:54:08 +0200 Subject: [PATCH 08/21] migratet to new version ESPAsyncWebServer. Added some error handling for more stability --- src/IotWebConf.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/IotWebConf.cpp b/src/IotWebConf.cpp index 3afa7f9..61935d7 100644 --- a/src/IotWebConf.cpp +++ b/src/IotWebConf.cpp @@ -302,21 +302,15 @@ void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) #ifdef IOTWEBCONF_DEBUG_TO_SERIAL Serial.println("Rendering parameters:"); - //this->_systemParameters.debugTo(&Serial); - //this->_customParameterGroups.debugTo(&Serial); + this->_systemParameters.debugTo(&Serial); + this->_customParameterGroups.debugTo(&Serial); #endif - Serial.println("=========================Add parameters to the form"); - - // -- Add parameters to the form this->_systemParameters.renderHtml(dataArrived, webRequestWrapper); - Serial.println("=========================_systemParameters"); this->_customParameterGroups.renderHtml(dataArrived, webRequestWrapper); - Serial.println("=========================_customParameterGroups"); content = htmlFormatProvider->getFormEnd(); - Serial.println("=========================updatePath"); if (this->_updatePath != nullptr) { String pitem = htmlFormatProvider->getUpdate(); @@ -325,7 +319,6 @@ void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) } // -- Fill config version string; - Serial.println("=========================Fill config version string"); { String pitem = htmlFormatProvider->getConfigVer(); pitem.replace("{v}", this->_configVersion); From e16d16a54808d079e7a96af000502c0d679ef5a5 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 1 Oct 2024 11:57:33 +0200 Subject: [PATCH 09/21] Revert "migratet to new version ESPAsyncWebServer. Added some error handling for more stability" This reverts commit 3939be49ce6d44134b598c2ecd261e8d7c6ba76f. --- src/IotWebConf.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/IotWebConf.cpp b/src/IotWebConf.cpp index 61935d7..3afa7f9 100644 --- a/src/IotWebConf.cpp +++ b/src/IotWebConf.cpp @@ -302,15 +302,21 @@ void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) #ifdef IOTWEBCONF_DEBUG_TO_SERIAL Serial.println("Rendering parameters:"); - this->_systemParameters.debugTo(&Serial); - this->_customParameterGroups.debugTo(&Serial); + //this->_systemParameters.debugTo(&Serial); + //this->_customParameterGroups.debugTo(&Serial); #endif + Serial.println("=========================Add parameters to the form"); + + // -- Add parameters to the form this->_systemParameters.renderHtml(dataArrived, webRequestWrapper); + Serial.println("=========================_systemParameters"); this->_customParameterGroups.renderHtml(dataArrived, webRequestWrapper); + Serial.println("=========================_customParameterGroups"); content = htmlFormatProvider->getFormEnd(); + Serial.println("=========================updatePath"); if (this->_updatePath != nullptr) { String pitem = htmlFormatProvider->getUpdate(); @@ -319,6 +325,7 @@ void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) } // -- Fill config version string; + Serial.println("=========================Fill config version string"); { String pitem = htmlFormatProvider->getConfigVer(); pitem.replace("{v}", this->_configVersion); From a8278da9ae2d208df9e79094e1e5ec6fa2fdf0e8 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 1 Oct 2024 12:04:56 +0200 Subject: [PATCH 10/21] removed some debug informations --- src/IotWebConf.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/IotWebConf.cpp b/src/IotWebConf.cpp index 3afa7f9..61935d7 100644 --- a/src/IotWebConf.cpp +++ b/src/IotWebConf.cpp @@ -302,21 +302,15 @@ void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) #ifdef IOTWEBCONF_DEBUG_TO_SERIAL Serial.println("Rendering parameters:"); - //this->_systemParameters.debugTo(&Serial); - //this->_customParameterGroups.debugTo(&Serial); + this->_systemParameters.debugTo(&Serial); + this->_customParameterGroups.debugTo(&Serial); #endif - Serial.println("=========================Add parameters to the form"); - - // -- Add parameters to the form this->_systemParameters.renderHtml(dataArrived, webRequestWrapper); - Serial.println("=========================_systemParameters"); this->_customParameterGroups.renderHtml(dataArrived, webRequestWrapper); - Serial.println("=========================_customParameterGroups"); content = htmlFormatProvider->getFormEnd(); - Serial.println("=========================updatePath"); if (this->_updatePath != nullptr) { String pitem = htmlFormatProvider->getUpdate(); @@ -325,7 +319,6 @@ void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) } // -- Fill config version string; - Serial.println("=========================Fill config version string"); { String pitem = htmlFormatProvider->getConfigVer(); pitem.replace("{v}", this->_configVersion); From 16817664cdb54d983c360acec9c610bcfc7cd71a Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 2 Oct 2024 06:19:24 +0200 Subject: [PATCH 11/21] do not render parameters --- src/IotWebConf.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/IotWebConf.cpp b/src/IotWebConf.cpp index 61935d7..88e9aec 100644 --- a/src/IotWebConf.cpp +++ b/src/IotWebConf.cpp @@ -301,9 +301,9 @@ void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) webRequestWrapper->sendContent(content); #ifdef IOTWEBCONF_DEBUG_TO_SERIAL - Serial.println("Rendering parameters:"); - this->_systemParameters.debugTo(&Serial); - this->_customParameterGroups.debugTo(&Serial); + //Serial.println("Rendering parameters:"); + //this->_systemParameters.debugTo(&Serial); + //this->_customParameterGroups.debugTo(&Serial); #endif // -- Add parameters to the form this->_systemParameters.renderHtml(dataArrived, webRequestWrapper); From 745fdd40d4faac328b3b89f0c2437efae17241d8 Mon Sep 17 00:00:00 2001 From: Andreas Zogg Date: Wed, 13 Nov 2024 08:00:28 +0100 Subject: [PATCH 12/21] void setConfigSavedPage added --- src/IotWebConf.cpp | 12 +++++++++++- src/IotWebConf.h | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/IotWebConf.cpp b/src/IotWebConf.cpp index 88e9aec..011e67e 100644 --- a/src/IotWebConf.cpp +++ b/src/IotWebConf.cpp @@ -247,6 +247,11 @@ void IotWebConf::setConfigSavedCallback(std::function func) this->_configSavedCallback = func; } +void IotWebConf::setConfigSavedPage(std::function func){ + this->_configSavedPage = func; +} + + void IotWebConf::setFormValidator( std::function func) { @@ -369,7 +374,12 @@ void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) } else { - page += F("Return to home page."); + if (this->_configSavedPage != nullptr){ + this->_configSavedPage(webRequestWrapper); + return; + } else { + page += F("Return to home page."); + } } page += htmlFormatProvider->getEnd(); diff --git a/src/IotWebConf.h b/src/IotWebConf.h index 2f65e1c..51f899f 100644 --- a/src/IotWebConf.h +++ b/src/IotWebConf.h @@ -293,6 +293,8 @@ class IotWebConf */ void setConfigSavedCallback(std::function func); + void setConfigSavedPage(std::function func); + /** * Specify a callback method, that will be called when form validation is required. * If the method will return false, the configuration will not be saved. @@ -600,6 +602,7 @@ class IotWebConf std::function _wifiConnectionCallback = nullptr; std::function _configSavingCallback = nullptr; std::function _configSavedCallback = nullptr; + std::function _configSavedPage = nullptr; std::function _formValidator = nullptr; std::function _apConnectionHandler = &(IotWebConf::connectAp); From 6e266874f3f6a5d9d810b5aad3665d78431de4a6 Mon Sep 17 00:00:00 2001 From: Andreas Zogg Date: Wed, 13 Nov 2024 14:41:28 +0100 Subject: [PATCH 13/21] Update setConfigSavedPage to accept void return type for custom actions --- src/IotWebConf.cpp | 3 +-- src/IotWebConf.h | 11 +++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/IotWebConf.cpp b/src/IotWebConf.cpp index 011e67e..1d2dda3 100644 --- a/src/IotWebConf.cpp +++ b/src/IotWebConf.cpp @@ -247,11 +247,10 @@ void IotWebConf::setConfigSavedCallback(std::function func) this->_configSavedCallback = func; } -void IotWebConf::setConfigSavedPage(std::function func){ +void IotWebConf::setConfigSavedPage(std::function func){ this->_configSavedPage = func; } - void IotWebConf::setFormValidator( std::function func) { diff --git a/src/IotWebConf.h b/src/IotWebConf.h index 51f899f..946b143 100644 --- a/src/IotWebConf.h +++ b/src/IotWebConf.h @@ -293,7 +293,14 @@ class IotWebConf */ void setConfigSavedCallback(std::function func); - void setConfigSavedPage(std::function func); + /** + * Sets a custom function that will be called when the configuration page is + * saved. This function can be used to perform custom actions after the + * configuration has been successfully saved. + * @func - A function that accepts a WebRequestWrapper as a parameter + */ + void setConfigSavedPage(std::function func); + /** * Specify a callback method, that will be called when form validation is required. @@ -602,7 +609,7 @@ class IotWebConf std::function _wifiConnectionCallback = nullptr; std::function _configSavingCallback = nullptr; std::function _configSavedCallback = nullptr; - std::function _configSavedPage = nullptr; + std::function _configSavedPage = nullptr; std::function _formValidator = nullptr; std::function _apConnectionHandler = &(IotWebConf::connectAp); From 3f8f6076d4a869be2631071a2dac67cb7fbdf378 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 15 Nov 2024 06:22:25 +0100 Subject: [PATCH 14/21] Add support for custom pages when configuration is incomplete --- src/IotWebConf.cpp | 69 ++++++++++++++++++++++++++++++++++++---------- src/IotWebConf.h | 12 ++++++++ 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/IotWebConf.cpp b/src/IotWebConf.cpp index 1d2dda3..3e01d23 100644 --- a/src/IotWebConf.cpp +++ b/src/IotWebConf.cpp @@ -247,7 +247,27 @@ void IotWebConf::setConfigSavedCallback(std::function func) this->_configSavedCallback = func; } -void IotWebConf::setConfigSavedPage(std::function func){ +void IotWebConf::setConfigAPPasswordMissingPage( + std::function func) +{ + this->_configAPPasswordMissingPage = func; +} + +void IotWebConf::setConfigSSIDNotConfiguredPage( + std::function func) +{ + this->_configSSIDNotConfiguredPage = func; +} + +void IotWebConf::setConfigNotConfiguredPage( + std::function func) +{ + this->_configNotConfiguredPage = func; +} + +void IotWebConf::setConfigSavedPage( + std::function func) +{ this->_configSavedPage = func; } @@ -359,26 +379,45 @@ void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) page += "Configuration saved. "; if (this->_apPassword[0] == '\0') { - page += F("You must change the default AP password to continue. Return " - "to configuration page."); - } - else if (this->_wifiParameters._wifiSsid[0] == '\0') - { - page += F("You must provide the local wifi settings to continue. Return " - "to configuration page."); + if (this->_configAPPasswordMissingPage != nullptr) + { + this->_configAPPasswordMissingPage(webRequestWrapper); + return; + } + else + { + page += F("You must change the default AP password to continue. Return " + "to configuration page."); + } } - else if (this->_state == NotConfigured) - { - page += F("Please disconnect from WiFi AP to continue!"); + else if (this->_wifiParameters._wifiSsid[0] == '\0') { + if (this->_configSSIDNotConfiguredPage != nullptr) + { + this->_configSSIDNotConfiguredPage(webRequestWrapper); + return; + } + else + { + page += F("You must provide the local wifi settings to continue. " + "Return to configuration page."); + } } - else + else if (this->_state == NotConfigured) { + if (this->_configNotConfiguredPage != nullptr) + { + this->_configNotConfiguredPage(webRequestWrapper); + return; + } else { + page += F("Please disconnect from WiFi AP to continue!"); + } + } + else { if (this->_configSavedPage != nullptr){ this->_configSavedPage(webRequestWrapper); return; - } else { - page += F("Return to home page."); - } + } + page += F("Return to home page."); } page += htmlFormatProvider->getEnd(); diff --git a/src/IotWebConf.h b/src/IotWebConf.h index 946b143..f58ed78 100644 --- a/src/IotWebConf.h +++ b/src/IotWebConf.h @@ -293,6 +293,15 @@ class IotWebConf */ void setConfigSavedCallback(std::function func); + void setConfigAPPasswordMissingPage( + std::function func); + + void setConfigSSIDNotConfiguredPage( + std::function func); + + void setConfigNotConfiguredPage( + std::function func); + /** * Sets a custom function that will be called when the configuration page is * saved. This function can be used to perform custom actions after the @@ -609,6 +618,9 @@ class IotWebConf std::function _wifiConnectionCallback = nullptr; std::function _configSavingCallback = nullptr; std::function _configSavedCallback = nullptr; + std::function _configSSIDNotConfiguredPage = nullptr; + std::function _configAPPasswordMissingPage = nullptr; + std::function _configNotConfiguredPage = nullptr; std::function _configSavedPage = nullptr; std::function _formValidator = nullptr; std::function _apConnectionHandler = From d09d9577ebe009e1baf4c8486116ded731d3cdce Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 15 Nov 2024 07:03:43 +0100 Subject: [PATCH 15/21] Update configuration header to include device name --- library.properties | 2 +- src/IotWebConf.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 67dbf36..0399a21 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=IotWebConf -version=3.2.1 +version=3.2.3 author=Balazs Kelemen maintainer=Balazs Kelemen sentence=ESP8266/ESP32 non-blocking WiFi/AP web configuration. diff --git a/src/IotWebConf.cpp b/src/IotWebConf.cpp index 3e01d23..6dc5f96 100644 --- a/src/IotWebConf.cpp +++ b/src/IotWebConf.cpp @@ -314,7 +314,7 @@ void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) webRequestWrapper->send(200, "text/html; charset=UTF-8", ""); String content = htmlFormatProvider->getHead(); - content.replace("{v}", "Config ESP"); + content.replace("{v}", String("Config ") + this->getThingName()); content += htmlFormatProvider->getScript(); content += htmlFormatProvider->getStyle(); content += htmlFormatProvider->getHeadExtension(); From 13a31f43f365455c3a485478770ce1295f2120e4 Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 17 Nov 2024 08:34:44 +0100 Subject: [PATCH 16/21] Enhance firmware update HTML interface with improved styling and navigation links --- library.properties | 2 +- src/IotWebConfESP32HTTPUpdateServer.h | 47 ++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/library.properties b/library.properties index 0399a21..7b19fef 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=IotWebConf -version=3.2.3 +version=3.2.4 author=Balazs Kelemen maintainer=Balazs Kelemen sentence=ESP8266/ESP32 non-blocking WiFi/AP web configuration. diff --git a/src/IotWebConfESP32HTTPUpdateServer.h b/src/IotWebConfESP32HTTPUpdateServer.h index b1357bf..cabcfe2 100644 --- a/src/IotWebConfESP32HTTPUpdateServer.h +++ b/src/IotWebConfESP32HTTPUpdateServer.h @@ -152,14 +152,45 @@ class HTTPUpdateServer String _password; bool _authenticated; String _updaterError; - const char* serverIndex PROGMEM = -R"(
- - -
- )"; - const char* successResponse PROGMEM = -"Update Success! Rebooting...\n"; + const char* serverIndex PROGMEM =R"( + + + + + +
+ + + +
+
+
+ Firmware update +
+ + +
+
+
+ + + +
Go to configure page to change configuration.
Go to main page.
+ + )"; + const char* successResponse PROGMEM = + "Update Success! " + "Rebooting...\n"; }; ///////////////////////////////////////////////////////////////////////////////// From d2406ebe0fad6c9548d47ba0e6b6a918eaaaa461 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 11 Jul 2025 06:43:41 +0200 Subject: [PATCH 17/21] Add detailed documentation for input parameters and their types --- README.md | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) diff --git a/README.md b/README.md index 70ee741..92ef546 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,237 @@ to ESP32. There are two major problems. - ESP8266 uses specific naming for it's classes (e.g. ESP8266WebServer). However, ESP32 uses a more generic naming (e.g. WebServer). The idea here is to use the generic naming hoping that ESP8266 will adopt these "standards" sooner or later. - ESP32 does not provide an HTTPUpdateServer implementation. So in this project we have implemented one. Whenever ESP32 provides an official HTTPUpdateServer, this local implementation will be removed. +## Input parameters + +IotWebConf provides various parameter types for creating configuration forms. Each parameter type is designed for specific use cases and renders appropriate HTML input fields. + +### Base Classes + +#### ConfigItem +Abstract base class for all configuration items. Provides core functionality for: +- EEPROM storage and loading +- HTML rendering +- Value validation +- Debug output +- JSON serialization (if enabled) + +#### ParameterGroup +Groups related parameters together in fieldsets for better organization. + +```cpp +ParameterGroup group("groupId", "Group Label"); +``` + +#### Parameter +Base class for all input parameters with common properties: +- `label` - Display label in the configuration form +- `id` - Unique identifier for HTML and storage +- `valueBuffer` - Buffer to store the parameter value +- `length` - Buffer length +- `defaultValue` - Default value on first startup +- `errorMessage` - Validation error message +- `visible` - Controls parameter visibility + +### Available Parameter Types + +#### TextParameter +Standard text input field for string values. + +```cpp +TextParameter textParam( + "Parameter Label", // label + "paramId", // id + valueBuffer, // value buffer + 32, // buffer length + "default value", // default value (optional) + "placeholder text", // placeholder (optional) + "custom HTML attrs" // custom HTML attributes (optional) +); +``` + +**Properties:** +- `placeholder` - Text displayed in empty input field +- `customHtml` - Additional HTML attributes for customization + +#### PasswordParameter +Password input field with special handling - only updates EEPROM when a new value is provided. + +```cpp +PasswordParameter passwordParam( + "Password", + "password", + passwordBuffer, + 32, + "defaultPass", // default value (optional) + "Enter password", // placeholder (optional) + "ondblclick=\"pw(this.id)\"" // custom HTML (optional) +); +``` + +**Features:** +- Masked input field (type="password") +- Double-click to reveal password (with default customHtml) +- Only saves to EEPROM when new value provided +- Limited to IOTWEBCONF_PASSWORD_LEN characters + +#### NumberParameter +Numeric input field with number validation. + +```cpp +NumberParameter numberParam( + "Port Number", + "port", + portBuffer, + 6, + "8080", // default value (optional) + "Enter port", // placeholder (optional) + "min='1' max='65535'" // custom HTML for validation (optional) +); +``` + +**Features:** +- HTML5 number input type +- Browser-native numeric validation +- Supports min/max attributes via customHtml + +#### CheckboxParameter +Checkbox input for boolean values. + +```cpp +CheckboxParameter checkboxParam( + "Enable Feature", + "enable", + enableBuffer, + 10, + true // default checked state +); +``` + +**Features:** +- Value is either empty or "selected" +- `isChecked()` method returns boolean state +- Special form handling (unchecked boxes don't send values) + +#### SelectParameter +Dropdown selection from predefined options. + +```cpp +// Define options +const char* optionValues = "opt1\0opt2\0opt3"; +const char* optionNames = "Option 1\0Option 2\0Option 3"; + +SelectParameter selectParam( + "Select Option", + "option", + optionBuffer, + 10, + optionValues, // values to store + optionNames, // display names + 3, // option count + 20, // max name length + "opt1" // default value (optional) +); +``` + +**Features:** +- Dropdown HTML SELECT element +- Separate values and display names +- Configurable option count and name length + +#### DateParameter +HTML5 date picker input. + +```cpp +DateParameter dateParam( + "Select Date", + "date", + dateBuffer, + 12, + "2023-01-01" // default value (optional) +); +``` + +**Features:** +- Native browser date picker +- ISO date format (YYYY-MM-DD) +- Calendar popup interface + +#### TimeParameter +HTML5 time picker input. + +```cpp +TimeParameter timeParam( + "Select Time", + "time", + timeBuffer, + 8, + "12:00" // default value (optional) +); +``` + +**Features:** +- Native browser time picker +- 24-hour format (HH:MM) +- Time selection interface + +### Parameter Organization + +#### Adding Parameters to Groups +```cpp +ParameterGroup mainGroup("main", "Main Settings"); +mainGroup.addItem(&textParam); +mainGroup.addItem(&passwordParam); +mainGroup.addItem(&numberParam); +``` + +#### Visibility Control +```cpp +// Hide parameter conditionally +textParam.visible = false; +``` + +### Advanced Features + +#### Custom HTML Attributes +All text-based parameters support custom HTML attributes: +```cpp +TextParameter customParam( + "Custom Field", + "custom", + buffer, + 32, + nullptr, + "placeholder", + "required pattern='[A-Za-z]+' title='Letters only'" +); +``` + +#### Validation +Parameters can have error messages set for validation feedback: +```cpp +if (strlen(textParam.valueBuffer) < 3) { + textParam.errorMessage = "Minimum 3 characters required"; +} +``` + +#### JSON Support +When `IOTWEBCONF_ENABLE_JSON` is defined, parameters support JSON serialization: +```cpp +#ifdef IOTWEBCONF_ENABLE_JSON + parameter.loadFromJson(jsonObject); +#endif +``` + +### Best Practices + +1. **Buffer Management**: Always ensure value buffers are large enough for expected values +2. **Parameter IDs**: Use unique, descriptive IDs without spaces or special characters +3. **Default Values**: Provide sensible defaults for better user experience +4. **Validation**: Implement proper validation and error handling +5. **Organization**: Group related parameters together using ParameterGroup +6. **Security**: Use PasswordParameter for sensitive data + + ## Customizing and extending functionality IotWebConf is ment to be developer friendly by providing lots of customization options. See [HackingGuide](doc/HackingGuide.md) for From 80cffe388dc0c121c07ff5b00ffd856661f3f6a5 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 21 Aug 2025 07:04:11 +0200 Subject: [PATCH 18/21] Remove debug serial prints in handleCaptivePortal function --- src/IotWebConf.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/IotWebConf.cpp b/src/IotWebConf.cpp index 46d973c..05bfcc3 100644 --- a/src/IotWebConf.cpp +++ b/src/IotWebConf.cpp @@ -508,12 +508,12 @@ bool IotWebConf::handleCaptivePortal(WebRequestWrapper* webRequestWrapper) if (!isIp(host) && !host.startsWith(thingName)) { #ifdef IOTWEBCONF_DEBUG_TO_SERIAL - Serial.print("Request for "); - Serial.print(host); - Serial.print(" redirected to "); - Serial.print(webRequestWrapper->localIP()); - Serial.print(":"); - Serial.println(webRequestWrapper->localPort()); + //Serial.print("Request for "); + //Serial.print(host); + //Serial.print(" redirected to "); + //Serial.print(webRequestWrapper->localIP()); + //Serial.print(":"); + //Serial.println(webRequestWrapper->localPort()); #endif webRequestWrapper->sendHeader( "Location", String("http://") + toStringIp(webRequestWrapper->localIP()) + ":" + webRequestWrapper->localPort(), true); From 9fc8d68110fd0f7def37128029eaae0f3583cbb2 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 7 Nov 2025 15:54:15 +0100 Subject: [PATCH 19/21] Make isActive and setActive methods virtual in OptionalParameterGroup class --- library.properties | 2 +- src/IotWebConfOptionalGroup.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library.properties b/library.properties index 7b19fef..375e9a7 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=IotWebConf -version=3.2.4 +version=3.2.5 author=Balazs Kelemen maintainer=Balazs Kelemen sentence=ESP8266/ESP32 non-blocking WiFi/AP web configuration. diff --git a/src/IotWebConfOptionalGroup.h b/src/IotWebConfOptionalGroup.h index 60a2b1f..d7aeb71 100644 --- a/src/IotWebConfOptionalGroup.h +++ b/src/IotWebConfOptionalGroup.h @@ -71,8 +71,8 @@ class OptionalParameterGroup : public ParameterGroup { public: OptionalParameterGroup(const char* id, const char* label, bool defaultActive); - bool isActive() { return this->_active; } - void setActive(bool active) { this->_active = active; } + virtual bool isActive() const { return this->_active; } + virtual void setActive(bool active) { this->_active = active; } protected: int getStorageSize() override; From 6d6ee4718d0d267c366995b52d4b7aa783401adb Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 23 Nov 2025 09:54:31 +0100 Subject: [PATCH 20/21] file removed --- .clang-format | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .clang-format diff --git a/.clang-format b/.clang-format deleted file mode 100644 index c2b03d8..0000000 --- a/.clang-format +++ /dev/null @@ -1,5 +0,0 @@ -BasedOnStyle: LLVM -PointerAlignment: Left -AllowShortFunctionsOnASingleLine: InlineOnly -AlignAfterOpenBracket: AlwaysBreak -BreakBeforeBraces: Allman \ No newline at end of file From 073e21219bf557e625bfe8e61828e8bce382e6b3 Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 23 Nov 2025 10:06:55 +0100 Subject: [PATCH 21/21] feat: Add support for real chunking with ESPAsyncWebServer Extended the library to support proper chunked response handling with ESPAsyncWebServer, enabling efficient streaming of large responses. --- library.properties | 2 +- src/IotWebConf.cpp | 30 +++++++++------- src/IotWebConf.h | 17 ++++++++- src/IotWebConfOptionalGroup.cpp | 62 +++++++++++++++++++++++++++++++-- src/IotWebConfOptionalGroup.h | 3 ++ src/IotWebConfParameter.cpp | 61 ++++++++++++++++++++++++++++++-- src/IotWebConfParameter.h | 20 +++++++---- src/IotWebConfTParameter.h | 11 ++++-- 8 files changed, 179 insertions(+), 27 deletions(-) diff --git a/library.properties b/library.properties index 375e9a7..aa42957 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=IotWebConf -version=3.2.5 +version=3.3.0 author=Balazs Kelemen maintainer=Balazs Kelemen sentence=ESP8266/ESP32 non-blocking WiFi/AP web configuration. diff --git a/src/IotWebConf.cpp b/src/IotWebConf.cpp index 05bfcc3..1bbea74 100644 --- a/src/IotWebConf.cpp +++ b/src/IotWebConf.cpp @@ -284,6 +284,21 @@ void IotWebConf::setWifiConnectionTimeoutMs(unsigned long millis) //////////////////////////////////////////////////////////////////////////////// +String IotWebConf::getUpdateLinkHtml() { + if (this->_updatePath != nullptr) { + String pitem = htmlFormatProvider->getUpdate(); + pitem.replace("{u}", this->_updatePath); + return pitem; + } + return String(); +} + +String IotWebConf::getConfigVersionHtml() { + String pitem = htmlFormatProvider->getConfigVer(); + pitem.replace("{v}", this->_configVersion); + return pitem; +} + void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) { if (this->_state == OnLine) @@ -335,19 +350,8 @@ void IotWebConf::handleConfig(WebRequestWrapper* webRequestWrapper) content = htmlFormatProvider->getFormEnd(); - if (this->_updatePath != nullptr) - { - String pitem = htmlFormatProvider->getUpdate(); - pitem.replace("{u}", this->_updatePath); - content += pitem; - } - - // -- Fill config version string; - { - String pitem = htmlFormatProvider->getConfigVer(); - pitem.replace("{v}", this->_configVersion); - content += pitem; - } + content += this->getUpdateLinkHtml(); + content += this->getConfigVersionHtml(); content += htmlFormatProvider->getEnd(); diff --git a/src/IotWebConf.h b/src/IotWebConf.h index 4d0d293..27f5a62 100644 --- a/src/IotWebConf.h +++ b/src/IotWebConf.h @@ -523,6 +523,11 @@ class IotWebConf { return &this->_systemParameters; }; + + ParameterGroup* getCustomParameterGroup() { + return &this->_customParameterGroups; + } + Parameter* getThingNameParameter() { return &this->_thingNameParameter; @@ -548,6 +553,14 @@ class IotWebConf return &this->_apTimeoutParameter; }; + const char* getApPassword() const { + return this->_apPassword; + } + + String getUpdateLinkHtml(); + String getConfigVersionHtml(); + + /** * If config parameters are modified directly, the new values can be saved by this method. * Note, that init() must pretend saveConfig()! @@ -576,6 +589,8 @@ class IotWebConf return this->htmlFormatProvider; } + bool validateForm(WebRequestWrapper* webRequestWrapper); + private: const char* _initialApPassword = nullptr; const char* _configVersion; @@ -648,7 +663,7 @@ class IotWebConf void readEepromValue(int start, byte* valueBuffer, int length); void writeEepromValue(int start, byte* valueBuffer, int length); - bool validateForm(WebRequestWrapper* webRequestWrapper); + void changeState(NetworkState newState); void stateChanged(NetworkState oldState, NetworkState newState); diff --git a/src/IotWebConfOptionalGroup.cpp b/src/IotWebConfOptionalGroup.cpp index 9e64649..c1f210d 100644 --- a/src/IotWebConfOptionalGroup.cpp +++ b/src/IotWebConfOptionalGroup.cpp @@ -61,8 +61,7 @@ void OptionalParameterGroup::loadValue( ParameterGroup::loadValue(doLoad); } -void OptionalParameterGroup::renderHtml( - bool dataArrived, WebRequestWrapper* webRequestWrapper) +void OptionalParameterGroup::renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper) { if (this->label != nullptr) { @@ -100,6 +99,65 @@ void OptionalParameterGroup::renderHtml( } } +bool OptionalParameterGroup::renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper, HtmlChunkCallback outputCallback) { + // Serial.println("OptionalParameterGroup::renderHtml called"); + + ConfigItem* current_ = _currentItem ? _currentItem : this->_firstItem; + + if (!_startTemplateSend && this->label != nullptr) { + //Serial.println(" outputting start template"); + String content_ = getStartTemplate(); + content_.replace("{b}", this->label); + content_.replace("{i}", this->getId()); + content_.replace("{v}", this->_active ? "active" : "inactive"); + if (this->_active) { + content_.replace("{cb}", "hide"); + content_.replace("{cf}", ""); + } + else { + content_.replace("{cb}", ""); + content_.replace("{cf}", "hide"); + } + bool completed_ = outputCallback(content_.c_str(), content_.length()); + if (!completed_) { + //Serial.println("Rendering interrupted during start template, saving state."); + return completed_; + } + _startTemplateSend = true; + } + + + while (current_ != nullptr) { + //Serial.print(" rendering item: "); Serial.println(current_->getId()); + if (current_->visible) { + bool completed_ = current_->renderHtml(dataArrived, webRequestWrapper, outputCallback); + if (!completed_) { + //Serial.println("Rendering interrupted, saving state."); + _currentItem = current_; + return completed_; + } + } + current_ = this->getNextItemOf(current_); + } + + if (this->label != nullptr) { + //Serial.println(" outputting end template"); + String content_ = getEndTemplate(); + content_.replace("{b}", this->label); + content_.replace("{i}", this->getId()); + bool completed_ = outputCallback(content_.c_str(), content_.length()); + if (!completed_) { + //Serial.println("Rendering interrupted during end template, saving state."); + return completed_; + } + } + + _currentItem = nullptr; + _startTemplateSend = false; + //Serial.println("OptionalParameterGroup::renderHtml completed"); + return true; +} + void OptionalParameterGroup::update(WebRequestWrapper* webRequestWrapper) { // -- Get active variable diff --git a/src/IotWebConfOptionalGroup.h b/src/IotWebConfOptionalGroup.h index d7aeb71..74f6a28 100644 --- a/src/IotWebConfOptionalGroup.h +++ b/src/IotWebConfOptionalGroup.h @@ -82,6 +82,7 @@ class OptionalParameterGroup : public ParameterGroup void loadValue(std::function doLoad) override; void renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper) override; + bool renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper, HtmlChunkCallback outputCallback) override; virtual String getStartTemplate() { return FPSTR(IOTWEBCONF_HTML_FORM_OPTIONAL_GROUP_START); }; virtual String getEndTemplate() { return FPSTR(IOTWEBCONF_HTML_FORM_OPTIONAL_GROUP_END); }; void update(WebRequestWrapper* webRequestWrapper) override; @@ -90,6 +91,8 @@ class OptionalParameterGroup : public ParameterGroup private: bool _defaultActive; bool _active; + bool _continueRendering = false; + }; class ChainedParameterGroup; diff --git a/src/IotWebConfParameter.cpp b/src/IotWebConfParameter.cpp index b41cff3..baa677f 100644 --- a/src/IotWebConfParameter.cpp +++ b/src/IotWebConfParameter.cpp @@ -110,6 +110,55 @@ void ParameterGroup::renderHtml( webRequestWrapper->sendContent(content); } } + +bool ParameterGroup::renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper, HtmlChunkCallback outputCallback) { + //Serial.println("ParameterGroup::renderHtml called"); + + ConfigItem* current_ = _currentItem ? _currentItem : this->_firstItem; + + if (!_startTemplateSend && this->label != nullptr) { + //Serial.println("Sending start template"); + String content_ = getStartTemplate(); + content_.replace("{b}", this->label); + content_.replace("{i}", this->getId()); + bool completed_ = outputCallback(content_.c_str(), content_.length()); + if (!completed_) { + //Serial.println("Rendering interrupted during start template, saving state."); + return completed_; + } + _startTemplateSend = true; + } + + while (current_ != nullptr) { + //Serial.print("Rendering item: "); Serial.println(current_->getId()); + if (current_->visible) { + bool completed_ = current_->renderHtml(dataArrived, webRequestWrapper, outputCallback); + if (!completed_) { + //Serial.println("Rendering interrupted, saving state."); + _currentItem = current_; + return completed_; + } + } + current_ = current_->_nextItem; + } + + if (this->label != nullptr) { + String content_ = getEndTemplate(); + content_.replace("{b}", this->label); + content_.replace("{i}", this->getId()); + bool completed_ = outputCallback(content_.c_str(), content_.length()); + if (!completed_) { + //Serial.println("Rendering interrupted during end template, saving state."); + return completed_; + } + } + + _currentItem = nullptr; + _startTemplateSend = false; + //Serial.println("ParameterGroup::renderHtml completed"); + return true; +} + void ParameterGroup::update(WebRequestWrapper* webRequestWrapper) { ConfigItem* current = this->_firstItem; @@ -295,8 +344,7 @@ TextParameter::TextParameter( this->customHtml = customHtml; } -void TextParameter::renderHtml( - bool dataArrived, WebRequestWrapper* webRequestWrapper) +void TextParameter::renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper) { String content = this->renderHtml( dataArrived, @@ -304,6 +352,15 @@ void TextParameter::renderHtml( webRequestWrapper->arg(this->getId())); webRequestWrapper->sendContent(content); } + +bool TextParameter::renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper, HtmlChunkCallback outputCallback) { + String content = this->renderHtml( + dataArrived, + webRequestWrapper->hasArg(this->getId()), + webRequestWrapper->arg(this->getId())); + return outputCallback(content.c_str(), content.length()); +} + String TextParameter::renderHtml( bool dataArrived, bool hasValueFromPost, String valueFromPost) { diff --git a/src/IotWebConfParameter.h b/src/IotWebConfParameter.h index b5cf265..1238918 100644 --- a/src/IotWebConfParameter.h +++ b/src/IotWebConfParameter.h @@ -38,6 +38,8 @@ const char IOTWEBCONF_HTML_FORM_SELECT_PARAM[] PROGMEM = const char IOTWEBCONF_HTML_FORM_OPTION[] PROGMEM = "\n"; +typedef std::function HtmlChunkCallback; + namespace iotwebconf { @@ -90,7 +92,7 @@ class ConfigItem * The webRequestWrapper->sendContent() method should be used in the implementations. */ virtual void renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper) = 0; - + virtual bool renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper, HtmlChunkCallback outputCallback) = 0; /** * New value arrived from the form post. The value should be stored in the * in this config item. @@ -141,13 +143,16 @@ class ParameterGroup : public ConfigItem virtual void loadFromJson(JsonObject jsonObject) override; #endif + void renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper) override; + bool renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper, HtmlChunkCallback outputCallback) override; + protected: int getStorageSize() override; void storeValue(std::function doStore) override; void loadValue(std::function doLoad) override; - void renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper) override; + void update(WebRequestWrapper* webRequestWrapper) override; void clearErrorMessage() override; void debugTo(Stream* out) override; @@ -163,6 +168,10 @@ class ParameterGroup : public ConfigItem virtual String getEndTemplate() { return FPSTR(IOTWEBCONF_HTML_FORM_GROUP_END); }; ConfigItem* _firstItem = nullptr; + ConfigItem* _currentItem = nullptr; + bool _startTemplateSend = false; + bool _continueRendering = false; + size_t _currentStringPos = 0; ConfigItem* getNextItemOf(ConfigItem* parent) { return parent->_nextItem; }; friend class IotWebConf; // Allow IotWebConf to access protected members. @@ -253,10 +262,10 @@ class TextParameter : public Parameter const char* customHtml; protected: - virtual String renderHtml( - bool dataArrived, bool hasValueFromPost, String valueFromPost); + virtual String renderHtml(bool dataArrived, bool hasValueFromPost, String valueFromPost); // Overrides virtual void renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper) override; + virtual bool renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper, HtmlChunkCallback outputCallback) override; virtual void update(String newValue) override; virtual void debugTo(Stream* out) override; /** @@ -478,8 +487,7 @@ class TimeParameter : public TextParameter { } protected: - virtual String renderHtml( - bool dataArrived, bool hasValueFromPost, String valueFromPost) override + virtual String renderHtml(bool dataArrived, bool hasValueFromPost, String valueFromPost) override { return TextParameter::renderHtml("time", hasValueFromPost, valueFromPost); }; diff --git a/src/IotWebConfTParameter.h b/src/IotWebConfTParameter.h index aab28d2..077a28b 100644 --- a/src/IotWebConfTParameter.h +++ b/src/IotWebConfTParameter.h @@ -385,8 +385,7 @@ class InputParameter : virtual public ConfigItemBridge ConfigItemBridge::ConfigItemBridge(id), label(label) { } - virtual void renderHtml( - bool dataArrived, WebRequestWrapper* webRequestWrapper) override + virtual void renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper) override { String content = this->renderHtml( dataArrived, @@ -395,6 +394,14 @@ class InputParameter : virtual public ConfigItemBridge webRequestWrapper->sendContent(content); } + virtual bool renderHtml(bool dataArrived, WebRequestWrapper* webRequestWrapper, HtmlChunkCallback outputCallback) override { + String content = this->renderHtml( + dataArrived, + webRequestWrapper->hasArg(this->getId()), + webRequestWrapper->arg(this->getId())); + return outputCallback(content.c_str(), content.length()); + } + const char* label; /**