ESP32-S2 Web Server Implementation Guide
ESP32-S2 Web Server Implementation Guide
The application's lifecycle is fundamentally divided into two distinct phases: an initial
Provisioning Phase and a continuous Operational Phase. This bifurcation dictates the
high-level state machine of the entire system.
● Provisioning Phase: When the device is powered on for the first time or has no stored
Wi-Fi credentials, it enters this phase. It activates its Wi-Fi radio in Soft Access Point
(SoftAP) mode, creating a temporary, local Wi-Fi network.4 The primary goal of this phase
is to present a simple web interface to the user, allowing them to scan for local Wi-Fi
networks and submit the credentials (SSID and password) for their home or office
network.4 The ESP-IDF provides a comprehensive Wi-Fi Provisioning Manager component
specifically designed to handle this entire workflow, including the creation of the
temporary network and a captive portal to simplify the user experience.6
● Operational Phase: Once valid Wi-Fi credentials have been received and successfully
stored, the device transitions to the operational phase. It disables the SoftAP, switches its
Wi-Fi mode to Station (STA), and connects to the user-provided network.4 Upon
successful connection and acquisition of an IP address, the device starts its primary
application logic—in this case, the USB/IP server—and launches a persistent, more
feature-rich web server. This web server serves the main configuration and monitoring
interface, accessible from any device on the local network.8 Subsequent reboots will
bypass the provisioning phase entirely, provided the stored credentials remain valid and
the network is available.
The transition between these two phases is a critical juncture. The architecture must ensure a
graceful shutdown of all provisioning-related services before initializing the operational
services to prevent resource conflicts and undefined behavior.
To manage the concurrent operations required by this architecture, the application logic is
segregated into distinct FreeRTOS tasks. Each task is an independent thread of execution with
its own stack and priority, managed by the FreeRTOS scheduler.3 This multi-tasking approach
prevents long-running operations, such as handling a web request or managing a USB
connection, from blocking other critical system functions.
With multiple tasks operating concurrently, a robust mechanism for sharing data between
them is not an optional refinement but a foundational requirement for system stability. The
web_interface_task needs to read status information generated by the usb_ip_server_task,
and the usb_ip_server_task may need to act on configuration changes initiated from the web
interface. Direct access to shared global variables in a preemptive, multi-core RTOS
environment is a recipe for disaster, leading to race conditions and data corruption.3
To address this, the architecture employs a centralized Shared State Module. This is a C
module (shared_state.c) that encapsulates all data to be shared between tasks within a single
struct. This struct might contain fields such as usb_device_connected (a boolean),
client_ip_address (a string), and data_throughput_kbps (an integer).
xSemaphoreTake. After the access is complete, it must "give" the mutex back using
xSemaphoreGive. This guarantees atomic operations on the shared data, preventing one task
from reading the data while another is in the middle of updating it.
While other FreeRTOS primitives like queues and task notifications are excellent for signaling
events or passing discrete messages, they are less suitable for managing a persistent,
complex state that needs to be accessed randomly by multiple tasks.14 The mutex-protected
shared structure provides a clear, efficient, and thread-safe repository for the system's
current state, acting as a reliable bridge between the core application logic and the web
interface. This formal Inter-Task Communication (ITC) strategy is paramount to building a
production-grade embedded system.
A seamless out-of-the-box user experience is crucial for any connected device. The initial
process of connecting the device to a user's local Wi-Fi network, known as provisioning, can
be complex to implement correctly. Fortunately, ESP-IDF provides a high-level, integrated
component, the Wi-Fi Provisioning Manager, which abstracts away the low-level details of
network creation, device discovery, and secure credential transfer.6
The Wi-Fi Provisioning Manager supports multiple transport mechanisms, including Bluetooth
LE and SoftAP. For this application, the wifi_prov_scheme_softap is the ideal choice.6 When
this scheme is used, the manager automatically performs the following actions:
1. Initializes Wi-Fi in AP+STA mode: The device can simultaneously act as an Access Point
while being ready to connect as a Station.6
2. Starts a SoftAP: It creates a Wi-Fi network with a configurable Service Set Identifier
(SSID), for example, "PROV_XXXXXX".16
3. Starts an HTTP Server: An internal, lightweight web server is launched to handle
provisioning requests.6
4. Starts an mDNS Service: This allows for user-friendly service discovery. Instead of
needing to know the device's default IP address (e.g., 192.168.4.1), a user can often
navigate to a hostname like http://espressif.local in their browser.6
The entire process is initiated with a few function calls. First, the manager is configured with a
wifi_prov_mgr_config_t structure, specifying wifi_prov_scheme_softap as the chosen scheme.
Then, wifi_prov_mgr_init() initializes the manager. Finally, wifi_prov_mgr_start_provisioning()
starts the service, taking parameters for security level, proof-of-possession, and the service
name (SoftAP SSID).6 Using the official manager provides a standardized and secure (Security
1 offers AES-CTR encryption) solution that is also compatible with official Espressif
provisioning mobile applications for iOS and Android, offering an alternative to the web-based
setup.16
The event handler for WIFI_PROV_END is the trigger for the application to transition from the
provisioning phase to the operational phase. Upon receiving this event, the handler should
de-initialize the provisioning manager using wifi_prov_mgr_deinit() to free up resources, and
then signal the main_app_task to proceed with launching the primary application tasks.6
A key feature of the Wi-Fi Provisioning Manager is its tight integration with the Non-Volatile
Storage (NVS) library. When credentials are successfully received, the manager automatically
saves them to the default NVS partition.5 This ensures that the Wi-Fi configuration persists
across device reboots and power cycles.
To create a seamless user experience, the main_app_task should, upon startup, first check if
the device has already been provisioned. This is accomplished by calling
wifi_prov_mgr_is_provisioned(). If this function returns true, it means valid credentials exist in
NVS. The application can then skip the entire provisioning process and proceed directly to
connecting to the stored Wi-Fi network.6 This logic ensures that the user only has to perform
the setup procedure once. If the device later fails to connect to the stored network,
application logic can be implemented to re-initiate the provisioning process, for example, after
a button press or a timeout period.
After the device has been provisioned and is connected to the local network, the persistent
operational web server is launched. This server is the backbone of the user interface,
responsible for serving the frontend web application and providing a dynamic data interface
through a RESTful API. The esp_http_server component in ESP-IDF provides a flexible and
efficient foundation for this purpose.11
To create a dynamic, responsive user interface that can display real-time status and accept
configuration changes without full page reloads, a clear and well-defined Application
Programming Interface (API) is essential. A RESTful (Representational State Transfer) API using
JSON (JavaScript Object Notation) as the data exchange format is the modern standard for
such web applications.19
All API endpoints are grouped under a common prefix, such as /api/, to distinguish them from
requests for static assets like HTML or CSS files. The core endpoints for this application are:
● GET /api/status: This endpoint is used by the frontend to poll the device for its latest
status. When requested, the server will respond with a JSON object containing real-time
information from the usb_ip_server_task. An example response might be:
{"usb_connected": true, "client_ip": "192.168.1.123", "uptime_sec": 3600}.
● GET /api/config: This endpoint retrieves the current, non-sensitive configuration settings
stored on the device. This allows the web interface to populate configuration forms with
the existing values when the page loads.
● POST /api/config: This endpoint is used to submit updated configuration settings to the
device. The web browser will send a JSON object in the body of the POST request
containing the new key-value pairs. The server will then validate these settings, update its
internal state, and persist the changes to NVS.
This API-centric design decouples the backend (firmware) from the frontend (web page). As
long as the API contract is maintained, either side can be updated independently, leading to a
more modular and maintainable system.
For each URI endpoint defined, a corresponding handler function must be implemented and
registered with the web server using httpd_register_uri_handler().2 This function takes a
httpd_uri_t structure that links a URI path and an HTTP method (e.g., HTTP_GET, HTTP_POST)
to a specific C function.18
● status_get_handler (for GET /api/status): This function's primary role is to read the
current status from the mutex-protected shared state module. It will take the mutex, copy
the relevant status variables into local memory, and then release the mutex as quickly as
possible to minimize blocking time. It then formats these variables into a JSON string. For
simple structures, this can be done with sprintf, but for more complex objects, a
dedicated library like cJSON is recommended. Finally, it sets the HTTP Content-Type
header to application/json 21 and sends the JSON string as the response body using
httpd_resp_send().2
● config_post_handler (for POST /api/config): This handler is more complex as it involves
processing incoming data. It first needs to determine the length of the request body from
the content_len field of the httpd_req_t structure and allocate a buffer to receive it. The
httpd_req_recv() function is used to read the POST data into this buffer.10 Once received,
the JSON data is parsed and validated. If the new settings are valid, the handler takes the
shared state mutex, updates the relevant configuration fields in the shared
struct, and then calls a function to save these new settings to NVS. After releasing the
mutex, it sends a success response to the client, typically a 200 OK status with a simple
JSON body like {"success": true}.
The following table provides a clear API contract, serving as a single source of truth for both
firmware and frontend development.
The frontend is the user-facing component of the system, comprising the HTML, CSS, and
JavaScript files that are served by the ESP32-S2 and rendered in the user's web browser. A
modern, dynamic frontend is essential for providing real-time monitoring and a seamless
configuration experience, leveraging asynchronous JavaScript to communicate with the
device's REST API.
The foundation of the user interface is a well-structured HTML document. This document
defines the layout of the page, including sections for status display and configuration forms.
To enable dynamic updates via JavaScript, key elements that will display changing data are
given unique id attributes.
For example, a section for displaying the USB connection status might look like this:
<h2>USB/IP Server Status</h2>
<p>USB Device: <span id="usb-status">Initializing...</span></p>
<p>Connected Client: <span id="client-ip">None</span></p>
A separate CSS file is used to style the HTML elements, ensuring a clean, professional, and
responsive layout that works well on both desktop and mobile browsers.22 The HTML file links
to this stylesheet using a
The key to a real-time monitoring interface is the ability to update data on the page without
requiring the user to manually refresh it. This is achieved using asynchronous JavaScript. The
modern standard for this is the Fetch API, which provides a clean, promise-based interface for
making network requests.23
This polling mechanism creates the appearance of a live dashboard, providing the user with
up-to-date information on the USB/IP server's operation.25
Submitting configuration changes from the web interface also leverages JavaScript to provide
a better user experience than a traditional HTML form submission, which would cause a full
page reload.24
An event listener is attached to the "submit" event of the configuration form. This listener's
callback function will:
1. Prevent Default Action: Call event.preventDefault() to stop the browser from
performing a standard form submission.
2. Gather Form Data: Collect the values from the various input fields in the form.
3. Construct JSON Payload: Assemble the collected data into a JavaScript object that
matches the expected format for the /api/config POST endpoint.
4. Send POST Request: Use the Fetch API to send a POST request to /api/config. The
request options will specify the method: 'POST', the necessary headers ('Content-Type':
'application/json'), and the JSON payload converted to a string in the body.
5. Provide User Feedback: Based on the success or failure of the fetch request, the script
can provide feedback to the user, such as displaying a "Settings saved successfully"
message or an error alert.
The optimal approach is a hybrid workflow that leverages the strengths of both methods.
During active UI development, use SPIFFS for its fast iteration capabilities. For creating the
final production release, switch the build configuration to use the EMBED_FILES method. This
provides the best of both worlds: a highly efficient development process and a simple, robust,
single-file deployment for the end-user.
The following table summarizes the trade-offs between these two strategies.
Development Workflow Slow iteration; requires full Fast iteration; UI assets can
firmware recompile for any be updated independently.
UI change.
For an embedded device to be practical, its configuration must persist across reboots and
power cycles. The ESP-IDF provides the Non-Volatile Storage (NVS) library, a specialized
key-value storage system designed for use with the onboard flash memory.31 It is the standard
and recommended method for storing small amounts of data like Wi-Fi credentials, device
settings, and calibration data.
NVS operates on a dedicated partition in the flash memory, typically labeled "nvs" in the
partition table.34 The library is designed for robustness, incorporating wear-leveling to
maximize the lifespan of the flash memory and mechanisms to recover from sudden power
loss during a write operation.33
The NVS API is handle-based. To perform read or write operations, an application must first
open a namespace using nvs_open(), which provides a handle for subsequent operations.
This modular approach ensures that the web server task and other tasks do not need to know
the specifics of the NVS API. They simply interact with the in-memory shared state and trigger
a save operation when necessary, leading to cleaner and more maintainable code.
The shared_state module is the central nervous system of the application. Its implementation
is critical for robust operation. The module consists of three main parts:
1. The State Structure: A struct that contains all data to be shared.
C
typedef struct {
bool usb_device_connected;
char client_ip_address[1];
uint32_t data_throughput_kbps;
//... other configuration and status fields
} app_state_t;
2. The Mutex Handle: A static SemaphoreHandle_t variable within the module to hold the
mutex.
C
static SemaphoreHandle_t g_state_mutex;
3. The Accessor Functions: A set of public functions that provide controlled access to the
state. These functions are the only way other modules should interact with the shared
data.
C
void shared_state_set_usb_status(bool is_connected) {
if (xSemaphoreTake(g_state_mutex, portMAX_DELAY) == pdTRUE) {
// Safely access the shared resource
g_app_state.usb_device_connected = is_connected;
xSemaphoreGive(g_state_mutex);
}
}
Similarly, a getter function would wrap its read access within the same
xSemaphoreTake/xSemaphoreGive block. The portMAX_DELAY parameter ensures the task
will wait indefinitely until the mutex is available, preventing it from proceeding with a
potentially unsafe access. It is vital that critical sections—the code between taking and giving
the mutex—are kept as short as possible to avoid unnecessarily blocking other tasks.3
With the thread-safe shared state module in place, we can trace the flow of data through the
system in two common scenarios, illustrating how the architecture works in practice.
Throughout this process, the mutex ensures that the web_interface_task never reads the state
structure while the usb_ip_server_task is in the middle of modifying it, preventing inconsistent
data from ever being sent to the user.
Scenario 2: User-Initiated Configuration Change
1. User Action: The user changes a setting in the web interface—for instance, a device
hostname—and clicks "Save".
2. POST Request: The browser's JavaScript sends a POST /api/config request with a JSON
body: {"hostname": "new-device-name"}.
3. Request Handling: The web_interface_task executes the config_post_handler. It
receives and parses the JSON body.
4. In-Memory Update: The handler calls a setter function,
shared_state_set_hostname("new-device-name"). This function takes the mutex,
updates the hostname field in the shared state structure, and gives the mutex. The
configuration is now updated in RAM.
5. Persistent Storage: The handler then calls config_save(). This function takes the mutex
again, reads the complete, consistent state from the shared structure, writes it to NVS,
and releases the mutex.
6. Application Logic Reacts: At some later point, the usb_ip_server_task, perhaps in its
main loop, calls shared_state_get_hostname() to retrieve the current hostname. Because
it uses the thread-safe getter, it will receive the new value set by the user, and can act on
it accordingly (e.g., by restarting its mDNS service with the new name).
This walkthrough demonstrates how the carefully designed architecture, centered around a
mutex-protected shared state, facilitates complex, asynchronous interactions between
multiple RTOS tasks in a safe, reliable, and predictable manner.
Section 7: Conclusion
The architecture detailed in this report provides a comprehensive and robust framework for
implementing a web-based configuration and monitoring interface on an ESP32-S2 based
device. By leveraging the core components of the ESP-IDF, including the Wi-Fi Provisioning
Manager, the esp_http_server, and the Non-Volatile Storage library, it is possible to create a
professional-grade product with a seamless user experience.
The key architectural decisions that ensure the system's stability and maintainability are:
● A Two-Phase Lifecycle: Clearly separating the initial device provisioning from its main
operational state simplifies logic and resource management.
● RTOS Task Segregation: Isolating the core application logic, the web server, and the
main state machine into distinct FreeRTOS tasks promotes modularity and prevents
blocking operations from impacting system responsiveness.
● A Centralized, Mutex-Guarded State: The implementation of a thread-safe shared
state module is the most critical element for ensuring data integrity in a concurrent,
multi-tasking environment. This prevents race conditions and provides a reliable
communication bridge between all system components.
● A RESTful API Design: Using a well-defined RESTful API with JSON decouples the
firmware backend from the web frontend, allowing for independent development and
greater flexibility.
● A Hybrid Web Asset Workflow: Employing SPIFFS for rapid UI development and
embedded files for production releases offers an optimal balance between developer
efficiency and deployment simplicity.
By adhering to these design principles, developers can move beyond simple examples and
build complex, connected IoT devices that are not only feature-rich but also stable, secure,
and easy for end-users to manage. This architectural blueprint serves as a solid foundation
for any ESP32-based project requiring a sophisticated web interface.
Works cited
1. ESP32 Web Server (ESP-IDF) - Embedded Explorer, accessed September 25,
2025, https://embeddedexplorer.com/esp32-web-server/
2. FreeRTOS (IDF) - ESP32 - — ESP-IDF Programming Guide v5.5.1 documentation -
Espressif Systems, accessed September 25, 2025,
https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/
freertos_idf.html
3. ESP-IDF Tutorials: Soft-AP · Developer Portal, accessed September 25, 2025,
https://developer.espressif.com/blog/2025/04/soft-ap-tutorial/
4. ESP32: WiFi Provisioning with Soft AP and Captive Portal - Reddit, accessed
September 25, 2025,
https://www.reddit.com/r/esp32/comments/1n4c6nl/esp32_wifi_provisioning_with
_soft_ap_and_captive/
5. Wi-Fi Provisioning - ESP32 - — ESP-IDF Programming Guide v5.5.1 ..., accessed
September 25, 2025,
https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/provisio
ning/wifi_provisioning.html
6. Making a commercial product from esp and wifi creds : r/esp32 - Reddit,
accessed September 25, 2025,
https://www.reddit.com/r/esp32/comments/18z3gwr/making_a_commercial_prod
uct_from_esp_and_wifi/
7. A simple HTTP server - Embedded Rust on Espressif - ESP-RS, accessed
September 25, 2025, https://docs.esp-rs.org/std-training/03_4_http_server.html
8. ESP32 Web Server with ESP-IDF, accessed September 25, 2025,
https://esp32tutorials.com/esp32-web-server-esp-idf/
9. HTTP Server - ESP32 - — ESP-IDF Programming Guide v4.2.2 documentation,
accessed September 25, 2025,
https://docs.espressif.com/projects/esp-idf/en/v4.2.2/esp32/api-reference/protoco
ls/esp_http_server.html
10.HTTP Server - ESP32 - — ESP-IDF Programming Guide v5.5.1 documentation,
accessed September 25, 2025,
https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/protoc
ols/esp_http_server.html
11. ESP32, ESP-IDF, FreeRTOS - Queues or global state (plus mutex?) to share when a
key on a keyboard is pressed / released? - Reddit, accessed September 25, 2025,
https://www.reddit.com/r/esp32/comments/1jck2bz/esp32_espidf_freertos_queue
s_or_global_state_plus/
12.Semaphores and Mutexes - - — ESP-Techpedia latest documentation, accessed
September 25, 2025,
https://docs.espressif.com/projects/esp-techpedia/en/latest/esp-friends/get-start
ed/basic-concepts/common-freertos-api/semaphore-and-mutexes.html
13.Efficient Inter-Task Communication with FreeRTOS Task ..., accessed September
25, 2025,
https://embeddedexplorer.com/efficient-inter-task-communication-with-freertos
-task-notifications-on-esp-wrover-kit/
14.Inter task Communication Architecture - Kernel - FreeRTOS Community Forums,
accessed September 25, 2025,
https://forums.freertos.org/t/inter-task-communication-architecture/11815
15.espressif/esp-idf-provisioning-android - GitHub, accessed September 25, 2025,
https://github.com/espressif/esp-idf-provisioning-android
16.ESP SoftAP Provisioning 4+ - App Store - Apple, accessed September 25, 2025,
https://apps.apple.com/us/app/esp-softap-provisioning/id1474040630
17.ESP-IDF Tutorials: Basic HTTP server · Developer Portal, accessed September 25,
2025, https://developer.espressif.com/blog/2025/06/basic_http_server/
18.ESP32 Rest API Web Server GET and POST Examples with ..., accessed September
25, 2025,
https://microcontrollerslab.com/esp32-rest-api-web-server-get-post-postman/
19.Example of JSON REST API on ESP32 | by Phoax | Medium, accessed September
25, 2025,
https://phoax.medium.com/example-of-json-rest-api-for-esp32-4a5f64774a05
20.esp_http_client: how to post using json? - ESP32 Forum, accessed September 25,
2025, https://esp32.com/viewtopic.php?t=6584
21.ESP32 Web Server using SPIFFS (SPI Flash File System) - Random Nerd Tutorials,
accessed September 25, 2025,
https://randomnerdtutorials.com/esp32-web-server-spiffs-spi-flash-file-system/
22.Resolving JavaScript File Download Issues from ESP32 Webserver - Medium,
accessed September 25, 2025,
https://medium.com/@python-javascript-php-html-css/resolving-javascript-file-
download-issues-from-esp32-webserver-d6cbf6e66915
23.Input Data on HTML Form ESP32/ESP8266 Web Server Arduino ..., accessed
September 25, 2025,
https://randomnerdtutorials.com/esp32-esp8266-input-data-html-form/
24.Web server on ESP32: How to update and display sensor values from the server
automatically? - Stack Overflow, accessed September 25, 2025,
https://stackoverflow.com/questions/44809589/web-server-on-esp32-how-to-u
pdate-and-display-sensor-values-from-the-server-aut
25.Web server on ESP32: How to update and display sensor values? -
Circuits4you.com, accessed September 25, 2025,
https://circuits4you.com/2018/11/20/web-server-on-esp32-how-to-update-and-
display-sensor-values/
26.ESP-IDF using HTML in my code with variable inside : r/esp32 - Reddit, accessed
September 25, 2025,
https://www.reddit.com/r/esp32/comments/1ndp9jc/espidf_using_html_in_my_cod
e_with_variable_inside/
27.mongoose - Espressif ESP32 web server HTML example - Stack ..., accessed
September 25, 2025,
https://stackoverflow.com/questions/41910072/espressif-esp32-web-server-html
-example
28.Embed Your Website in Your ESP8266 Firmware Image - Tinkerman, accessed
September 25, 2025,
https://tinkerman.cat/post/embed-your-website-in-your-esp8266-firmware-imag
e/
29.Store and read static pages in flash - ESP32 Forum, accessed September 25,
2025, https://esp32.com/viewtopic.php?t=1059
30.ESP IDF - Storage Help - What is NVS and Why? : r/esp32 - Reddit, accessed
September 25, 2025,
https://www.reddit.com/r/esp32/comments/1ajmhog/esp_idf_storage_help_what_i
s_nvs_and_why/
31.ESP32 Non-Volatile Storage (NVS) - ncona.com, accessed September 25, 2025,
https://ncona.com/2024/09/esp32-non-volatile-storage-nvs/
32.Non-Volatile Storage Library - ESP32 - — ESP-IDF Programming ..., accessed
September 25, 2025,
https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/storage
/nvs_flash.html
33.Non-volatile storage library - - — ESP-IDF Programming Guide release-v3.3
documentation, accessed September 25, 2025,
https://docs.espressif.com/projects/esp-idf/en/release-v3.3/api-reference/storage
/nvs_flash.html
34.NVS Data Storage and Reading in ESP32: A Comprehensive Guide - Medium,
accessed September 25, 2025,
https://medium.com/engineering-iot/nvs-data-storage-and-reading-in-esp32-a-
comprehensive-guide-12bdbc6325ac
35.ESP32 ESP-IDF Storing a text string into the NVS and updating it, so ..., accessed
September 25, 2025,
http://www.macpczone.co.uk/content/esp32-esp-idf-storing-text-string-nvs-and
-updating-it-so-it-can-survive-power-cycles