Introduction: ESP32 Captive Portal to Configure Static and DHCP IP Settings

About: For Remote Supervision

ESP 32 is a device with integrated WiFi and BLE. It is kind of a boon for the IoT projects. Just give your SSID, password and IP configurations and integrate the things into the cloud. But, managing the IP settings and User credentials can be a headache to the user.

What if the User wants to change the WiFi credentials?

What if the user wants to switch the DHCP/Static IP settings?

Flashing the ESP32 everytime is not reliable and not even the solution for these problems. Here in this instructable we will be going to demonstrate.

  • How to create a captive portal.
  • Hosting a web form from the ESP32.
  • Reading and Writing from SPIFFS ESP32.
  • Creating a Soft Access Point and connecting to a station

Step 1: Hardware and Software Specification

Hardware Specification

Software Specification

  • Arduino IDE

Step 2: Creating a Captive Portal

A captive portal is a web page that is displayed to newly connected users t before they are granted broader access to network resources. Here we are serving three web pages to select between DHCP and Static IP Settings. we can define the IP address to ESP in two ways.

  • DHCP IP address- it is a way to dynamically assign the IP address to the device. The ESP's default IP address is 192.168.4.1
  • Static IP address- assigning a permanent IP Adress to our network device. to provide the static IP to the device we need to define the IP address, gateway address, and subnet mask.

In the first webpage, the User is provided with the radio buttons to select between DHCP and Static IP settings. In the next webpage, we have to provide the IP related information to proceed further.

HTML Code

The HTML code for web pages can be found in this Github repository.

You can use any IDE or text editor like Sublime or notepad++ to make HTML web pages.

  • First Create an HTML webpage containing two radio buttons to choose between DHCP and Static IP Settings.
  • Now create the button to submit your response
  • Give some name to radio buttons. The ESP Web server class will take these names as arguments and get the response of the radio buttons using these arguments
  • Now insert a ' SUBMIT ' button to send the response to the device.
  • In the other web pages, we have text boxes. Give the name value and Input type to the text box and add a submit button to ' SUBMIT ' submit the response.
  • Create a ' RESET ' button to reset the content of the text field.
<div>//Radio Button</div><div><div id="radio_select"></div><div><input type="radio" name = "configure" value="dhcp" id="radio_dhcp">DHCP Setting</div><div><p><input type="radio" name = "configure" value="dhcp" id="radio_static">Static IP Setting</p><p></div></p><p>//Input Text Boxes</p><p><input maxlength="30px" type='text' name="ipv4static" placeholder='ip Address' style="width: 400px; padding: 5px 10px ;"  required></p><p><input maxlength="30px" type = "text" name="gateway"  placeholder = "gateway address" style="width: 400px; padding: 5px 10px ;" required></p><p><input maxlength="30px" type = "text" name="subnet"  placeholder= "subnet mask" style="width: 400px; padding: 5px 10px ;" required></p><p>//Submit Button</p><p><INPUT type="submit"></p><p><style></p><p>input[type="submit"]{<br>    background-color: #3498DB; /* Green */
    border: none;
    color: white;
    padding:15px 48px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
}</p><p></style></p><p>//Reset Button</p><p><INPUT type = "reset"></p><p><style></p><p>input[type="submit"]{    background-color: #3498DB; /* Green */<br>    border: none;
    color: white;
    padding:15px 48px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
}</p><p></style></p></div>

Step 3: Getting the Web Response From Web Pages to ESP32

Serving web pages from ESP 32 device is great fun. It can be anything from showing the temperature data in the webpage, turning the led's from the custom webpage or storing the User WiFi credentials through a webpage. For this purpose, ESP 32 uses WebServer Class to server web pages.

  • First, Create an instance of WebServer class at port 80(HTTP port).
  • Now set up the ESP device as softAP. Give the SSID and passkey and assign a static IP to the device.
  • Begin the server.
//*********SSID and Pass for AP**************/
const char *ssidAP = "give SSID";
const char *passAP = "pass key";

//*********Static IP Config**************/
IPAddress ap_local_IP(192,168,1,77); IPAddress ap_gateway(192,168,1,254); IPAddress ap_subnet(255,255,255,0);

//*********SoftAP Config**************/

WiFi.mode(WIFI_AP);

Serial.println(WiFi.softAP(ssidAP,passAP) ? "soft-AP setup": "Failed to connect"); delay(100); Serial.println(WiFi.softAPConfig(ap_local_IP, ap_gateway, ap_subnet)? "Configuring Soft AP" : "Error in Configuration"); Serial.println(WiFi.softAPIP());

//begin the server

server.begin();

  • Create and serve the URL using different callbacks.
  • and handle the client asynchronously using handleClient.
server.on("/", handleRoot);
server.on("/dhcp", handleDHCP);
server.on("/static", handleStatic);
// handle the responses
server.handleClient();
  • To access the web pages. Connect to the AP that you have just created, listed within your WiFi networks. Now, go to the browser, Enter the IP configured by you in the last step and access the webpage.
  • Web server class takes the name given to inputs( 'text','button','radiobutton'etc.) as arguments. It saves the responses of these inputs as arguments and we can get the values or check them using args, arg,hasArg methods.

if(server.args()>0){
for(int i=0; i<=server.args();i++){

Serial.println(String(server.argName(i))+'\t' + String(server.arg(i)));

}

if(server.hasArg("ipv4static") && server.hasArg("gateway") && server.hasArg("subnet")){
staticSet(); }else if(server.arg("ipv4")!= ""){ dhcpSetManual(); }else{ dhcpSetDefault(); }

Step 4: Static IP Configuration

  • So far we have understood how to connect to AP and how to get the values from the input fields of the webpage.

In this step, we will configure the Static IP

  • Select the Static IP Setting and click on Submit button. You will be redirected to the next page.
  • In the next page enter the static IP address, gateway address and subnet Mask this page will be served at "/static" which is handled by handle static callback method.
  • Get the value of text fields using server.arg() method.
String ipv4static = String(server.arg("ipv4static"));

String gateway = String(server.arg("gateway"));

String subnet = String(server.arg("subnet"));
  • Now, these values are serialized into a JSON Format.
  • Then we will write the JSON to SPIFFS.

root["statickey"]="staticSet";

root["staticIP"] = ipv4static;

root["gateway"] = gateway;

root["subnet"] = subnet;

File fileToWrite = SPIFFS.open("/ip_set.txt", FILE_WRITE);

if(root.printTo(fileToWrite)){

Serial.println("--File Written"); }

  • This configuration is saved in SPIFFS. Later, these values are read from SPIFFS.
  • The static IP values are then parsed from JSON.
File file = SPIFFS.open("/ip_set.txt", "r");

while(file.available()){

debugLogData += char(file.read()); }

if(debugLogData.length()>5){

JsonObject& readRoot =jsonBuffer.parseObject(debugLogData);

if(readRoot.containsKey("statickey")){

String ipStaticValue= readRoot["staticIP"];

String gatewayValue = readRoot["gateway"];

String subnetValue = readRoot["subnet"];

Step 5: DHCP Settings

In this step, we will configure the DHCP Settings

  • Select the DHCP Settings from the index page and click on "Submit"
  • You will be redirected to the next page. In the next page enter the IP address or select choose default and click on the "Submit" button to submit the response. This page will be served at "/dhcp" which is handled by handleDHCP callback method. Get the value of text fields using server.arg() method. When clicked in choose default checkbox. the 192.168.4.1 IP will be given to the device.
  • Now, these values are serialized into a JSON Format.

  • Then we will write the JSON to SPIFFS.

JsonObject& root =jsonBuffer.createObject();

root["dhcpManual"]="dhcpManual";

root["dhcpIP"] = "192.168.4.1";

File fileToWrite = SPIFFS.open("/ip_set.txt", FILE_WRITE);

if(root.printTo(fileToWrite)){

Serial.println("--File Written"); }

  • This configuration is saved in SPIFFS. Later, these values are read from SPIFFS.
  • The dhcp IP values are then parsed from JSON.

File file = SPIFFS.open("/ip_set.txt", "r");
while(file.available()){ debugLogData += char(file.read()); } if(debugLogData.length()>5){ JsonObject& readRoot =jsonBuffer.parseObject(debugLogData);

if(readRoot.containsKey("dhcpDefault")){

String ipdhcpValue= readRoot["dhcpIP"];

Serial.println(ipdhcpValue);

dhcpAPConfig();}


Step 6: Saving WiFi Credentials

For now, we have selected the IP configuration. Now we need to save the wifi credentials of the User. To resolve this situation. We have followed this procedure.

  • So now we have our device AP setup in DHCP or Static IP configuration which we had selected from the captive portal mentioned in last steps.
  • Let's say we have selected Static IP configuration.
  • We will configure a softAP at this IP.
  • After reading the values from SPIFFS and parsing these values from JSON. We will configure the softAP at this IP.
  • Convert the IP String into Bytes.

byte ip[4];

parseBytes(ipv4Arr,'.', ip, 4, 10);

ip0 = (uint8_t)ip[0];

ip1 = (uint8_t)ip[1];

ip2 = (uint8_t)ip[2];

ip3 = (uint8_t)ip[3];

IPAddress ap_local(ip0,ip1,ip2,ip3);

//***************Parse bytes from string******************//

void parseBytes(const char* str, char sep, byte* bytes, int maxBytes, int base) {

for (int i = 0; i < maxBytes; i++) {

bytes[i] = strtoul(str, NULL, base);

str = strchr(str, sep);

if (str == NULL || *str == '\0') {

break;

}

str++;

}}


  • Now we will configure the softAP at this IP
Serial.println(WiFi.softAPConfig(ap_localWeb_IP, ap_gate, ap_net) ? "Configuring softAP" : "not connected");               Serial.println(WiFi.softAPIP());
  • Now begin the web server and serve a webpage at this IP. To enter the WiFi Credentials of the User.
  • The webpage consists of two text fields to enter SSID and Password.
  • handleStaticForm is a callback method that serves the webpage.
  • server.handleClient() takes care of the request and responses to and from the webpage.

server.begin();

server.on("/", handleStaticForm);

server.onNotFound(handleNotFound);

STimer = millis();

while(millis()-STimer<= SInterval) {

server.handleClient(); }

  • The HTML form is saved in SPIFFS. we check for the suitable arguments using server.arg(). to get the value of SSID and Password.

File file = SPIFFS.open("/WiFi.html", "r");

server.streamFile(file,"text/html");

file.close();

Step 7: Read and Write From SPIFFS

SPIFFS

Serial Peripheral Interface Flash File System, or SPIFFS for short. It's a light-weight file system for microcontrollers with an SPI flash chip. The onboard flash chip of the ESP32 has plenty of space for your web pages. We have also stored our webpage in Flash System. There are a few steps we need to follow to upload data to spiffs

  • In your Arduino sketchbook directory, create tools directory if it doesn't exist yet
  • Unpack the tool into tools directory (the path will look like /Arduino/tools/ESP32FS/tool/esp32fs.jar)
  • Restart Arduino IDE
  • Open a sketch (or create a new one and save it)
  • Go to sketch directory (choose Sketch > Show Sketch Folder)
  • Create a directory named data and any files you want in the file system there. We have uploaded our HTML page with name webform.html
  • Make sure you have selected a board, port, and closed Serial Monitor
  • Select Tools > ESP8266 Sketch Data Upload. This should start uploading the files into the ESP8266 flash file system. When done, IDE status bar will display SPIFFS Image Uploaded message.
<p>void handleDHCP(){<br>  File  file = SPIFFS.open("/page_dhcp.html", "r");
  server.streamFile(file,"text/html");
  file.close();}</p><p>void handleStatic(){
  File  file = SPIFFS.open("/page_static.html", "r");
  server.streamFile(file,"text/html");
  file.close();}</p>

Writing to SPIFFS

Here we are writing the saved setting to the SPIFFS so that users should not have to go through these steps whenever device resets.

  • Convert the arguments received from the webpage to JSON objects
  • Write this JSON to the .txt file saved in SPIFFS.
           

<p>String ipv4static = String(server.arg("ipv4static"));</p>
String gateway = String(server.arg("gateway"));
           String subnet = String(server.arg("subnet"));
           root["statickey"]="staticSet";
           root["staticIP"] = ipv4static;
           root["gateway"] = gateway;
           root["subnet"] = subnet;
           String JSONStatic;
           char JSON[120];
           root.printTo(Serial);
           root.prettyPrintTo(JSONStatic);
           JSONStatic.toCharArray(JSON,sizeof(JSONStatic)+2);
           File fileToWrite = SPIFFS.open("/ip_set.txt", FILE_WRITE);
           if(!fileToWrite){
              Serial.println("Error opening SPIFFS");
            }
           if(fileToWrite.print(JSON)){
                Serial.println("--File Written");
            }else{
                Serial.println("--Error Writing File");
              } 
              fileToWrite.close();  <br>

Step 8: Overall Code

The Over code for HTML and ESP32 can be found in this Github Repository