ESP32 Set Up Wi-Fi Connection Using Bluetooth


Wi-Fi connection manager using Bluetooth serial, the Preferences library and an enum state machine.

Sometimes you need to remotely connect to an ESP32 over Wi-Fi but you don’t know the IP address or the ESP32 reconnects with a new IP address each time.

The easiest way to find the IP address for an inaccessible board is to transmit it over Bluetooth serial to a mobile phone. However Bluetooth and Wi-Fi don’t co-exist very well on the ESP32 because they share the same radio system. The Bluetooth connection needs to be closed as soon as the Wi-Fi connection starts to be used for data.

In this tutorial and example code you can see how to use use Bluetooth serial to read the IP address and then close the connection so only Wi-Fi is using the radio.

This demonstration application uses an ESP32 based camera board but it can be adapted for other projects where you need to access an ESP32 over Wi-Fi.

There are three parts to the tutorial – uploading the sketch, pairing your phone with the ESP32 and connecting using a serial Bluetooth application.

Upload the Sketch to the ESP32

Copy the code from here into a new Sketch and upload it to your ESP32 board. If you are using the ESP32-CAM, remember to disconnect pin 0 and press reset.

Open the serial monitor so you can check the progress of the steps below.

Connecting a Mobile Phone to the ESP32

I have Android 9 but other mobiles should be very similar.

Go to Settings and select Connected devices:
Android Bluetooth Settings Link

Select Pair new device:
Pair New Device

Select robot01 from the list of Available devices:
Available Devices

Confirm pairing:
Pair Confirm

You should see the device in Currently connected:
Bluetooth Device Connected

Using the Serial Terminal

Install the Serial Bluetooth Terminal app from the Play Store –

Open Serial Bluetooth Terminal and select ‘Devices’ from the menu:
Serial Bluetooth Terminal Devices

Select robot01 from the list to start the Serial Terminal connection:
Choose Bluetooth Device

If this is the first time the ESP32 has connected to this Wi-Fi network or the password has changed then you will see the following output.

Serial terminal connecting to ESP32:
Bluetooth Serial Terminal Connection

ESP32 scanning for Wi-Fi networks:
Bluetooth Serial Terminal WiFi Scan

Select the number for your network SSID:
Bluetooth Serial Terminal SSID

Enter the password for this network:
Bluetooth Serial Terminal Pass

When the ESP32 connects to the Wi-Fi network, the ESP32 IP address is shown and the Bluetooth is disconnected:
Bluetooth Serial Terminal Wi-Fi IP address

If the ESP32 already has the correct connection credentials then just the IP address of the ESP32 will be displayed:
Bluetooth Serial Show IP Address

How does this work?

A few important parts of the code are explained below:

The code uses an ‘enum state machine’. An enum can be thought of as a variable with a fixed number of values such as SCAN_START, SCAN_COMPLETE, SSID_ENTERED, PASS_ENTERED, LOGIN_FAILED

These values are used in a switch statement in the main loop. Functions run or variable values are set based on the current enum value:

    case SCAN_START:
      SerialBT.println("Scanning Wi-Fi networks");
      Serial.println("Scanning Wi-Fi networks");
      SerialBT.println("Please enter the number for your Wi-Fi");
      wifi_stage = SCAN_COMPLETE;

    case SSID_ENTERED:
      SerialBT.println("Please enter your Wi-Fi password");
      Serial.println("Please enter your Wi-Fi password");
      wifi_stage = WAIT_PASS;

    case PASS_ENTERED:
      SerialBT.println("Please wait for Wi-Fi connection...");
      Serial.println("Please wait for Wi_Fi connection...");
      wifi_stage = WAIT_CONNECT;
      preferences.putString("pref_ssid", client_wifi_ssid);
      preferences.putString("pref_pass", client_wifi_password);
      if (init_wifi()) { // Connected to WiFi
        connected_string = "ESP32 IP: ";
        connected_string = connected_string + WiFi.localIP().toString();
        bluetooth_disconnect = true;
      } else { // try again
        wifi_stage = LOGIN_FAILED;

    case LOGIN_FAILED:
      SerialBT.println("Wi-Fi connection failed");
      Serial.println("Wi-Fi connection failed");
      wifi_stage = SCAN_START;

The Sketch uses two Bluetooth callbacks depending on whether Wi-Fi has connected or not:

  if (!init_wifi()) { // Connect to Wi-Fi fails
  } else {

If the ESP32 cannot connect to Wi-Fi then the first callback initialised. This listens for Bluetooth data sent to the ESP32. Depending on the type of data and the current value of the enum, various variables are set and functions run:

void callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
  if (event == ESP_SPP_SRV_OPEN_EVT) {
    wifi_stage = SCAN_START;

  if (event == ESP_SPP_DATA_IND_EVT && wifi_stage == SCAN_COMPLETE) { // data from phone is SSID
    int client_wifi_ssid_id = SerialBT.readString().toInt();
    client_wifi_ssid = ssids_array[client_wifi_ssid_id];
    wifi_stage = SSID_ENTERED;

  if (event == ESP_SPP_DATA_IND_EVT && wifi_stage == WAIT_PASS) { // data from phone is password
    client_wifi_password = SerialBT.readString();
    wifi_stage = PASS_ENTERED;


Alternatively, if the ESP32 has successfully connected to Wi-Fi then a second callback initialises and waits for input from the Bluetooth connection:

void callback_show_ip(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
  if (event == ESP_SPP_SRV_OPEN_EVT) {
    SerialBT.print("ESP32 IP: ");
    bluetooth_disconnect = true;

The final important thing to note in the code is that once the Wi-Fi IP address is known to the user then the Bluetooth should be closed. This happens either when the IP address has been displayed on the mobile phone or when the user connects to the IP in a browser. One example is shown in the code above. Another is shown below when the camera is connected over a websocket:

  if (socket_server.poll()) {

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

scroll to top