In this tutorial I will show you how to create Web Server using ESP32
Module and ESP-IDF. You will create how to create a HTML Web Page with
Buttons for 2 LEDs. We will control LEDs based on pressed buttons.
In this tutorial we will use HTTP protocol for running Web Server on ESP32. Lets first understand what is HTTP.
HTTP
HTTP which stands for Hypertext Transfer Protocol is the foundation of the World Wide Web (WWW) is used to load Web Pages including our WebSite. It is standard which is used between Web browser and Web Server, It defines rules to transfer data.
It works on Client server model, Client requests data from Server.
Features
-
Stateless
Server is not required to store any information between requests. -
Connectionless
It is considered connectionless as connection is dropped after every data transfers. -
Media Independent
Multiple type of data can be shared using HTTP. -
Client-Server Model
Follows client-server model for requesting and serving data. -
Requests Methods
Supports multiple methods like GET, POST, PUT and DELETE for different actions.
Prerequisite
Before proceeding further make sure you have installed VS Code with ESP-IDF
extension. You can follow steps mentioned at this link to install and
configure ESP-IDF in VS Code.
Hardware Used
In this tutorial we are using following hardware,
-
ESP32-C6 Dev Kit (You can use any ESP32 based board with this code)
-
5mm Through Hole LEDs
-
470 Ohm Through Hole Resistors
-
Connecting Wires
-
Bread Board
Create Example Project ESP-IDF
Open VS Code and Press CTRL+SHIFT+P or Click
on View > Command Palette to Open Command Palette
option. Select ESP-IDF: Show Example Projects Option
to view all available examples from ESP-IDF.
Select captive_portal under http_server section,
then Select location at which you want to create example project.
After project is created you will see project folder open in VS Code.
ESP-IDF Web-Server Code
You need to replace 2 files with provided code for each of them below.
-
main.c
/* Captive Portal Example This example code is in the Public Domain (or CC0 licensed, at your option.) Unless required by applicable law or agreed to in writing, this software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ #include <sys/param.h> #include "esp_event.h" #include "esp_log.h" #include "esp_mac.h" #include "nvs_flash.h" #include "esp_wifi.h" #include "esp_netif.h" #include "lwip/inet.h" #include "driver/gpio.h" #include "esp_http_server.h" #include "dns_server.h" #define EXAMPLE_ESP_WIFI_SSID "EmbeTronics" #define EXAMPLE_ESP_WIFI_PASS "12345678" #define EXAMPLE_MAX_STA_CONN 5 #define RED_LED_PIN 2 #define GREEN_LED_PIN 3 extern const char root_start[] asm("_binary_root_html_start"); extern const char root_end[] asm("_binary_root_html_end"); static const char *TAG = "example"; static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { if (event_id == WIFI_EVENT_AP_STACONNECTED) { wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *)event_data; ESP_LOGI(TAG, "station " MACSTR " join, AID=%d", MAC2STR(event->mac), event->aid); } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) { wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data; ESP_LOGI(TAG, "station " MACSTR " leave, AID=%d, reason=%d", MAC2STR(event->mac), event->aid, event->reason); } } static void wifi_init_softap(void) { wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL)); wifi_config_t wifi_config = { .ap = { .ssid = EXAMPLE_ESP_WIFI_SSID, .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID), .password = EXAMPLE_ESP_WIFI_PASS, .max_connection = EXAMPLE_MAX_STA_CONN, .authmode = WIFI_AUTH_WPA_WPA2_PSK }, }; if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) { wifi_config.ap.authmode = WIFI_AUTH_OPEN; } ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config)); ESP_ERROR_CHECK(esp_wifi_start()); esp_netif_ip_info_t ip_info; esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"), &ip_info); char ip_addr[16]; inet_ntoa_r(ip_info.ip.addr, ip_addr, 16); ESP_LOGI(TAG, "Set up softAP with IP: %s", ip_addr); ESP_LOGI(TAG, "wifi_init_softap finished. SSID :'%s' password:'%s'", EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); } #ifdef CONFIG_ESP_ENABLE_DHCP_CAPTIVEPORTAL static void dhcp_set_captiveportal_url(void) { // get the IP of the access point to redirect to esp_netif_ip_info_t ip_info; esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"), &ip_info); char ip_addr[16]; inet_ntoa_r(ip_info.ip.addr, ip_addr, 16); ESP_LOGI(TAG, "Set up softAP with IP: %s", ip_addr); // turn the IP into a URI char* captiveportal_uri = (char*) malloc(32 * sizeof(char)); assert(captiveportal_uri && "Failed to allocate captiveportal_uri"); strcpy(captiveportal_uri, "http://"); strcat(captiveportal_uri, ip_addr); // get a handle to configure DHCP with esp_netif_t* netif = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"); // set the DHCP option 114 ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_stop(netif)); ESP_ERROR_CHECK(esp_netif_dhcps_option(netif, ESP_NETIF_OP_SET, ESP_NETIF_CAPTIVEPORTAL_URI, captiveportal_uri, strlen(captiveportal_uri))); ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_start(netif)); } #endif // CONFIG_ESP_ENABLE_DHCP_CAPTIVEPORTAL /* HTTP GET Handlers */ static esp_err_t root_get_handler(httpd_req_t *req) { const uint32_t root_len = root_end - root_start; ESP_LOGI(TAG, "Serve root, Req %s",req->uri); httpd_resp_set_type(req, "text/html"); httpd_resp_send(req, root_start, root_len); return ESP_OK; } static esp_err_t root_get_handler_red_led_on(httpd_req_t *req) { ESP_LOGI(TAG, "Serve root, Req %s",req->uri); gpio_set_level(RED_LED_PIN, 1); root_get_handler(req); return ESP_OK; } static esp_err_t root_get_handler_red_led_off(httpd_req_t *req) { ESP_LOGI(TAG, "Serve root, Req %s",req->uri); gpio_set_level(RED_LED_PIN, 0); root_get_handler(req); return ESP_OK; } static esp_err_t root_get_handler_green_led_on(httpd_req_t *req) { ESP_LOGI(TAG, "Serve root, Req %s",req->uri); gpio_set_level(GREEN_LED_PIN, 1); root_get_handler(req); return ESP_OK; } static esp_err_t root_get_handler_green_led_off(httpd_req_t *req) { ESP_LOGI(TAG, "Serve root, Req %s",req->uri); gpio_set_level(GREEN_LED_PIN , 0); root_get_handler(req); return ESP_OK; } static const httpd_uri_t root = { .uri = "/", .method = HTTP_GET, .handler = root_get_handler }; static const httpd_uri_t root_red_led_on = { .uri = "/RED_LED_ON", .method = HTTP_GET, .handler = root_get_handler_red_led_on }; static const httpd_uri_t root_red_led_off = { .uri = "/RED_LED_OFF", .method = HTTP_GET, .handler = root_get_handler_red_led_off }; static const httpd_uri_t root_green_led_on = { .uri = "/GREEN_LED_ON", .method = HTTP_GET, .handler = root_get_handler_green_led_on }; static const httpd_uri_t root_green_led_off = { .uri = "/GREEN_LED_OFF", .method = HTTP_GET, .handler = root_get_handler_green_led_off }; // HTTP Error (404) Handler - Redirects all requests to the root page esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err) { // Set status httpd_resp_set_status(req, "302 Temporary Redirect"); // Redirect to the "/" root directory httpd_resp_set_hdr(req, "Location", "/"); // iOS requires content in the response to detect a captive portal, simply redirecting is not sufficient. httpd_resp_send(req, "Redirect to the captive portal", HTTPD_RESP_USE_STRLEN); ESP_LOGI(TAG, "Redirecting to root"); return ESP_OK; } static httpd_handle_t start_webserver(void) { httpd_handle_t server = NULL; httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.max_open_sockets = 13; config.lru_purge_enable = true; // Start the httpd server ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port); if (httpd_start(&server, &config) == ESP_OK) { // Set URI handlers ESP_LOGI(TAG, "Registering URI handlers"); httpd_register_uri_handler(server, &root); httpd_register_uri_handler(server, &root_red_led_on); httpd_register_uri_handler(server, &root_red_led_off); httpd_register_uri_handler(server, &root_green_led_on); httpd_register_uri_handler(server, &root_green_led_off); httpd_register_err_handler(server, HTTPD_404_NOT_FOUND, http_404_error_handler); } return server; } void app_main(void) { /* Turn of warnings from HTTP server as redirecting traffic will yield lots of invalid requests */ esp_log_level_set("httpd_uri", ESP_LOG_ERROR); esp_log_level_set("httpd_txrx", ESP_LOG_ERROR); esp_log_level_set("httpd_parse", ESP_LOG_ERROR); /* Init LED GPIO Pins */ gpio_config_t io_conf = { .pin_bit_mask = ((1ULL << RED_LED_PIN) | (1ULL << GREEN_LED_PIN)), // Select Led GPIO Pins .mode = GPIO_MODE_OUTPUT, // Set as output .pull_up_en = GPIO_PULLUP_DISABLE, // Disable pull-up .pull_down_en = GPIO_PULLDOWN_DISABLE, // Disable pull-down .intr_type = GPIO_INTR_DISABLE // Disable interrupts }; gpio_config(&io_conf); // Initialize networking stack ESP_ERROR_CHECK(esp_netif_init()); // Create default event loop needed by the main app ESP_ERROR_CHECK(esp_event_loop_create_default()); // Initialize NVS needed by Wi-Fi ESP_ERROR_CHECK(nvs_flash_init()); // Initialize Wi-Fi including netif with default config esp_netif_create_default_wifi_ap(); // Initialise ESP32 in SoftAP mode wifi_init_softap(); // Configure DNS-based captive portal, if configured #ifdef CONFIG_ESP_ENABLE_DHCP_CAPTIVEPORTAL dhcp_set_captiveportal_url(); #endif // Start the server for the first time start_webserver(); // Start the DNS server that will redirect all queries to the softAP IP dns_server_config_t config = DNS_SERVER_CONFIG_SINGLE("*" /* all A queries */, "WIFI_AP_DEF" /* softAP netif ID */); start_dns_server(&config); } -
root.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>EmbeTronics LED Control</title> <style> body { font-family: Arial, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #f0f0f0; margin: 0; } .container { background-color: #2e5077; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); text-align: center; } a { color: #ffffff; font-weight: bold; } h1 { color: #ffffff; } h2 { color: #ffffff; } .led-control { margin: 15px 0; } .led-control button { padding: 10px 20px; margin: 5px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; color: white; } .led-control .green-on { background-color: #28a745; } .led-control .green-off { background-color: #dc3545; } .led-control .red-on { background-color: #dc3545; } .led-control .red-off { background-color: #28a745; } </style> </head> <body> <div class="container"> <img alt="Embedded Image" src="data:image/png;base64,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"> <h1>EmbeTronics LED Control Panel</h1> <a href="https://www.embetronics.com/">Visit embetronics.com for More information !!</a> <div class="led-control"> <h2>Green LED</h2> <!-- <button class="green-on" onclick="controlLed('green', 'on')">Turn On</button> --> <a href=GREEN_LED_ON><button class="green-on" >Turn On</button></a> <a href=GREEN_LED_OFF><button class="green-off" >Turn Off</button></a> </div> <div class="led-control"> <h2>Red LED</h2> <a href=RED_LED_ON><button class="red-on" >Turn On</button></a> <a href=RED_LED_OFF><button class="red-off" >Turn Off</button></a> </div> </div> </body> </html>
Working Of Code
- Connect 2 LEDs with Board on GPIO Pins 2 and 3 through 470 Ohm series resistor.
- Now replace code for above two files in project folder, then build and flash code on ESP32 Board.
-
As soon as program starts running on board, It will create Wi-Fi
Access Point with below credentials.
SSID : EmbeTronics PASS : 12345678 - From Laptop or Mobile, Connect with above Access Point using provided credentials. As soon as device is connected with access point of ESP32, It will automatically open webpage in browser.
- If Webpage didn't open automatically in Web Browser, Use IP Address "192.168.4.1" to open Web Page manually.
- From Webpage you can control both LEDs by pressing On and Off Button.
Video
You can watch video for working of project at below link.
Full Project Code
You can directly download and use whole project from below GitHub
link.
GitHub Repo Link
Explanation of Code
Let us understand blocks of code and see how it works.
First we will include all required header files. Header files for
FreeRTOS, WiFi, MQTT and Logging are included.
#include <sys/param.h>
#include "esp_event.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "nvs_flash.h"
#include "esp_wifi.h"
#include "esp_netif.h"
#include "lwip/inet.h"
#include "driver/gpio.h"
#include "esp_http_server.h"
#include "dns_server.h"Then Wi-Fi Credentials to used with Access Point are set.
#define EXAMPLE_ESP_WIFI_SSID "EmbeTronics"
#define EXAMPLE_ESP_WIFI_PASS "12345678"
#define EXAMPLE_MAX_STA_CONN 5Pins for Red and Green LED are set, You can replace pins number with your configuration.
#define RED_LED_PIN 2
#define GREEN_LED_PIN 3
HTML file for Web Page is embedded into project. It is specified using EMBED_FILES into CMakeLists.txt file.
idf_compo
nent_register(SRCS main.c
EMBED_FILES root.html)
HTML file content is accessed from code via below variables.
extern const char root_start[] asm("_binary_root_html_start");
extern const char root_end[] asm("_binary_root_html_end");
TAG to be used when ESP Log print is defined. You can modify as per your requirement.
extern const char root_start[] asm("_binary_root_html_start");
/* TAG for ESP Log Print */ static const char *TAG = "example";
wifi_event_handler handler function to handle all Wi-Fi related events is defined. It handles Wi-Fi Connect, Disconnect and IP Got events. It will try to connect with provided Wi-Fi network with defined number of retries.
/* WiFi Event Handler Function */
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
/* WiFi Connect Retry Count */
static int s_retry_num = 0;
/* If WiFi Station Mode Start Event Received */
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
}
/* If WiFi Disconnect Event Received */
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
{
/* If WiFi Cconnect Retry Count not Completed,Try Connecting */
if (s_retry_num < EXAMPLE_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_network_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG,"connect to the AP fail");
}
/* If IP Got Event Received */
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "static ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_network_event_group, CONNECTED_BIT);
}
}
wifi_init_softap function initializes Wi-Fi in Soft Access Point Mode.
static void wifi_init_softap(void)
{
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
wifi_config_t wifi_config = {
.ap = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
.password = EXAMPLE_ESP_WIFI_PASS,
.max_connection = EXAMPLE_MAX_STA_CONN,
.authmode = WIFI_AUTH_WPA_WPA2_PSK
},
};
if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
}
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
esp_netif_ip_info_t ip_info;
esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"), &ip_info);
char ip_addr[16];
inet_ntoa_r(ip_info.ip.addr, ip_addr, 16);
ESP_LOGI(TAG, "Set up softAP with IP: %s", ip_addr);
ESP_LOGI(TAG, "wifi_init_softap finished. SSID:'%s' password:'%s'",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
}
dhcp_set_captiveportal_url function enables DHCP server on Access Point.
static void dhcp_set_captiveportal_url(void) {
// get the IP of the access point to redirect to
esp_netif_ip_info_t ip_info;
esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"), &ip_info);
char ip_addr[16];
inet_ntoa_r(ip_info.ip.addr, ip_addr, 16);
ESP_LOGI(TAG, "Set up softAP with IP: %s", ip_addr);
// turn the IP into a URI
char* captiveportal_uri = (char*) malloc(32 * sizeof(char));
assert(captiveportal_uri && "Failed to allocate captiveportal_uri");
strcpy(captiveportal_uri, "http://");
strcat(captiveportal_uri, ip_addr);
// get a handle to configure DHCP with
esp_netif_t* netif = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF");
// set the DHCP option 114
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_stop(netif));
ESP_ERROR_CHECK(esp_netif_dhcps_option(netif, ESP_NETIF_OP_SET, ESP_NETIF_CAPTIVEPORTAL_URI, captiveportal_uri, strlen(captiveportal_uri)));
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_start(netif));
}
Then, HTTP request handler functions are defined as below. We have defined individual handler for Webpage root request and LED On/Off requests.
/* HTTP GET Handlers */
static esp_err_t root_get_handler(httpd_req_t *req)
{
const uint32_t root_len = root_end - root_start;
ESP_LOGI(TAG, "Serve root, Req %s",req->uri);
httpd_resp_set_type(req, "text/html");
httpd_resp_send(req, root_start, root_len);
return ESP_OK;
}
static esp_err_t root_get_handler_red_led_on(httpd_req_t *req)
{
ESP_LOGI(TAG, "Serve root, Req %s",req->uri);
gpio_set_level(RED_LED_PIN, 1);
root_get_handler(req);
return ESP_OK;
}
static esp_err_t root_get_handler_red_led_off(httpd_req_t *req)
{
ESP_LOGI(TAG, "Serve root, Req %s",req->uri);
gpio_set_level(RED_LED_PIN, 0);
root_get_handler(req);
return ESP_OK;
}
static esp_err_t root_get_handler_green_led_on(httpd_req_t *req)
{
ESP_LOGI(TAG, "Serve root, Req %s",req->uri);
gpio_set_level(GREEN_LED_PIN, 1);
root_get_handler(req);
return ESP_OK;
}
static esp_err_t root_get_handler_green_led_off(httpd_req_t *req)
{
ESP_LOGI(TAG, "Serve root, Req %s",req->uri);
gpio_set_level(GREEN_LED_PIN, 0);
root_get_handler(req);
return ESP_OK;
}
All structures as shown below are used to register each handler function is defined.
static const httpd_uri_t root = {
.uri = "/",
.method = HTTP_GET,
.handler = root_get_handler
};
static const httpd_uri_t root_red_led_on = {
.uri = "/RED_LED_ON",
.method = HTTP_GET,
.handler = root_get_handler_red_led_on
};
static const httpd_uri_t root_red_led_off = {
.uri = "/RED_LED_OFF",
.method = HTTP_GET,
.handler = root_get_handler_red_led_off
};
static const httpd_uri_t root_green_led_on = {
.uri = "/GREEN_LED_ON",
.method = HTTP_GET,
.handler = root_get_handler_green_led_on
};
static const httpd_uri_t root_green_led_off = {
.uri = "/GREEN_LED_OFF",
.method = HTTP_GET,
.handler = root_get_handler_green_led_off
};http_404_error_handler handler function is used to handle HTTP 404 Error.
// HTTP Error (404) Handler - Redirects all requests to the root page
esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err)
{
// Set status
httpd_resp_set_status(req, "302 Temporary Redirect");
// Redirect to the "/" root directory
httpd_resp_set_hdr(req, "Location", "/");
// iOS requires content in the response to detect a captive portal, simply redirecting is not sufficient.
httpd_resp_send(req, "Redirect to the captive portal", HTTPD_RESP_USE_STRLEN);
ESP_LOGI(TAG, "Redirecting to root");
return ESP_OK;
}start_webserver function initializes and starts HTTP Web Server, and registers all handlers functions (root, led on and off requests) with it.
static httpd_handle_t start_webserver(void)
{
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.max_open_sockets = 13;
config.lru_purge_enable = true;
// Start the httpd server
ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
if (httpd_start(&server, &config) == ESP_OK) {
// Set URI handlers
ESP_LOGI(TAG, "Registering URI handlers");
httpd_register_uri_handler(server, &root);
httpd_register_uri_handler(server, &root_red_led_on);
httpd_register_uri_handler(server, &root_red_led_off);
httpd_register_uri_handler(server, &root_green_led_on);
httpd_register_uri_handler(server, &root_green_led_off);
httpd_register_err_handler(server, HTTPD_404_NOT_FOUND, http_404_error_handler);
}
return server;
}At last app_main function of our code is defined. It performs below mentioned things,
- Set Log level for HTTP modules
- Initializes GPIO pins for Red and Green LEDs.
- Initializes network stack with Soft-AP Wi-Fi Access Point
- Initializes NVS flash memory
- Initializes DHCP server for Captive Portal
- Start Web Server over HTTP
- Start DNS Server
void app_main(void)
{
/*
Turn of warnings from HTTP server as redirecting traffic will yield
lots of invalid requests
*/
esp_log_level_set("httpd_uri", ESP_LOG_ERROR);
esp_log_level_set("httpd_txrx", ESP_LOG_ERROR);
esp_log_level_set("httpd_parse", ESP_LOG_ERROR);
/* Init LED GPIO Pins */
gpio_config_t io_conf = {
.pin_bit_mask = ((1ULL << RED_LED_PIN) | (1ULL << GREEN_LED_PIN)), // Select Led GPIO Pins
.mode = GPIO_MODE_OUTPUT, // Set as output
.pull_up_en = GPIO_PULLUP_DISABLE, // Disable pull-up
.pull_down_en = GPIO_PULLDOWN_DISABLE, // Disable pull-down
.intr_type = GPIO_INTR_DISABLE // Disable interrupts
};
gpio_config(&io_conf);
// Initialize networking stack
ESP_ERROR_CHECK(esp_netif_init());
// Create default event loop needed by the main app
ESP_ERROR_CHECK(esp_event_loop_create_default());
// Initialize NVS needed by Wi-Fi
ESP_ERROR_CHECK(nvs_flash_init());
// Initialize Wi-Fi including netif with default config
esp_netif_create_default_wifi_ap();
// Initialise ESP32 in SoftAP mode
wifi_init_softap();
// Configure DNS-based captive portal, if configured
#ifdef CONFIG_ESP_ENABLE_DHCP_CAPTIVEPORTAL
dhcp_set_captiveportal_url();
#endif
// Start the server for the first time
start_webserver();
// Start the DNS server that will redirect all queries to the softAP IP
dns_server_config_t config = DNS_SERVER_CONFIG_SINGLE("*" /* all A queries */, "WIFI_AP_DEF" /* softAP netif ID */);
start_dns_server(&config);
}
Wrapping Up
In todays, Tutorial you have learned how to control leds from web browser
using ESP32 Board.
Please leave a comment if you have a question or you found this
helpful.



0 Comments