WiFi Basics with ESP32

How to connect your ESP32 to WiFi and make network requests

WiFi is the ESP32's superpower. While many microcontrollers can read sensors and blink LEDs, the ESP32 can do all of that and send data to the internet, receive commands from a server, or host its own web page -- all for under five dollars. In this article, you will learn how to connect your ESP32 to a WiFi network and make your first HTTP request.

🔗Connecting to WiFi (Station Mode)

The most common WiFi use case is Station mode (STA): your ESP32 connects to an existing WiFi network, just like your phone or laptop does.

Here is the minimal code to connect:

#include <WiFi.h>

const char* ssid = "YourNetworkName";
const char* password = "YourPassword";

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

  Serial.printf("Connecting to %s", ssid);

  WiFi.begin(ssid, password);

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

  Serial.println("\nConnected!");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // Your code here
}

Upload this sketch, open the Serial Monitor at 115200 baud, and you should see something like:

Connecting to YourNetworkName......
Connected!
IP address: 192.168.1.47

That IP address means your ESP32 is on the network and reachable by other devices.

🔗What Each Part Does

CodePurpose
#include <WiFi.h>Includes the ESP32 WiFi library (built into the ESP32 Arduino core)
WiFi.begin(ssid, password)Starts the connection process
WiFi.status()Returns the current connection status
WL_CONNECTEDConstant indicating a successful connection
WiFi.localIP()Returns the IP address assigned by your router

🔗WiFi Modes

The ESP32 supports three WiFi modes:

ModeDescriptionUse Case
Station (STA)Connects to an existing networkSending sensor data to the internet
Access Point (AP)Creates its own WiFi networkConfiguration portal, direct device-to-device
STA + APBoth at the same timeConnect to internet while serving a config page

🔗Access Point Mode

In AP mode, the ESP32 creates its own WiFi network that other devices can join. This is useful when there is no existing network available, or when you want to set up a configuration portal:

#include <WiFi.h>

const char* ap_ssid = "ESP32-Setup";
const char* ap_password = "12345678";  // Must be at least 8 characters

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

  WiFi.softAP(ap_ssid, ap_password);

  Serial.println("Access Point started!");
  Serial.print("AP IP address: ");
  Serial.println(WiFi.softAPIP());
}

void loop() {
  // Serve a web page, handle configuration, etc.
}

When this runs, you will see a new WiFi network called "ESP32-Setup" appear on your phone or laptop. The ESP32's IP in AP mode is usually 192.168.4.1.

Tip: AP mode is commonly used for initial setup -- the ESP32 starts in AP mode, serves a web page where you enter your home WiFi credentials, then switches to Station mode to connect to your network. Many commercial IoT devices work this way.

🔗Making HTTP Requests

Once connected to WiFi, the ESP32 can talk to web servers just like a browser. The HTTPClient library makes this straightforward.

🔗HTTP GET Request

This example connects to WiFi and fetches data from a public API:

#include <WiFi.h>
#include <HTTPClient.h>

const char* ssid = "YourNetworkName";
const char* password = "YourPassword";

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

  // Connect to WiFi
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nConnected!");
}

void loop() {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;

    http.begin("http://httpbin.org/ip");  // Public test API
    int httpCode = http.GET();

    if (httpCode > 0) {
      Serial.printf("HTTP response code: %d\n", httpCode);
      String payload = http.getString();
      Serial.println(payload);
    } else {
      Serial.printf("HTTP request failed: %s\n",
                     http.errorToString(httpCode).c_str());
    }

    http.end();  // Free resources
  }

  delay(10000);  // Wait 10 seconds before next request
}

This fetches your ESP32's public IP address from httpbin.org and prints it to the Serial Monitor.

🔗HTTP POST Request

To send data to a server (for example, a sensor reading to a logging service):

void sendSensorData(float temperature) {
  if (WiFi.status() != WL_CONNECTED) return;

  HTTPClient http;
  http.begin("http://yourserver.com/api/data");
  http.addHeader("Content-Type", "application/json");

  String json = "{\"temperature\":" + String(temperature, 1) + "}";
  int httpCode = http.POST(json);

  if (httpCode > 0) {
    Serial.printf("POST response: %d\n", httpCode);
  } else {
    Serial.printf("POST failed: %s\n",
                   http.errorToString(httpCode).c_str());
  }

  http.end();
}

🔗Checking Signal Strength

The WiFi.RSSI() function returns the Received Signal Strength Indicator in dBm. This is useful for diagnosing connectivity issues or choosing the best location for your device:

void printSignalStrength() {
  int rssi = WiFi.RSSI();
  Serial.printf("Signal strength: %d dBm", rssi);

  if (rssi > -50) {
    Serial.println(" (Excellent)");
  } else if (rssi > -60) {
    Serial.println(" (Good)");
  } else if (rssi > -70) {
    Serial.println(" (Fair)");
  } else {
    Serial.println(" (Weak - consider moving closer to router)");
  }
}
RSSI RangeSignal Quality
-30 to -50 dBmExcellent
-50 to -60 dBmGood
-60 to -70 dBmFair
-70 to -80 dBmWeak
Below -80 dBmUnreliable

🔗Handling Disconnections

WiFi connections are not permanent -- routers restart, signals drop, interference happens. A robust project should handle disconnections gracefully:

#include <WiFi.h>

const char* ssid = "YourNetworkName";
const char* password = "YourPassword";

unsigned long lastReconnectAttempt = 0;
const unsigned long reconnectInterval = 5000;  // Try every 5 seconds

void connectToWiFi() {
  Serial.printf("Connecting to %s", ssid);
  WiFi.begin(ssid, password);

  // Wait up to 10 seconds for connection
  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 20) {
    delay(500);
    Serial.print(".");
    attempts++;
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\nConnected!");
    Serial.print("IP: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("\nConnection failed.");
  }
}

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

  WiFi.mode(WIFI_STA);
  WiFi.setAutoReconnect(true);  // ESP32 will try to reconnect automatically
  connectToWiFi();
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    unsigned long now = millis();
    if (now - lastReconnectAttempt > reconnectInterval) {
      lastReconnectAttempt = now;
      Serial.println("WiFi disconnected. Reconnecting...");
      connectToWiFi();
    }
  }

  // Your main code here -- check WiFi.status() before making requests
}

Tip: WiFi.setAutoReconnect(true) tells the ESP32 to automatically try to reconnect when the connection drops. The manual reconnection logic above acts as a fallback in case auto-reconnect does not succeed.

🔗A Note on Credentials

In these examples, the WiFi SSID and password are hardcoded directly in the source code. This is perfectly fine for learning and personal projects. However, for anything you plan to share or publish:

  • Do not commit WiFi credentials to public repositories.
  • Consider storing credentials in a separate config.h file that you add to .gitignore.
  • For a more polished approach, use the AP mode configuration portal described earlier to let users enter their own credentials.

A simple config.h approach:

// config.h (do not commit this file)
#define WIFI_SSID "YourNetworkName"
#define WIFI_PASSWORD "YourPassword"
// main sketch
#include "config.h"
#include <WiFi.h>

void setup() {
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  // ...
}

🔗A Note on ADC2 and WiFi

If you are using analog input pins while WiFi is active, be aware that ADC2 (GPIOs 0, 2, 4, 12, 13, 14, 15, 25, 26, 27) cannot be used while WiFi is on. The WiFi driver uses the ADC2 hardware internally.

If you need analog readings while connected to WiFi, use ADC1 pins (GPIOs 32, 33, 34, 35, 36, 39). These work fine alongside WiFi.

Warning: This is a hardware limitation, not a software bug. If your analog readings return 0 or garbage values while WiFi is connected, check whether you are using an ADC2 pin.

🔗Complete Example: WiFi Weather Logger

Here is a more complete example that ties together the concepts from this article -- connecting to WiFi, handling reconnection, and making periodic HTTP requests:

#include <WiFi.h>
#include <HTTPClient.h>

const char* ssid = "YourNetworkName";
const char* password = "YourPassword";

unsigned long lastRequestTime = 0;
const unsigned long requestInterval = 30000;  // Every 30 seconds

void connectToWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  Serial.print("Connecting to WiFi");
  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 20) {
    delay(500);
    Serial.print(".");
    attempts++;
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.printf("\nConnected! IP: %s | RSSI: %d dBm\n",
                  WiFi.localIP().toString().c_str(),
                  WiFi.RSSI());
  } else {
    Serial.println("\nFailed to connect.");
  }
}

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

  connectToWiFi();
}

void loop() {
  // Reconnect if needed
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFi lost. Reconnecting...");
    connectToWiFi();
    return;
  }

  // Make periodic requests
  unsigned long now = millis();
  if (now - lastRequestTime >= requestInterval) {
    lastRequestTime = now;

    HTTPClient http;
    http.begin("http://httpbin.org/ip");
    int httpCode = http.GET();

    if (httpCode == 200) {
      Serial.println("Response: " + http.getString());
    } else {
      Serial.printf("Request failed (code %d)\n", httpCode);
    }

    http.end();
  }
}

🔗What's Next?

HTTP requests are useful, but for IoT applications you often need something lighter, faster, and more suitable for real-time communication. In the next article, we will learn about MQTT -- the lightweight messaging protocol that is the backbone of most IoT systems.