Browser based configuration of ESP8266 with many parameters?

I have searched the web for a way to add a web configuration page to my ESP8266 device (ESP-07S).
I need it to be always accessible, so password protection for saving changes is a must.

It also needs to set a lot more than the SSID plus password of a station mode connection, for example this device will be running either in station or AP mode in normal operation and it supplies a number of functions that all need to be configurable.
I cannot use a button or such to switch to config mode because once installed these devices are pretty much inaccessible except via WiFi.

So it seems like WiFiManager is not going to cut it by the looks of the pages I have read. It seems to have several properties I do not want:

  • Only deals with SSID/Password
  • Is designed for an ESP that runs in AP mode only for configuration otherwise in station mode
  • Config page only available when it detects that it is not able to connect to a WiFi network
  • Built-in automatic switchover to config mode

Currently I have a configuration TCP server set up on the ESP but it is not a webserver so it needs a special PC tool to connect and show/change the settings. I would rather like to have a built-in config webpage because of ease of access through a browser. Then the config page will be tightly connected to the actual parameters needed by the application version in the same sketch. So an external tool needs not be updated every time the sketch changes...

My config server reads the config data from a struct stored in EEPROM and the tool can read it over the network and display on the screen. When a change is made it can save it back to EEPROM (on command to the ESP). The changes are applied at reboot of the ESP. But whenever changes are done to the sketch the tool also needs to be updated....

Is there any generic type of configuration system I can use? Or do I have to re-invent the wheel fully?
I do not really know how to create a web form on the ESP that can handle user input like a regular website form.
But I do know how to do this in Apache using PHP scripts as handlers for a form, but this is of course not possible in an ESP...
Ideally I would like to use a custom web form that is populated with data from the config struct and uses a submit button for each parameter shown. Clicking this shall change the particular value in the temp struct on the ESP without switching the page.
Then also a "Save" button that requires a password and which when activated tells the ESP to save the changed struct to EEPROM and restart.
The password can be required to show the page too if that simplifies things.

Is anything like this available already?

WiFi manager could be looked at as an example of what you might want to do.

I had a look at the howto's I found about WiFiManager and it seems like it does not do what I want but instead it does what I do not want....
I want a config page available at all times (with a login to view) and it shall not interfere with the boot-up connectivity, because I have my own code for that. In fact it should not mess with the startup at all. Everything about that is controlled by the config struct which is read from EEPROM at startup.

Since I already have a config server in place which it needs my special configuration Windows program, I now wanted to add an on-board config page that will be easier to use and will be compatible with whatever developments I do on the application itself...
All I want (which for me is the hard point) is to serve up a config page I can hard-code in progmem as a const string or such.
The page must have boxes for all my parameters, some of which are selectors with limited allowed values.
All of these must be populated with the current set of parameters in my config struct.
Then when the client clicks submit buttons for the various parameters the current value should be sent to the server, which will store it in its temporary copy of the config struct.
Finally when the client clicks the "Write" button the temp struct as it now exists shall be written to EEPROM (I have functions to read/write this struct already).

I went to the GitHub location for WiFiManger and looked at WiFiManager.cpp, but I could not make heads or tails out of that since I am not a C++ programmer. I have programmed embedded systems in Ansi-C but mostly I have 23 years experience with Object Pascal. But never ever programmed C++.....

I also had a look at example OnDemandConfigPortal.ino without making much of it...

WiFiLink firmware has a configuration Web Panel. copy and modify. I can help.

Thanks,
I have downloaded the content of the data dir (comment mentions webpanel).
Actually I could not download (could not find a download link) so I have copied the sources into a local editor and saved each file separately under its name, including the images dir.
I could show the index.html file in my web browser and it looks OK, but the source for this page is really complex...

How do I actually use this?
Due to the size of the files they must be stored somewhere in the ESP file system (I have never used that before)...

on github the green button has download zip

there is WebServer.ino and the main sketch is ArduinoFirmwareEsp.ino. Configuration.h/cpp manages the config file but the implementation is not nice.

I had already navigated down the tree until I found what I wanted to download.
The green button is at the top of the page tree, but I now found it....

Another problem I have is that I have not used json stuff before.
My current data reside in a packed struct, which is stored in EEPROM at address 0.

typedef struct __attribute__((__packed__))
{
  unsigned int checksum;
  char sta_ssid[32];   //SSID to connect to in station mode
  char sta_passwd[32]; //SSID connection password
  byte addr[4];  //IP address in AP mode and in sataion mode if bypassing DHCP
  long baud;     //Serial port baudrate, max 38400
  unsigned int tcpport;  //Serial bridge listening TCP port
  byte mode; //WIFI_OFF = 0, WIFI_STA = 1, WIFI_AP = 2, WIFI_AP_STA = 3
  byte wichannel;  //AP Channel number to use 1..13, if set to 0 = use auto  settings
  byte hidden;  //AP SSID hidden or not (hidden = 1)
  byte fixedaddress;  //Use fixed address in STA mode instead of DHCP
  char updateuser[20];    //Login for the web firmware update function
  char updatepwd[20];    //Password fr the web firmware update function
  byte numsensors;    //Supported DHT sensors bitmapped (0..16)
  unsigned int dhtinterval;  //Measure interval for DHT sensors (in minutes)
  char host[12];        //For setting the network hostname
  char ap_ssid[32];        //Separate storage for AP SSID
  char ap_passwd[32];    //Separate storage for AP passwd
  byte reserved[57]; //For future expansion
} ESPConfiguration;  // Total Size: 256 bytes

These values are either strings (char arrays) or numbers, but there are restrictions on the numbers in some cases like baud, mode, wichannel, hidden, fixedaddress, numsensors and these must be observed in the config page. My solution in the windows application is to put them as dropdown lists (baud, mode or checkboxes (true/false). For wichannel and numsensors I rely on the ESP to reject a setting that is off range.

How can such a thing be accommodated?

I have put together a config webpage (as of now only displaying the form, no real action yet), which shows how I envision it to look like.
I could put this page source as a string in an h file like I have seen done in a few examples, but how do I populate it with the current data from the active config struct?
And how do I retrieve the submitted data in the ESP webserver for parsing in Arduino?
In a normal case I would have a server side php script to handle this by setting the form action to point to the PHP script.
The page I have created is using method "get", which puts all the form data into the URL sent to the webserver.
Is there some good Arduino function to retrieve the URL and parse it for the known names?
(Without resorting to Json, which I don't understand)

you can use eeprom. see how WebServer.ino works and how it interacts with Java Script.

I recommend you to create a separate test project with WiFiLink source code, compile it and upload and test it. You will need SPIFFS and SPIFFS Upload plugin for Arduino IDE (I use Arduino IDE for this, because to setup it in Eclipse is complicated). Instructions about SPIFFS are in README for the firmware.

If it runs as is, then remove the ComLogic things from the firmware source. Test again. Then for example change how configuration is stored. Try to chage the pages etc

I am trying to make a simpler and not so general sketch function to begin with.
I got some ideas from this sketch on Github.
And from another example I got the suggestion to put the definition of the webpage body into a header file for simpler editing and not to clutter up the main source file too much.
So now I have this in the index_body_html.h file (abbreviated):

const char INDEX_BODY_HTML[] =
"<body>"
    "<div class=\"container\">"
        "<h1 style=\"text-align: center;\">SS AP Wifi Details</h1>"
        "<form method=\"get\" action=\"post.html\">"
            "<fieldset>"
                "<legend>Station mode connection</legend>"
                "<div class=\"field-group\">"
                    "<label>STA SSID</label>"
                    "<input name=\"sta_ssid\" type=\"text\" value=\"**sta_ssid**\" length=32>"
                    "<label>STA Password</label>"
                    "<input name=\"sta_password\" type=\"text\" value=\"**sta_password**\" length=64>"
                    "<input name=\"fixed_address\" type=\"checkbox\" value=\"**fixed_address**\"> Fixed IP address
"
                "</div>"
            "</fieldset>"
....lots more text....
        "</form>"
    "</div>"
"</body>"
"</html>";

And in my main source file I have this:

#include "head_html.h"   //This holds the source for the head part of the webpage
#include "index_body_html.h"   //This holds the source for the body part of the webpage

String webpagesrc;  //My webpage text source to be sent to the caller

void ComposeWebPage()  //Replace placeholders in template with current data from ESPConf struct
{
    webpagesrc = INDEX_BODY_HTML;  //Flagged as unknown...
    webpagesrc.replace("**ap_ssid**", ESPConf.ssid);  //ESPConf.ssid is a char[32] array...
    webpagesrc.replace("**sta_password**", ESPConf.passwd);  //As is this..
    ....
}

The idea is to use the template from the header file as a source for the String variable webpagesrc, and then use the replace method to exchange the placeholders for the actual existing values from the ESPConf struct.

Then when all is done I want to add in the templated header (including a style section) to the start of webpagesrc.
This header is in another h file in the same way as the body shown above.

When I code this in Sloeber IDE the name INDEX_BODY_HTML gets a red wiggly underline and it seems like the IDE cannot find it even though it is defined in the h file included just a few lines above...
Obviously I am doing something illegal here concerning assigning the webpagesrc String variable a value from the const char array.

Question:
What is the proper syntax to be used in order to assign const text to a String variable so I can perform the replacements?
And how do I make the template text available to the main source file?

The Sloeber IDE is a bit "strange". I had to save both the h files and the cpp file I was working in, then the wiggly line disappeared and it was OK with finding the data. So I could move on.

Answers:
To assign the declared const text to a string variable and replacing placeholders for variables, this works:

#include "head_html.h"
#include "index_body_html.h"

String webpagesrc = ""; //A global variable...

void ComposeWebPage()
{
    long int i;
    String tmp = "";
    long int baud[6] = {38400, 19200, 9600, 4800, 2400, 1200};

    //Load predefined templates from header files
    webpagesrc = HEAD_START_HTML;
    webpagesrc += STYLE_HTML;
    webpagesrc += HEAD_END_HTML;
    webpagesrc += INDEX_BODY_HTML;

    //Replace placeholders for strings:
    webpagesrc.replace("**ap_ssid**", ESPConf.ap_ssid);
    webpagesrc.replace("**ap_password**", ESPConf.ap_passwd);
    webpagesrc.replace("**sta_ssid**", ESPConf.sta_ssid);
    webpagesrc.replace("**sta_password**", ESPConf.sta_passwd);
    webpagesrc.replace("**hostname**", ESPConf.host);
    .....
    //Replace placeholders for Numbers
    webpagesrc.replace("**apip1**", String(ESPConf.addr[0]));
    webpagesrc.replace("**apip2**", String(ESPConf.addr[1]));
    webpagesrc.replace("**apip3**", String(ESPConf.addr[2]));
    webpagesrc.replace("**apip4**", String(ESPConf.addr[3]));
    webpagesrc.replace("**tcpport**", String(ESPConf.tcpport));
    webpagesrc.replace("**dht_interval**", String(ESPConf.dhtinterval));
    webpagesrc.replace("**dht_map**", String(ESPConf.numsensors));
    .....

I was prepared for warnings etc concerning the replace function but using String(value) took care of that.
I made a debug print of the webpage to the serial port inside setup(), so I could capture the generated html and put it into a file for checking that it shows the correct page and it does!

Now I have "just" to handle the serving of this page on a tcp port (maybe 8080) and handle the submit sting being returned with all the variables set. But there are many how-to pages outlining serving out a webpage so that should not be a problem,
The main concern here is how to extract the parameters from the returned string....

use the ESP8266WebServer library

It is already included in the device code since I have a function to update firmware via the network.
So far I have not used it to create a webserver with viewable pages, though, and not parsing any returned parameters in the URL either.
My form submit looks like this (following he page URL):

?sta_ssid=CompanyLAN&sta_password=CompanyPwd&ap_ssid=SS4678&ap_password=SS0146789&ssid_hidden=on&apip1=192&apip2=168&apip3=211&apip4=1&hostname=tcpuart25&wifimode=0&wifichannel=7&baud=38400&tcpport=2101&dht_map=7&dht_interval=60&save_passwd=somepwd

So following the ? there are a list of identifier=value items separated by & characters.

I have seen commands like:
server.hasArg("identifier")
and
server.Arg("identifier"
which I guess I can use as long as I can direct the code to extract the submit response....

the library WebServer will parse the form data and make it available as getParam

I am using ESP8266WebServer and it has different methods:

server.hasArg(identifier)
server.arg(identifier)

But that is a minor difference, I think.
Notice my error previously, the second command is arg() not Arg().
(Used to case insensitive Pascal...)

yes, sorry, the ESPAsyncWebServer has "params"

Back again...
I have created the basic framework to reach a config page as shown before and I can view it in a browser and when I click submit the handler for processing is activated as shown by my debug messages!
The response to a valid and an illegal password is also correct, the proper acknowledge page is shown.

So now I just have to dig out the remaining parameters from the submit and repopulate the config struct and save it to EEPROM. The password is the last item in the parameter list so I think I will be good.
Not difficult, just a bit tedious...

@Juraj, thanks for your support and suggestions!

A follow-up question:
If a checkbox is unchecked then the corresponding value will not be present in the GET URL...
What will the result of server.arg(identifier) be in such a case? Will it result in an empty string, "0" or what?

I added debug code to check what is returned from checkboxes.
Turns out to be nothing if the box is unchecked, i.e. not even the identifier.
When it is checked the browser sends "on" to the server....
I had thought it would send numbers 0 or 1, but this is not the case.

Anyway it is now completed and I have a web based configuration function on board. :slight_smile:

use hasArg for checkbox

Good suggestion!

		if (webConfigServer.hasArg("fixedaddress"))
			ConfTmp.fixedaddress = 1;
		else
			ConfTmp.fixedaddress = 0;