ESP-IDF http Server

Server here i mean any kind of service hosted on ESP32 which is accessible via TCP/IP. Here our server may be a TCP or UDP server. In both there are plenty of services both there are limited services which can be really implemented on these small chips.

In ESP-IDF example codes they have provided

  • Raw TCP Server
  • Raw UDP Server
  • DNS
  • ICMP Service
  • DHCP Server
  • Webserver (http and https)
  • NTP Server

For the any of these services we need a connection first, as you know ESP chips support ethernet but its not easy so its better to try the wifi interface as the bridge to outer world. So the first line we need.

#include <esp_wifi.h>

then for easy setup of wifi basic settings needed for http server (not preferable for applications where wifi scan needed)

#include "protocol_examples_common.h"

Now lets see app_main() this is the default entry point of any ESP-IDF build, lets inculde whatever required for a basic http server

    static httpd_handle_t server = NULL;

    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    ESP_ERROR_CHECK(example_connect());

    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_handler, &server));
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, &server));

    if (*server == NULL) {
        ESP_LOGI(TAG, "Starting webserver");

        httpd_handle_t server = NULL;
        httpd_config_t config = HTTPD_DEFAULT_CONFIG();
        config.lru_purge_enable = true;

        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, &hello);
           }
        else
        {
        ESP_LOGI(TAG, "Error in connection");
        *server == NULL;
        }
    }

the wifi drivers communicate the mainloop via events, so we need to create the default event loop and then attach wifi events to the event loop and their respective handlers.

Here our example_connect() is like db_connect() funtion most used in server side codes, its already feeded with the details required for the connection, once we call the function it tries to connect, if returned ok program will continue or ESP_ERROR_CHECK() will initiate a reboot.

Connection and reconnection all managed via these two events IP_EVENT_STA_GOT_IP and WIFI_EVENT_STA_DISCONNECTED. the first one reconnect and the second one for disconnect.

Now we need to write these two handlers, lets start with connect handler. This is what we expect to do after got the IP connection established. Connect handler triggered when the wifi driver gets an IP from DHCP. This handler sets server configuration and then start the server. starting the server can be done via another function like start_server() which calls httpd_start() or else we can directly call the httpd_start() from the handler.

httpd_register_uri_handler(server, &hello); this line registers uri handler hello to the server.

static void connect_handler(void* arg, esp_event_base_t event_base,
                            int32_t event_id, void* event_data)
{
    httpd_handle_t* server = (httpd_handle_t*) arg;
    if (*server == NULL) {
        ESP_LOGI(TAG, "Starting webserver");

        httpd_handle_t server = NULL;
        httpd_config_t config = HTTPD_DEFAULT_CONFIG();
        config.lru_purge_enable = true;

        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, &hello);
           }
        else
        {
        ESP_LOGI(TAG, "Error in connection");
        *server == NULL;
        }
    }
}

and the disconnect handler uses the previously set server handle as an input and then control (stop) it via the handle. After stopping its best to set the server handle to null.

static void disconnect_handler(void* arg, esp_event_base_t event_base,
                               int32_t event_id, void* event_data)
{
    httpd_handle_t* server = (httpd_handle_t*) arg;
    if (*server) {
        ESP_LOGI(TAG, "Stopping webserver");
        httpd_stop(server);
        *server = NULL;
    }
}

we have added all detail to start the server but not the request responders, without these the server will listen but it have no idea about reply, as we have not added the details of URI “hello” (/hello). This will be passed to server event handler as URI structure object.

static const httpd_uri_t hello = {
    .uri       = "/hello",
    .method    = HTTP_GET,
    .handler   = hello_get_handler,
    /* Let's pass response string in user
     * context to demonstrate it's usage */
    .user_ctx  = "Hello World!"
};
static esp_err_t hello_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, "<h1>Hello Secure World!</h1>", -1); // -1 = use strlen()

    return ESP_OK;
}

Now the rest part of app_main() have the same content as the connect handler which will start the webserver with default configuration. Now build and upload the program and open the url to see if the server is up. Most of the code is copied from ESP-IDF official repo on github. Similar code can be found on /examples/protocols/http_server/simple . Comment below if you stuck at any point.

if everything goes good, you will see the page hosted on ESP32.

Leave a Comment