# Connectivity with Zephyr - Part 1: WiFi on ESP32-S3

**URL:** https://hub.mender.io/t/connectivity-with-zephyr-part-1-wifi-on-esp32-s3/8130
**Category:** Zephyr
**Created:** [December 9, 2025, 2:24pm UTC](https://hub.mender.io/t/connectivity-with-zephyr-part-1-wifi-on-esp32-s3/8130 "2025-12-09T14:24:41Z")
**Posts on this page:** 1
**Page:** 1

<div class="post-metadata">

### Author: ![TheYoctoJester](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/theyoctojester/32/1444_2.png) [@TheYoctoJester](https://hub.mender.io/u/TheYoctoJester)
#### Post date: [December 9, 2025, 2:24pm UTC](https://hub.mender.io/t/connectivity-with-zephyr-part-1-wifi-on-esp32-s3/8130/1 "2025-12-09T14:24:41Z")

</div>

The ESP32 family has become a go-to platform for getting started with Zephyr. It is cheap, readily available, and offers integrated WiFi connectivity. This first part of a three-part tutorial series covers establishing a WiFi connection and obtaining an IP address via DHCP.

| | |
| --- | --- |
| **Target** | ESP32-S3-DevKitC |
| **Zephyr version** | 4.3.0 |
| **Level** | Beginner |

**Tutorial Series:**

1. **WiFi Connectivity** (this part)
2. [HTTP Client](https://hub.mender.io/t/connectivity-with-zephyr-part-2-http-client-on-esp32-s3/8131)
3. [HTTPS with TLS](https://hub.mender.io/t/connectivity-with-zephyr-part-3-https-with-tls-on-esp32-s3/8132)

## Prerequisites

**Hardware:**

- ESP32-S3-DevKitC (or compatible ESP32-S3 board)

**Software:**

- Zephyr RTOS (tested with v4.3.0)
- Zephyr SDK and `west` tool
- Espressif toolchain and HAL module
- A WiFi network with active DHCP server and internet access

**Required Setup:**

Before starting, ensure you have a working Zephyr development environment for ESP32:

1. **Zephyr Getting Started Guide** : Follow the official [Getting Started Guide](https://docs.zephyrproject.org/latest/develop/getting_started/index.html) to install Zephyr and the SDK.

2. **Espressif (ESP32) Setup**: Complete the [Espressif ESP32 board setup](https://docs.zephyrproject.org/latest/boards/espressif/esp32s3_devkitc/doc/index.html) including:

3. **Verify Installation** : Build and flash a simple example like `samples/hello_world` to confirm your environment works.

## Project Structure

The project consists of these files:

```auto
wifi_app/
├── CMakeLists.txt # Build configuration
├── Kconfig # Custom Kconfig options for WiFi credentials
├── prj.conf # Main Zephyr configuration
├── boards/
│ └── esp32s3_devkitc_procpu.conf # Board-specific settings
└── src/
    └── main.c # Application code

```

## Build System Files

Start with `CMakeLists.txt`:

```cmake
cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(wifi_app)

target_sources(app PRIVATE src/main.c)

```

## Project Configuration

The `prj.conf` file configures Zephyr’s networking stack for WiFi connectivity:

```ini
# Networking
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_TCP=y

# WiFi
CONFIG_WIFI=y
CONFIG_NET_L2_WIFI_MGMT=y
CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
CONFIG_NET_MGMT_EVENT_INFO=y

# Stack sizes for ESP32
CONFIG_MAIN_STACK_SIZE=4096
CONFIG_NET_TX_STACK_SIZE=2048
CONFIG_NET_RX_STACK_SIZE=2048

# Network buffers
CONFIG_NET_PKT_RX_COUNT=10
CONFIG_NET_PKT_TX_COUNT=10
CONFIG_NET_BUF_RX_COUNT=20
CONFIG_NET_BUF_TX_COUNT=20

# Logging
CONFIG_LOG=y
CONFIG_NET_LOG=y

# WiFi credentials (edit these)
CONFIG_WIFI_SSID="YourSSID"
CONFIG_WIFI_PSK="YourPassword"

```

The `CONFIG_NET_MGMT*` options enable the network management API, which provides callbacks for WiFi and IP address events. The buffer counts and stack sizes are tuned for the ESP32’s memory constraints.

For the WiFi credentials, we define custom Kconfig options in `Kconfig`:

```kconfig
mainmenu "WiFi HTTP Client Application"

config WIFI_SSID
	string "WiFi SSID"
	help
	  SSID of the WiFi network to connect to.

config WIFI_PSK
	string "WiFi Password"
	help
	  WPA2-PSK password for the WiFi network.

source "Kconfig.zephyr"

```

### Setting WiFi Credentials

You have two options for configuring the WiFi SSID and password:

**Option 1: Edit `prj.conf` directly**

Simply edit the `CONFIG_WIFI_SSID` and `CONFIG_WIFI_PSK` values in `prj.conf`:

```ini
CONFIG_WIFI_SSID="MyNetwork"
CONFIG_WIFI_PSK="MyPassword"

```

**Option 2: Use menuconfig**

Zephyr’s interactive configuration tool provides a menu-driven interface:

```bash
west build -t menuconfig

```

Navigate to the top-level menu “WiFi HTTP Client Application” to find the SSID and PSK options. Save and exit when done. This updates the build configuration without modifying `prj.conf` directly.

The ESP32-S3 also needs a board-specific configuration in `boards/esp32s3_devkitc_procpu.conf`:

```ini
CONFIG_ESP32_WIFI_STA_AUTO_DHCPV4=y

```

## Core Concepts

Before diving into the code, let us understand some key Zephyr concepts used in this example.

### Network Management Events

Zephyr’s networking stack is event-driven. Operations like WiFi connection and DHCP address assignment happen asynchronously - you initiate an operation, and the system notifies you when it completes (or fails) via callbacks. This is handled by the **Network Management API** (`net_mgmt`).

The pattern is:

1. Define a callback function to handle specific events
2. Register the callback with `net_mgmt_add_event_callback()`
3. Initiate an operation (e.g., `NET_REQUEST_WIFI_CONNECT`)
4. Your callback fires when the event occurs

### Network Interfaces

A **network interface** (`struct net_if`) represents a network device - in our case, the ESP32’s WiFi radio. Zephyr abstracts different network technologies (WiFi, Ethernet, cellular) behind this common interface. We use `net_if_get_default()` to get the primary network interface.

### Logging

Zephyr’s logging subsystem (`LOG_INF`, `LOG_ERR`, etc.) provides structured logging with module names and severity levels. The `LOG_MODULE_REGISTER()` macro declares a logging module with a name and default level.

## WiFi Connection Code

Create `src/main.c`:

```c
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/net/wifi_mgmt.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/net_event.h>

LOG_MODULE_REGISTER(wifi_app, LOG_LEVEL_INF);

static struct net_mgmt_event_callback wifi_cb;
static struct net_mgmt_event_callback ipv4_cb;

static void wifi_event_handler(struct net_mgmt_event_callback *cb,
                               uint64_t mgmt_event, struct net_if *iface)
{
    if (mgmt_event == NET_EVENT_WIFI_CONNECT_RESULT) {
        LOG_INF("WiFi connected");
    } else if (mgmt_event == NET_EVENT_WIFI_DISCONNECT_RESULT) {
        LOG_INF("WiFi disconnected");
    }
}

static void ipv4_event_handler(struct net_mgmt_event_callback *cb,
                               uint64_t mgmt_event, struct net_if *iface)
{
    if (mgmt_event == NET_EVENT_IPV4_ADDR_ADD) {
        struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;

        if (ipv4) {
            char addr_str[NET_IPV4_ADDR_LEN];

            for (int i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
                if (ipv4->unicast[i].ipv4.is_used) {
                    net_addr_ntop(AF_INET,
                                  &ipv4->unicast[i].ipv4.address.in_addr,
                                  addr_str, sizeof(addr_str));
                    LOG_INF("IP Address: %s", addr_str);
                }
            }
        }
    }
}

static int connect_wifi(void)
{
    struct net_if *iface = net_if_get_default();
    struct wifi_connect_req_params params = {
        .ssid = CONFIG_WIFI_SSID,
        .ssid_length = strlen(CONFIG_WIFI_SSID),
        .psk = CONFIG_WIFI_PSK,
        .psk_length = strlen(CONFIG_WIFI_PSK),
        .channel = WIFI_CHANNEL_ANY,
        .band = WIFI_FREQ_BAND_2_4_GHZ,
        .security = WIFI_SECURITY_TYPE_PSK,
    };

    LOG_INF("Connecting to %s...", CONFIG_WIFI_SSID);
    return net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &params, sizeof(params));
}

int main(void)
{
    LOG_INF("ESP32-S3 WiFi Example");

    /* Register WiFi event callback */
    net_mgmt_init_event_callback(&wifi_cb, wifi_event_handler,
                                 NET_EVENT_WIFI_CONNECT_RESULT |
                                 NET_EVENT_WIFI_DISCONNECT_RESULT);
    net_mgmt_add_event_callback(&wifi_cb);

    /* Register IPv4 event callback */
    net_mgmt_init_event_callback(&ipv4_cb, ipv4_event_handler,
                                 NET_EVENT_IPV4_ADDR_ADD);
    net_mgmt_add_event_callback(&ipv4_cb);

    /* Wait for WiFi driver to initialize */
    k_sleep(K_SECONDS(2));

    /* Connect to WiFi */
    int ret = connect_wifi();
    if (ret) {
        LOG_ERR("WiFi connect request failed: %d", ret);
    }

    return 0;
}

```

### Code Walkthrough

**Event Callbacks** : We register two separate callbacks:

- `wifi_event_handler` - notified when WiFi connects or disconnects
- `ipv4_event_handler` - notified when DHCP assigns an IP address

**WiFi Parameters** : The `wifi_connect_req_params` structure specifies:

- SSID and password (from Kconfig)
- `WIFI_CHANNEL_ANY` - let the driver find the access point
- `WIFI_FREQ_BAND_2_4_GHZ` - use 2.4 GHz band
- `WIFI_SECURITY_TYPE_PSK` - WPA2-PSK authentication

**Asynchronous Flow** : The `net_mgmt(NET_REQUEST_WIFI_CONNECT, ...)` call initiates the connection but returns immediately. The actual connection happens in the background, and our callbacks are invoked when events occur. The `main()` function returns after initiating the connection - the callbacks continue to fire as events occur.

## Building and Flashing

```bash
west build -b esp32s3_devkitc/esp32s3/procpu
west flash
west espressif monitor

```

## Expected Output

```auto
[00:00:00.000,000] <inf> wifi_app: ESP32-S3 WiFi Example
[00:00:02.000,000] <inf> wifi_app: Connecting to YourSSID...
[00:00:05.xxx,xxx] <inf> wifi_app: WiFi connected
[00:00:06.xxx,xxx] <inf> wifi_app: IP Address: 192.168.x.x

```

The WiFi connection and DHCP address assignment happen asynchronously after `main()` returns. The callbacks continue to fire as long as the system is running.

## Next Steps

With WiFi connectivity established, proceed to Part 2: HTTP Client to make HTTP requests to a web API.

## Further Reading

- [Zephyr Networking Guide](https://docs.zephyrproject.org/latest/connectivity/networking/index.html) - comprehensive overview of Zephyr’s network stack
- [Zephyr WiFi API Reference](https://docs.zephyrproject.org/latest/connectivity/networking/api/wifi.html) - detailed WiFi management API documentation
- [Zephyr Network Management](https://docs.zephyrproject.org/latest/connectivity/networking/api/net_mgmt.html) - the event callback system used in this tutorial
- [ESP32-S3-DevKitC Board Documentation](https://docs.zephyrproject.org/latest/boards/espressif/esp32s3_devkitc/doc/index.html) - board-specific details and configuration
- [Zephyr Kconfig Reference](https://docs.zephyrproject.org/latest/build/kconfig/index.html) - understanding the configuration system
