Share on facebook
Share on twitter
Share on linkedin
Share on reddit
Share on email

ESP32 Using SmartConfig

Changing Wi-Fi credentials in code for your ESP32 based IoT project is frustrating, right?

As most of us, either hard code Wi-Fi credential or will use famous Wi-Fi manager.

Apart from this, there is a method known as ESP-Touch, and it works on SmartConfig technology developed by TI.

We will explore SmartConfig technology, and you will be amazed as it is super simple to use and lightweight.

We will be using Arduino IDE for programming ESP32.

Project Summary

This tutorial will cover how to use the ESP-Touch protocol with your ESP32 based IoT projects/devices.

Using ESP-Touch, you will no longer need to hard code Wi-Fi credentials as you can easily change it whenever you want.

We will be using the Espressif app name as EspTouch: SmartConfig for ESP8266, ESP32.

By using this app, we can easily configure our ESP32 device with a new Wi-Fi credential.

ESP32 using Smart config using ESP-touch app flow chart

We will build an ESP32 project to store Wi-Fi credentials in EEPROM memory on a successful configuration.

Additionally, we will use the onboard Boot button on ESP32 as a reset button for erasing the stored Wi-Fi credentials and configuring a new one.

Here is the Tutorial breakdown:

About ESP-Touch Protocol

ESP-Touch protocol uses a SmartConfig technology. 

The SmartConfigTM is a technology developed by TI to connect a new Wi-Fi-based IoT device to a Wi-Fi network. 

It uses a mobile app to broadcast the network credentials from a smartphone, or a tablet, to an un-provisioned Wi-Fi device.

The major advantage of using ESP-Touch is that there is no need to create an Access Point (AP) with a known SSID or Password in ESP32.

Therefore ESP-Touch protocol provides a seamless way to configure Wi-Fi devices connecting to a router. It is very user-friendly when it comes to headless systems. It only takes few clicks on your smartphone.

 IoT device is not connected to the network initially, and the ESPTOUCH application cannot send any information to the device directly. With the ESP-TOUCH communication protocol, a device with Wi-Fi access capabilities, such as a smartphone, can send a series of UDP packets to the Wi-Fi Access Point (AP), encoding the SSID and password into the Length field of each of these UDP packets. The IoT device can then reach the UDP packets, obtaining and parsing out the required information. As per the ESP-Touch user guide, the data packet structure looks like this. 

ESP touch data packet structure for smartconfig

 And the protocol itself is lightweight compared to the Wi-Fi manager as the Wi-Fi manager requires a webpage code to be stored on device memory.

Prerequisites

We will use Arduino IDE for programming our ESP32 board. 

If you are not familiar with Arduino IDE, then you can check our guide on

❑ Getting started with Arduino IDE

For programming ESP32 using Arduino IDE, we will need to add the ESP32 board package in Arduino IDE. Follow our guide.

❑ Installing ESP32 in Arduino IDE

Skip the above steps if you have already done it before.

Additionally, we will need to download an Espressif app name as EspTouch: SmartConfig for ESP8266, ESP32 for Android, or Espressif Esptouch for apple.

ESP Touch app download from play store on a android mobile

And if you are planning to develop your mobile application, then don’t worry as Espressif has provided all support. Have a look at the following-

Basic WiFiSmartConfig example

ESP32 package comes with a basic WiFiSmartConfig example for us.

Let us understand this example first. 

You can navigate to this example at 

File > Examples > WiFi > WiFiSmartConfig. 

Arduino IDE opening ESP32 SmartConfig example code

Note:- The example path is only visible when selecting the proper ESP32 board in Arduino IDE.

Here is the example code-

 
#include "WiFi.h"

void setup() {
  Serial.begin(115200);

  //Init WiFi as Station, start SmartConfig
  WiFi.mode(WIFI_AP_STA);
  WiFi.beginSmartConfig();

  //Wait for SmartConfig packet from mobile
  Serial.println("Waiting for SmartConfig.");
  while (!WiFi.smartConfigDone()) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("SmartConfig received.");

  //Wait for WiFi to connect to AP
  Serial.println("Waiting for WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("WiFi Connected.");

  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // put your main code here, to run repeatedly:

}

Upload this example code on your ESP32 board as we can see there is no hard-coded network credential in the example.

ESP32 SmartConfig default example code uploding

After uploading, open the serial monitor and set the appropriate baud rate.
You will see that it is waiting to be configured by SmartConfig, and it will be showing continuous dots once it enters configuration mode.

Arduino IDE serial monitor displays waiting for SamrtConfig configuration

Now open the ESP-Touch app in your mobile device and connect your mobile device to your Wi-Fi router network. In android, it will also ask you to turn on location service for detecting the connected Wi-Fi SSID.

Android mobile turning on location service and connecting to Wi-Fi

It will fetch and display the connected Wi-Fi network SSID and BSSID.

Now you need to enter the password of the connected Wi-Fi network.

ESP Touch app entering Wi-Fi password and displaying connected network SSID and BSSID

Select the Multicast radio button.

ESP-Touch app showing connected Wi-Fi SSID and BSSID. And selecting multicast option

And press the confirm button, you will see a popup like this.

ESP-Touch app shows popup message of configuration

Wait for a while, and you will see a success message in the app along with the connected ESP32 BSSID and Inet Address information.

ESP-touch app showing success message

And, on the serial monitor, you will see a message as SmartConfig received, and now it will be connected to the given Wi-Fi network.

Arduino IDE serial monitor showing smartConfig data received and wifi connected

It’s that simple, and we do not need any stored SSID or Password for ESP Access Point.

The example is not perfect to use right now, as we need to configure it whenever we restart ESP because we are not storing Wi-Fi credentials. Also, ESP will always enter in SmartConfig mode.
We will be modifying the existing code to overcome these issues.

How code works

The first step will be to include a required library for the example.

  • WiFi.h library will take care of all wifi-related tasks like connecting to your Wi-Fi and SmartConfig.
    
#include "WiFi.h"

setup()

Inside the setup function, we will first initialize serial communication to observe data in a serial monitor.

We are using the default baud rate of 115200. But you can change it if you want.

    
Serial.begin(115200);

Start SmartConfig

Before starting SmartConfig, it is mandatory to put ESP into station mode.

Therefore setting Wi-Fi mode as WIFI_AP_STA.

    
WiFi.mode(WIFI_AP_STA);

Now, turn ON SmartConfig by using this command.

    
WiFi.beginSmartConfig();

And now we will be wait in while the loop until SmartConfig data is received. It means that it will stay in an infinite loop until someone configures it again with a mobile app. Therefore, making it a drawback of this particular example.

You will see a continuous dot in the serial monitor when ESP enters in this while loop.

    
  while (!WiFi.smartConfigDone()) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("SmartConfig received.");

Once you successfully configure Wi-Fi credentials, it will automatically try to connect to the given Wi-Fi credentials.

It will enter in another while loop until it gets connected to Wi-Fi.

    
  Serial.println("Waiting for WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

After connection, we will be serial printing the Wi-Fi connected message along with the IP address.

    
  Serial.println("WiFi Connected.");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

Wala! It is that simple now; I can configure my ESP within 5 seconds.

WiFiConFig With Storage and Reset

Now, let us add a few more functionality to this example so that it becomes more reliable.

In this project, we will store the received Wi-Fi credentials in EEPROM/Flash memory. Therefore, we do not need to configure ESP every time.

Next, we will add a little check like when ESP turns ON; it will retrieve the stored Wi-Fi credentials and connect to the Wi-Fi network.
If it connects successfully, then skip entering into SmartConfig mode.

Additionally, we will use the boot button as a reset button. It will clear the stored Wi-Fi credentials and restart ESP for a new configuration.
You need to press and hold the boot button for more than 3 seconds and release it, and you have successfully reset the configuration.

Here is the complete project code.

 
/*
  Date: 11-08-21
  Code is written by: Dharmik
  Configure ESP32 Wi-Fi parameters using SmartConfig
  Find more on www.TechTOnions.com
*/
#include "WiFi.h"
#include "EEPROM.h"
#define LENGTH(x) (strlen(x) + 1)   // length of char string
#define EEPROM_SIZE 200             // EEPROM size
#define WiFi_rst 0                  //WiFi credential reset pin (Boot button on ESP32)
String ssid;                        //string variable to store ssid
String pss;                         //string variable to store password
unsigned long rst_millis;

void setup() {
  Serial.begin(115200);             //Init serial
  pinMode(WiFi_rst, INPUT);
  if (!EEPROM.begin(EEPROM_SIZE)) { //Init EEPROM
    Serial.println("failed to init EEPROM");
    delay(1000);
  }
  else
  {
    ssid = readStringFromFlash(0); // Read SSID stored at address 0
    Serial.print("SSID = ");
    Serial.println(ssid);
    pss = readStringFromFlash(40); // Read Password stored at address 40
    Serial.print("psss = ");
    Serial.println(pss);
  }

  WiFi.begin(ssid.c_str(), pss.c_str());

  delay(3500);   // Wait for a while till ESP connects to WiFi

  if (WiFi.status() != WL_CONNECTED) // if WiFi is not connected
  {
    //Init WiFi as Station, start SmartConfig
    WiFi.mode(WIFI_AP_STA);
    WiFi.beginSmartConfig();

    //Wait for SmartConfig packet from mobile
    Serial.println("Waiting for SmartConfig.");
    while (!WiFi.smartConfigDone()) {
      delay(500);
      Serial.print(".");
    }

    Serial.println("");
    Serial.println("SmartConfig received.");

    //Wait for WiFi to connect to AP
    Serial.println("Waiting for WiFi");
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }

    Serial.println("WiFi Connected.");

    Serial.print("IP Address: ");
    Serial.println(WiFi.localIP());

    // read the connected WiFi SSID and password
    ssid = WiFi.SSID();
    pss = WiFi.psk();
    Serial.print("SSID:");
    Serial.println(ssid);
    Serial.print("PSS:");
    Serial.println(pss);
    Serial.println("Store SSID & PSS in Flash");
    writeStringToFlash(ssid.c_str(), 0); // storing ssid at address 0
    writeStringToFlash(pss.c_str(), 40); // storing pss at address 40
  }
  else
  {
    Serial.println("WiFi Connected");
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  rst_millis = millis();
  while (digitalRead(WiFi_rst) == LOW)
  {
    // Wait till boot button is pressed 
  }
  // check the button press time if it is greater than 3sec clear wifi cred and restart ESP 
  if (millis() - rst_millis >= 3000)
  {
    Serial.println("Reseting the WiFi credentials");
    writeStringToFlash("", 0); // Reset the SSID
    writeStringToFlash("", 40); // Reset the Password
    Serial.println("Wifi credentials erased");
    Serial.println("Restarting the ESP");
    delay(500);
    ESP.restart();            // Restart ESP
  }
}


void writeStringToFlash(const char* toStore, int startAddr) {
  int i = 0;
  for (; i < LENGTH(toStore); i++) {
    EEPROM.write(startAddr + i, toStore[i]);
  }
  EEPROM.write(startAddr + i, '\0');
  EEPROM.commit();
}


String readStringFromFlash(int startAddr) {
  char in[128]; // char array of size 128 for reading the stored data 
  int i = 0;
  curIn = EEPROM.read(startAddr);
  for (; i < 128; i++) {
    in[i] = EEPROM.read(startAddr + i);
  }
  return String(in);
}

How Code Works

First, we will include all necessary libraries for this project. 

  • WiFi.h library will take care of all wifi-related tasks like connecting to your Wi-Fi and SmartConfig.
  • EEPROM.h library will need to store data to EEPROM/Flash memory of ESP32.
    
#include "WiFi.h"
#include "EEPROM.h"

Defining custom function LENGTH(x) will give us a length of a char string with one incremental. We will use this function later.

And define the EEPROM size required as EEPROM_SIZE.

    
#define LENGTH(x) (strlen(x) + 1)   // length of char string
#define EEPROM_SIZE 200             // EEPROM size

We are using the Boot button of the ESP32 board for resetting the Wi-Fi credential settings. The boot button on the ESP32 board is connected with a  GPIO0 pin and has a pullup resistor.

Therefore we will define WiFi_rst as 0. If you use any other pin for the reset button, you need to add that GPIO number to the WiFi_rst variable.

    
#define WiFi_rst 0                  //WiFi credential reset pin (Boot button on ESP32)

We are defining String variables for retrieving SSID and Password.

Additionally, we will use the rst_millis variable for counting how long the reset button is pressed.

    
String ssid;                        //string variable to store ssid
String pss;                         //string variable to store password
unsigned long rst_millis;

setup()

We will initialize the serial communication with desired baud rate.

    
Serial.begin(115200);             //Init serial

Set the WiFi_rst pin as an input pin.

    
pinMode(WiFi_rst, INPUT);

Now, initialize the EEPROM with pre-defined EEPROM_SIZE.

Once it is initialized, we will read the stored SSID and Passwort as a String at addresses 0 and 40, respectively.

We use a user-defined function named as readStringFromFlash() for reading a string from EEPROM/flash memory.

    
if (!EEPROM.begin(EEPROM_SIZE)) { //Init EEPROM
    Serial.println("failed to init EEPROM");
    delay(1000);
  }
  else
  {
    ssid = readStringFromFlash(0); // Read SSID stored at address 0
    Serial.print("SSID = ");
    Serial.println(ssid);
    pss = readStringFromFlash(40); // Read Password stored at address 40
    Serial.print("psss = ");
    Serial.println(pss);
  }

Using Wi-Fi.begin function for connecting to the Wi-Fi network. We are passing Wi-Fi credentials as a String variable; therefore, we will need to use c_str(), which will returns a const char* that points to a null-terminated string. 

We will add a slight delay so that ESP can connect to the Wi-Fi network.

    
WiFi.begin(ssid.c_str(), pss.c_str());

delay(3500);   // Wait for a while till ESP connects to WiFi

After that delay, we will check that ESP32 is connected to Wi-Fi or not. 

If ESP connects to Wi-Fi, then we will skip the SmartConfig code inside the if condition.

And if it fails to connect with the Wi-Fi, we will init the Wi-Fi Station mode and SmartConfig similarly done in previous example.

    
if (WiFi.status() != WL_CONNECTED) // if WiFi is not connected
  {
    //Init WiFi as Station, start SmartConfig
    WiFi.mode(WIFI_AP_STA);
    WiFi.beginSmartConfig();

Wait for SmartConfig data to be arrived with while loop. Once network credentials have arrived, it will try to connect to that Wi-Fi network.

    
//Wait for SmartConfig packet from mobile
    Serial.println("Waiting for SmartConfig.");
    while (!WiFi.smartConfigDone()) {
      delay(500);
      Serial.print(".");
    }

    Serial.println("");
    Serial.println("SmartConfig received.");
    
//Wait for WiFi to connect to AP
    Serial.println("Waiting for WiFi");
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }

    Serial.println("WiFi Connected.");
    Serial.print("IP Address: ");
    Serial.println(WiFi.localIP());

After Wi-Fi is connected, we will read the connected Wi-Fi SSID and password with the following function.

    
    ssid = WiFi.SSID();
    pss = WiFi.psk();
    Serial.print("SSID:");
    Serial.println(ssid);
    Serial.print("PSS:");
    Serial.println(pss);

And we will store the new credentials by using another user-defined function, writeStringToFlash(). We only need to pass string data along with an address. 

    
    Serial.println("Store SSID & PSS in Flash");
    writeStringToFlash(ssid.c_str(), 0); // storing ssid at address 0
    writeStringToFlash(pss.c_str(), 40); // storing pss at address 40

Loop()

Inside the loop function, we will store the current millis() value in the rst_millis variable as we will use this value as a start time when someone presses the Wi-Fi reset button.

    
  rst_millis = millis();

When we press the Boot button, the while loop condition is satisfied. Hence, the code is stuck inside the loop until the button is released.

    
  while (digitalRead(WiFi_rst) == LOW)
  {
    // Wait till boot button is pressed 
  }

When the button is released immediately, we will check how much time we have pressed the button if time is greater than 3000mS, the if condition is satisfied.

    
  if (millis() - rst_millis >= 3000)

Now we will erase the stored Wi-Fi credentials at addresses 0 and 40 by passing blank values to the writeStringToFlash() function.

    
    Serial.println("Reseting the WiFi credentials");
    writeStringToFlash("", 0); // Reset the SSID
    writeStringToFlash("", 40); // Reset the Password
    Serial.println("Wifi credentials erased");

And finally, we will trigger a software reset to the ESP32 with the following command.

    
    Serial.println("Restarting the ESP");
    delay(500);
    ESP.restart();            // Restart ESP

writeStringToFlash(const char* toStore, int startAddr)

This user-defined function stores string or character array pointer in EEPROM/Flash storage of ESP32.

We need to store it in non-volatile memory; hence data stored is not erased even after power is OFF.

If we look closely at the code of this function, it is simply a for loop. It is executed as per the LENGTH() function input, and as discussed earlier, it will provide the length of a character string.

And we will use EEPROM.write() function to store each byte of character string to a particular address passed and address keep incremented. 

Once for loop is executed, we will save a '\0' as a string termination. And will commit the changes so that it stores them all in memory.

    
void writeStringToFlash(const char* toStore, int startAddr) {
  int i = 0;
  for (; i < LENGTH(toStore); i++) {
    EEPROM.write(startAddr + i, toStore[i]);
  }
  EEPROM.write(startAddr + i, '\0');
  EEPROM.commit();
}

String readStringFromFlash(int startAddr)

This user-defined function reads stored character strings from the desired address in EEPROM/Flash memory.

Here we are initializing the char array name as in[128] its size is 128, which means it can only handle the string length lower than 128. you can increase the size if you need to deal with bigger strings. 

Similar to storing function, it also works with a for loop. It will read all char byte one by one from the startAddr (start address).

And lastly, we will return it in the form of a String.

    
String readStringFromFlash(int startAddr) {
  char in[128]; // char array of size 128 for reading the stored data 
  int i = 0;
  curIn = EEPROM.read(startAddr);
  for (; i < 128; i++) {
    in[i] = EEPROM.read(startAddr + i);
  }
  return String(in);
}

Wrapping Up

We have seen that SmartConfig is a very efficient and straightforward way to configure network credentials in our ESP32 based IoT projects or devices.

And for configuration, ESP32 does not need any connected Wi-Fi network as the Wi-Fi manager requires.

We have tested SmartConfig with a standard Wi-Fi router, and it worked like a charm.

We have also tried this method using a mobile hotspot network, but unfortunately, it does not work.

Therefore if any of the viewers have tried it with a mobile hotspot, leave a comment below. And if you learned something new, then consider subscribing to our weekly newsletter.

Subscribe to our weekly newsletter

Subscribe
Notify of
guest
6 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
sanwartex
sanwartex
Guest
August 25, 2021 8:00 pm

nice work, good to know about this feature.

Alper
Alper
Guest
September 26, 2021 11:10 pm

hello it say there is no library as WIFI.h so i cant get it work. Could you please help me to solve it

Charles Sowers
Charles Sowers
Guest
October 6, 2021 7:30 am

I tried the example loaded with the ESP32 board package. When I run it and try to connect with espTouch it just grinds and grinds and then I get the message “Execute Result: Not found any devices though the screen says there is one device in the device count. Using iOS version.

posts info

Subscribe to our weekly newsletter

STAY IN TOUCH WITH US

Subscribe to our weekly newsletter