Skip to content
Tutorial
12 min read
October 17, 2026

Connect ESP32 to WiFi with MicroPython: Scan, Connect and Reconnect

Connect an ESP32 to Wi-Fi with MicroPython, scan nearby networks, read IP settings, reconnect after outages, and troubleshoot safely.

Connect an ESP32 to Wi-Fi with MicroPython: Scan, Connect, and Reconnect

Connecting an ESP32 to Wi-Fi lets a MicroPython project publish sensor readings, host a small web page, communicate with an MQTT broker, or send data to another device on the local network. The ESP32's Wi-Fi interface is controlled through MicroPython's network module, but exact behavior can differ by chip family, firmware build, and MicroPython version.

This guide covers checking firmware, scanning nearby networks, connecting in station mode, waiting with a timeout, reading network information, handling failures, and reconnecting without locking up the application. Examples use placeholder credentials. Replace them locally, and never publish real passwords, private IP details, or access tokens in a public repository or screenshot.

A Wi-Fi connection is not the same as an internet connection. The board may associate with an access point and receive an IP address while DNS, routing, or an external service remains unavailable. Robust applications should treat these steps separately and keep core sensor or control functions usable if networking fails.

1. Before you start

You need an ESP32 board supported by your MicroPython firmware, a USB data cable, a computer with Thonny or another serial REPL tool, and access to a Wi-Fi network. Confirm that the firmware is built for the exact board or chip family. ESP32 variants can differ in available features, memory, and firmware support.

Many ESP32 boards support 2.4 GHz Wi-Fi, while a typical 5 GHz-only access point will not be suitable. Some routers combine 2.4 GHz and 5 GHz under one network name; if connection fails, confirm that 2.4 GHz is enabled and that the router's security mode is compatible with the firmware. Captive portals, enterprise authentication, MAC filtering, and isolated guest networks can add complications.

Start with a known-good USB cable and verify that the board appears as a serial device. Open the MicroPython REPL and run import network. If the import fails, the firmware may not include expected networking support, or you may not be running MicroPython on the board. Fix firmware and serial communication before debugging the router.

2. Station mode and access-point mode

The ESP32 commonly connects to a router using station mode, represented by network.STA_IF. In station mode, the router manages network access and typically provides an IP address through DHCP. This is the mode used when the ESP32 should join an existing home or lab network.

Access-point mode, represented by network.AP_IF on common MicroPython ports, makes the board create a Wi-Fi network that other devices can join. It is useful for provisioning or a local control interface, but it is not the same as connecting the ESP32 to the internet through a router. Some projects use both modes, which increases complexity and should be implemented according to the board's firmware documentation.

For a first connection test, use station mode only. That keeps setup simple and makes it easier to distinguish Wi-Fi association problems from problems caused by a web server, MQTT client, or another application layer.

3. Scan for nearby networks

Scanning can confirm that the board sees access points in its environment. Run this from the REPL:

import network

wlan = network.WLAN(network.STA_IF)
wlan.active(True)

for item in wlan.scan():
    ssid = item[0].decode("utf-8", "ignore")
    channel = item[2]
    rssi = item[3]
    authmode = item[4]
    print(ssid, "channel=", channel, "RSSI=", rssi, "auth=", authmode)

The exact tuple fields and authentication representation should be confirmed against the documentation for the MicroPython version on your board. A stronger (less negative) RSSI usually indicates a stronger received signal, but the number alone does not guarantee a reliable connection. Interference, antenna orientation, channel congestion, and router configuration also matter.

A scan can take time and may temporarily affect connectivity on some implementations. Avoid scanning continuously in a production loop. If the expected network does not appear, check the 2.4 GHz band, router SSID broadcast settings, distance, antenna, and firmware support before changing credentials.

4. Connect with a timeout

This example activates station mode, requests a connection, and waits for a limited time rather than looping forever:

import network
import time

SSID = "YOUR_WIFI_NAME"
PASSWORD = "YOUR_WIFI_PASSWORD"

wlan = network.WLAN(network.STA_IF)
wlan.active(True)

if not wlan.isconnected():
    wlan.connect(SSID, PASSWORD)

timeout_ms = 15000
start = time.ticks_ms()
while not wlan.isconnected() and time.ticks_diff(time.ticks_ms(), start) < timeout_ms:
    time.sleep_ms(250)

if wlan.isconnected():
    print("Wi-Fi connected")
    print("Network config:", wlan.ifconfig())
else:
    print("Connection timed out")

Use your actual SSID and password only in your local device configuration. Do not commit them to source control. On some firmware builds, repeated connect calls or connection state transitions behave differently, so consult the specific port's documentation if this minimal example does not work.

A timeout is important because a project should not become permanently stuck when the router is offline. After a timeout, the program can continue local sensor work, report a status indicator, and retry later. Check connection state before making network requests.

5. Read the network configuration

Once connected, wlan.ifconfig() commonly returns the IP address, subnet mask, gateway, and DNS server. For example:

if wlan.isconnected():
    ip, subnet, gateway, dns = wlan.ifconfig()
    print("IP address:", ip)
    print("Gateway:", gateway)

The values depend on the local network. An address such as 192.168.1.42 is only illustrative, not a value to hard-code into your project. DHCP leases can change, and the router may assign a different address after reconnect or reboot. If another device must reliably reach the ESP32, use a router reservation or a suitable provisioning strategy rather than assuming the address never changes.

A valid IP address is evidence that the board joined the network and obtained configuration, but it does not prove that DNS or internet access works. Test the actual service the application needs, handle timeouts, and avoid printing sensitive network information in logs that may be shared publicly.

6. Reconnect after Wi-Fi drops

Wi-Fi can drop because the access point restarts, the signal becomes weak, the router changes channels, or the board loses power. A robust application should detect disconnection and retry with a delay instead of calling connect continuously on every iteration.

import time
import network

wlan = network.WLAN(network.STA_IF)
wlan.active(True)

SSID = "YOUR_WIFI_NAME"
PASSWORD = "YOUR_WIFI_PASSWORD"

def ensure_wifi(timeout_ms=10000):
    if wlan.isconnected():
        return True
    try:
        wlan.connect(SSID, PASSWORD)
    except OSError as exc:
        print("Wi-Fi request failed:", exc)
        return False

    start = time.ticks_ms()
    while not wlan.isconnected() and time.ticks_diff(time.ticks_ms(), start) < timeout_ms:
        time.sleep_ms(200)
    return wlan.isconnected()

if ensure_wifi():
    print("Connected:", wlan.ifconfig())
else:
    print("Offline; retry later")

Call the helper at controlled intervals rather than on every fast sensor sample. A larger application can implement exponential backoff, where the delay grows after repeated failures and resets after success. This reduces unnecessary connection attempts and makes the device less disruptive when the router is unavailable.

7. Keep sensor sampling independent from networking

A common design mistake is to make the entire application depend on Wi-Fi. If a blocking connection loop runs before a temperature sensor is read, the device may stop collecting data whenever the router is down. Separate local work from network delivery wherever possible.

A sensible structure is to read the sensor, validate the measurement, store or display it locally, and then attempt to send it if the network is available. The application can keep sampling while offline and send the latest value after reconnecting. If every measurement matters, use a bounded queue or persistent storage with an explicit policy for memory limits and power loss; do not assume a tiny microcontroller can buffer data indefinitely.

Also avoid long blocking delays inside a web server or MQTT application. Use short waits and state-based logic where possible. If networking fails, expose a clear status indicator and avoid repeatedly resetting the whole board unless that behavior is intentional and tested.

8. Troubleshooting common connection failures

The SSID is not listed. Check that the router's 2.4 GHz network is enabled, the board is within range, the SSID is broadcast if your scan relies on discovery, and the firmware supports the chip. Test with a nearby access point you control.

Authentication fails. Re-enter the password carefully, check the router's security configuration, and confirm that the network does not require a captive portal or enterprise login that the project does not support. Avoid repeatedly exposing the password in console output.

The board connects but cannot reach a service. Inspect the IP configuration, gateway, DNS, and local firewall or guest-network isolation. A local MQTT broker may be reachable only from the same subnet. An IP address alone does not prove that a remote hostname resolves or that a service is listening.

Connection works once but not after reboot. Confirm the script is saved to the device as main.py, credentials are available at startup, and connection attempts have timeouts. A manual IDE run is not proof that startup works.

The board repeatedly disconnects. Check signal strength, power stability, antenna placement, router logs, and code that repeatedly toggles the WLAN interface. Avoid rapid reconnect loops; introduce a retry interval and log state transitions rather than every loop iteration.

9. Security and reliability practices

Use unique network credentials and keep them out of public source control. Store them in a local configuration module or another provisioning mechanism appropriate to the device, and add that file to your repository's ignore rules. An ignore rule does not remove secrets that were already committed; if a credential was exposed, change it and review repository history.

Do not treat an ordinary Wi-Fi connection as encrypted application-level communication with every destination. For sensitive data, use a service and protocol configuration that validates the remote endpoint and protects data in transit. Avoid disabling certificate validation merely to make a connection work. The exact TLS and certificate features depend on the MicroPython build and memory constraints.

Use bounded timeouts for connection and network operations, limit retry frequency, and handle exceptions around code that can fail. Do not assume the network remains available between checking isconnected() and sending a request. Design for the possibility that a connection drops at any time. Keep logs useful but avoid printing passwords, tokens, or personal data. For deployed devices, plan how credentials can be changed without reflashing every board.

10. A repeatable workflow for a SolderHub project

  1. Confirm that the firmware matches the ESP32 variant and that the REPL works.
  2. Scan once to verify that the intended 2.4 GHz access point is visible.
  3. Connect in station mode using locally stored placeholder-replaced credentials.
  4. Use a timeout and report a clear connected or offline state.
  5. Print the IP configuration during development, but avoid publishing private network details.
  6. Test the actual target service separately from Wi-Fi association.
  7. Simulate router loss by turning off the access point during a controlled test; confirm the sensor or local interface remains safe and responsive.
  8. Restore the network and verify that retry logic reconnects without a manual reset.
  9. Test a reboot with the script saved on the board, not only by pressing Run in the IDE.
  10. Remove diagnostic secrets and excessive console logging before sharing the project.

Wi-Fi should be one subsystem of the application, not a single point of failure for every feature. A clear startup sequence, bounded waits, reconnection policy, and secret-handling discipline make MicroPython projects more reliable. Consult the official MicroPython documentation for the exact ESP32 port and firmware version when an API behaves differently from these common examples.

11. Test the failure path before deployment

Do not test only the happy path. First confirm a successful connection, then deliberately make the access point unavailable in a controlled environment and observe how the application behaves. The device should report that it is offline, avoid a tight reconnect loop, and continue any local behavior that is safe to continue. Restore the access point and verify that the retry policy recovers without requiring a power cycle. Also test an incorrect password and a router restart. These cases expose assumptions that are easy to miss during a quick bench test. If your application controls a relay, motor, heater, or other actuator, define a safe output state for network loss; never make an internet or Wi-Fi connection the only safeguard against a hazardous output.

Signal In

Built from what makers search for

The lookups piling up in SolderHub's search bar every day shape what we publish next — new component pages, board guides, and firmware notes, sent out as they go live.

By subscribing you agree to our Privacy Policy. Unsubscribe anytime.