Wi-Fi is the decisive argument for the ESP32: a connected object with no external radio module. In a few lines, the board joins a network (station mode) or creates its own (access point mode), then exchanges data — query an API, expose a control web page, publish measurements. It is a capability the classic Arduino does not have, and the heart of what the ESP32 family brings. Wireless links in general are covered in wireless technologies and Wi-Fi. This page gives the ESP32 incarnation of it.

What is it for?

The Wi-Fi of the ESP32 opens three typical uses in a project:

  • Linking the system to the Internet — fetch the time, a weather forecast, a setpoint from an API; send measurements to a server or a dashboard. The board is a client.
  • Offering an interface with no display — the ESP32 hosts a small web page. You drive the system and read its state from a browser, phone or PC. The board is a server.
  • Doing without infrastructure — in access-point mode, the ESP32 creates its own network, which you join directly, with no router or box (field configuration, demonstration).

Warning

Wi-Fi on = ADC2 unavailable. As soon as the Wi-Fi runs, the pins of the ADC2 converter read nothing at all. Every analog sensor of a connected project must sit on ADC1 (GPIO32-39, see configuring the GPIO).

Two modes: station and access point

Everything starts from the WiFi.h library, included in the ESP32 core.

  • Station (STA) — the ESP32 connects to an existing network (your router). This is the usual mode for reaching the Internet.
  • Access point (AP) — the ESP32 creates a network that other devices connect to. Handy for a local configuration.

The two Wi-Fi modes of the ESP32: in station mode (STA) the board joins an existing router; in access-point mode (AP) it creates its own network, which a phone or a PC connects to|640

#include <WiFi.h>
 
const char* ssid = "MonReseau";
const char* motDePasse = "********";
 
void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, motDePasse);            // station mode
  Serial.print("Connecting");
 
  int tentatives = 0;
  while (WiFi.status() != WL_CONNECTED && tentatives < 20) {  // 20 x 500 ms = 10 s max
    delay(500);
    Serial.print(".");
    tentatives++;
  }
  Serial.println();
 
  if (WiFi.status() != WL_CONNECTED) {     // failure: say so, do not freeze
    Serial.println("Connection failed - check the SSID and the password");
    return;
  }
  Serial.print("Connected, IP = ");
  Serial.println(WiFi.localIP());          // address handed out by the router
}
 
void loop() {}

The wait is bounded: after a dozen seconds the board gives up and says so, instead of staying frozen on a mistyped SSID. The examples that follow keep the short form so as not to drown their subject. In a project, take this bounded pattern back.

For access-point mode, two lines are enough: the board creates the network instead of joining it.

#include <WiFi.h>
 
void setup() {
  Serial.begin(115200);
  WiFi.softAP("ESP32-Demo", "motdepasse");   // network created by the board
  Serial.print("Access point up, IP = ");
  Serial.println(WiFi.softAPIP());           // 192.168.4.1 by default
}
 
void loop() {}

You join the ESP32-Demo network from a phone, then open 192.168.4.1 (handy for a demonstration on a bench, with no router or box). The password must be at least 8 characters long: below that, softAP() fails and the network does not show up.

Warning

The ESP32 (apart from the C5) is 2.4 GHz only. It does not connect to a network broadcast on 5 GHz alone. On a dual-band router, check that the 2.4 GHz band is on and that the SSID you target really is the 2.4 GHz network.

Example — Driving a LED from a browser

The most telling use: the ESP32 joins the network, hosts a minimal web page, and drives a LED according to the link clicked. A phone on the same network opens the IP address and commands the board.

Wiring: LED on GPIO16 (see the circuit of configuring the GPIO).

#include <WiFi.h>
#include <WebServer.h>
 
const char* ssid = "MonReseau";
const char* motDePasse = "********";
const int LED = 16;
 
WebServer serveur(80);   // HTTP server on port 80
 
void pageAccueil() {
  String html = "<h1>ESP32</h1>"
                "<p><a href=\"/on\">Allumer</a> | "
                "<a href=\"/off\">Eteindre</a></p>";
  serveur.send(200, "text/html", html);
}
 
void allumer() {
  digitalWrite(LED, HIGH);
  serveur.send(200, "text/html", "LED allumee. <a href=\"/\">Retour</a>");
}
 
void eteindre() {
  digitalWrite(LED, LOW);
  serveur.send(200, "text/html", "LED eteinte. <a href=\"/\">Retour</a>");
}
 
void setup() {
  Serial.begin(115200);
  pinMode(LED, OUTPUT);
 
  WiFi.begin(ssid, motDePasse);
  while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
  Serial.print("\nOpen http://");
  Serial.println(WiFi.localIP());   // the URL to type in the browser
 
  serveur.on("/", pageAccueil);     // map paths -> functions
  serveur.on("/on", allumer);
  serveur.on("/off", eteindre);
  serveur.begin();
}
 
void loop() {
  serveur.handleClient();           // handle requests continuously
}

Upload, open the serial monitor (115200) to read the IP address printed, then type http://<that IP> in a browser on the same network. The page offers two links that switch the LED on and off. You get a control interface with no display and no application in about fifty lines.

Three moments of the same page served by the ESP32 gathered in a single image: at the top the home page at address 192.168.1.31, titled ESP32, with the links Allumer and Eteindre; below, joined by red arrows, the two pages reached by those links — /on which answers LED allumee, /off which answers LED eteinte — each address bar carrying the browser warning Non sécurisé.|500

The browser shows Non sécurisé (not secure) next to the address, on all three pages. That is expected: the page is served over plain HTTP, with no encryption: the ESP32 has no certificate, and the traffic never leaves your local network. Nothing is broken, nothing needs fixing. The warning becomes a real subject the day the board is reachable from outside, or carries anything other than the state of a LED.

Pitfalls

An analog sensor gone mute over Wi-Fi. An analogRead measurement that drops to zero as soon as the connection comes up: the pin is on ADC2. Move the sensor onto ADC1 (GPIO32-39).

A 5 GHz network. The ESP32 (apart from the C5) does not see an SSID broadcast on 5 GHz alone. Turn on, or target, the 2.4 GHz band.

An endless connection loop. The while (WiFi.status() != WL_CONNECTED) blocks for ever if the SSID or the password is wrong. In a project, bound the wait (a counter plus a failure message) rather than freezing the board.

Credentials in clear in the code. An SSID and a password written in the sketch end up in the binary and in Git. For a deliverable, take them out of the code (a configuration file kept out of version control, or a configuration portal).

Brown-out on transmission. Wi-Fi transmission draws current spikes. On a weak USB supply, the voltage sags and the board reboots (Brownout detector was triggered). A clean supply and a clean cable.

A web page that stops answering. Forgetting serveur.handleClient() in loop(), or blocking the loop with a long delay, freezes the server. The loop has to run freely.

Exercises

Exercise 1 — Scanning the networks

On startup, list in the serial monitor every Wi-Fi network detected, with its signal strength (RSSI). Which function of WiFi.h?

Exercise 2 — A status page for a sensor

Change the example so that the web page shows the value of an analog sensor (on GPIO34, ADC1) instead of driving a LED. The value must be up to date on every reload of the page.

Special case — The board as a client (querying an API)

The other direction: the ESP32 goes and fetches a piece of data on the Internet. The HTTPClient library makes a request in a few lines.

#include <WiFi.h>
#include <HTTPClient.h>
 
void requete() {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin("http://exemple.com/api/mesure");  // plain http URL
    int code = http.GET();                         // > 0 = an answer came back
    if (code > 0) {
      Serial.println(http.getString());            // body of the answer
    }
    http.end();
  }
}

For an HTTPS URL (most public APIs today), you need a secure client (WiFiClientSecure) and, strictly speaking, the certificate of the server (a more advanced subject, to be looked up in the Espressif documentation). Internally (sensor to local server), plain HTTP is often enough.

Where it fits in the project

  • Step 4 of the proof-of-concept phase — if the project is a connected object, validating the Wi-Fi connection and a first exchange early (a status page, publishing a measurement) lifts the main uncertainty of the PoC. It is the building block that often justifies choosing the ESP32 over an Arduino.
  • An operating interface — a web page hosted by the board serves as a fallback HMI, or as a field configuration tool, with no dedicated application to develop.

Taking the credentials out of the code and bounding the connection attempts from the prototype onwards keeps a demo from turning into a fragile deliverable (a versioned password, a board frozen if the network changes).

Going further

See also