Chapter 93: HTTP Client Implementation in ESP-IDF
Chapter Objectives
After completing this chapter, you will be able to:
- Understand the fundamental concepts of the HTTP protocol, including request methods, headers, status codes, and message bodies.
- Utilize the ESP-IDF
esp_http_client
component to make HTTP requests from your ESP32. - Implement HTTP GET requests to retrieve data from web servers.
- Implement HTTP POST requests to send data to web servers.
- Handle and parse HTTP responses, including status codes, headers, and body content.
- Understand how to work with different types of response bodies, including chunked data.
- Configure various parameters of the HTTP client, such as URL, method, headers, and timeouts.
- Implement basic error handling for HTTP client operations.
- Appreciate the role of HTTP in IoT applications for interacting with web services and APIs.
Introduction
In today’s interconnected world, the Hypertext Transfer Protocol (HTTP) is the backbone of the World Wide Web and a primary means for devices and applications to exchange information. For an IoT device like the ESP32, being able to act as an HTTP client is crucial. It allows the ESP32 to fetch data from web servers (e.g., weather information, time synchronization, configuration files), send sensor readings to cloud platforms, interact with RESTful APIs, and much more.
Chapter 85 introduced TCP socket programming, which forms the foundation upon which HTTP operates. While you could technically implement HTTP by manually crafting requests and parsing responses over a TCP socket, this is complex and error-prone. Fortunately, ESP-IDF provides a dedicated esp_http_client
component that abstracts these low-level details, offering a robust and easy-to-use API for HTTP communication.
This chapter will delve into the basics of HTTP and then focus on the practical implementation of an HTTP client on the ESP32 using the esp_http_client
library. We will cover making GET and POST requests, handling responses, and common configurations, empowering your ESP32 to become an active participant in the web-connected ecosystem. The next chapter, Chapter 94, will build upon this by specifically addressing HTTPS for secure communication.
Theory
HTTP (Hypertext Transfer Protocol) Overview
HTTP is an application-layer protocol designed for distributed, collaborative, hypermedia information systems. It follows a request-response model where a client sends a request message to a server, and the server replies with a response message.
Key Components of HTTP:
- URL (Uniform Resource Locator):A URL specifies the resource to be accessed and the server hosting it. A typical HTTP URL structure is:scheme://host:port/path?query#fragment
scheme
:http
(orhttps
for secure HTTP).host
: Domain name (e.g.,www.example.com
) or IP address of the server.port
: Server port number (default is 80 for HTTP, 443 for HTTPS).path
: Path to the specific resource on the server (e.g.,/api/data
).query
: Optional parameters as key-value pairs (e.g.,?id=123&type=sensor
).fragment
: Optional identifier for a specific part of the resource (processed client-side).
Component | Example | Description |
---|---|---|
scheme |
http , https |
Protocol to be used (e.g., HTTP or HTTPS for secure HTTP). |
host |
www.example.com , 192.168.1.100 |
Domain name or IP address of the server. |
port |
80 , 443 , 8080 |
Server port number. Default is 80 for HTTP and 443 for HTTPS. Optional if default. |
path |
/api/data , /index.html |
Path to the specific resource on the server. |
query |
?id=123&type=sensor |
Optional parameters as key-value pairs, starting with a ‘?’. |
fragment |
#section2 |
Optional identifier for a specific part of the resource (processed client-side), starting with a ‘#’. |
- HTTP Methods (Verbs):Indicate the desired action to be performed on the resource. Common methods include:
- GET: Requests a representation of the specified resource. Used for retrieving data. Should be idempotent (multiple identical requests have the same effect as a single request) and should not have side effects (i.e., not change server state).
- POST: Submits data to be processed to the identified resource. Often used to create new resources or submit forms. Not necessarily idempotent.
- PUT: Replaces all current representations of the target resource with the request payload. Idempotent.
- DELETE: Removes the specified resource. Idempotent.
- HEAD: Similar to GET, but the server must not return a message body in the response. Useful for checking resource metadata (like
Content-Length
orLast-Modified
) without transferring the entire resource. - OPTIONS: Describes the communication options for the target resource.
- PATCH: Applies partial modifications to a resource.
Method | Description | Idempotent? | Has Body? (Typically) |
---|---|---|---|
GET | Requests a representation of the specified resource. Used for retrieving data. | Yes | No (Request body has no defined semantics) |
POST | Submits data to be processed to the identified resource (e.g., creating a new resource, submitting a form). | No | Yes (Request body contains data to submit) |
PUT | Replaces all current representations of the target resource with the request payload. | Yes | Yes (Request body is the new representation) |
DELETE | Removes the specified resource. | Yes | No (Request body has no defined semantics) |
HEAD | Similar to GET, but the server must not return a message body in the response. Used to get metadata (headers) about a resource without transferring its content. | Yes | No |
OPTIONS | Describes the communication options (e.g., allowed methods, headers) for the target resource. | Yes | No (Can have a body in some cases, but often not) |
PATCH | Applies partial modifications to a resource. | No | Yes (Request body contains instructions for modification) |
- HTTP Headers:Provide metadata about the HTTP request or response, or about the object sent in the message body. Headers are key-value pairs.
- Request Headers: Sent by the client. Examples:
Host
: The domain name of the server (mandatory for HTTP/1.1).User-Agent
: Information about the client software (e.g.,ESP32 HTTP Client
).Accept
: Media types the client can understand (e.g.,application/json
,text/html
).Content-Type
: The media type of the body of the request (for POST, PUT). E.g.,application/json
,application/x-www-form-urlencoded
.Content-Length
: The length of the request body in bytes.Authorization
: Authentication credentials (e.g.,Bearer <token>
).
- Request Headers: Sent by the client. Examples:
Header | Description | Example Value |
---|---|---|
Host | The domain name of the server (and optionally the port number). Mandatory for HTTP/1.1. | www.example.com |
User-Agent | A string identifying the client software making the request. | ESP32 HTTP Client/1.0 |
Accept | Media types that are acceptable for the response. | application/json , text/html , */* |
Content-Type | The media type of the body of the request (used with POST, PUT, PATCH). | application/json , application/x-www-form-urlencoded |
Content-Length | The length of the request body in bytes (used with POST, PUT, PATCH). | 128 |
Authorization | Contains credentials to authenticate the client with the server. | Bearer your_api_token , Basic YWxhZGRpbjpvcGVuc2VzYW1l |
Connection | Controls whether the network connection stays open after the current transaction finishes. | keep-alive , close |
Accept-Encoding | Indicates the content encodings (e.g., compression algorithms) the client can understand. | gzip , deflate |
- Response Headers: Sent by the server. Examples:
Content-Type
: The media type of the response body.Content-Length
: The length of the response body.Server
: Information about the server software.Date
: The date and time the response was generated.Location
: Used in redirections (with 3xx status codes).Set-Cookie
: Sends a cookie from the server to the client.
Header | Description | Example Value |
---|---|---|
Content-Type | The media type of the resource in the response body. | application/json , text/html; charset=utf-8 |
Content-Length | The length of the response body in bytes. Not present if Transfer-Encoding is chunked. | 1024 |
Server | Information about the server software that generated the response. | Apache/2.4.1 (Unix) , nginx/1.18.0 |
Date | The date and time at which the message was originated. | Tue, 27 May 2025 12:00:00 GMT |
Location | Used in redirection responses (3xx status codes) to specify the new URL. | /new-resource , http://www.newdomain.com/ |
Set-Cookie | Sends a cookie from the server to the client. | session_id=abc123xyz; Path=/; HttpOnly |
Cache-Control | Directives for caching mechanisms in both requests and responses. | no-cache , max-age=3600 |
Transfer-Encoding | Specifies the form of encoding used to safely transfer the payload body to the user. | chunked |
- HTTP Status Codes:Three-digit codes in the response indicating the outcome of the request. Grouped into classes:
- 1xx (Informational): Request received, continuing process. (Rarely handled directly by simple clients)
- 2xx (Successful): The action was successfully received, understood, and accepted.
200 OK
: Standard response for successful HTTP requests.201 Created
: The request has been fulfilled and resulted in a new resource being created.204 No Content
: The server successfully processed the request but is not returning any content.
- 3xx (Redirection): Further action needs to be taken by the user agent to fulfill the request.
301 Moved Permanently
: The resource has been assigned a new permanent URI.302 Found
(or307 Temporary Redirect
): The resource temporarily resides under a different URI.
- 4xx (Client Error): The request contains bad syntax or cannot be fulfilled.
400 Bad Request
: The server cannot or will not process the request due to an apparent client error.401 Unauthorized
: Authentication is required and has failed or has not yet been provided.403 Forbidden
: The server understood the request but refuses to authorize it.404 Not Found
: The server has not found anything matching the Request-URI.
- 5xx (Server Error): The server failed to fulfill an apparently valid request.
500 Internal Server Error
: A generic error message, given when an unexpected condition was encountered.503 Service Unavailable
: The server is currently unable to handle the request (e.g., overloaded or down for maintenance).
Status Code Range | Class | Meaning | Common Examples |
---|---|---|---|
1xx | Informational | Request received, server is continuing the process. Client should continue or wait. | 100 Continue , 101 Switching Protocols |
2xx | Successful | The request was successfully received, understood, and accepted. | 200 OK , 201 Created , 204 No Content |
3xx | Redirection | Further action must be taken by the client to complete the request (often involving a new URL). | 301 Moved Permanently , 302 Found , 304 Not Modified , 307 Temporary Redirect |
4xx | Client Error | The request contains bad syntax or cannot be fulfilled by the server as is. The client may need to modify the request. | 400 Bad Request , 401 Unauthorized , 403 Forbidden , 404 Not Found |
5xx | Server Error | The server failed to fulfill an apparently valid request. The problem is on the server’s side. | 500 Internal Server Error , 502 Bad Gateway , 503 Service Unavailable |
Key HTTP Status Codes:
Code | Meaning | Brief Description |
---|---|---|
200 | OK | Standard response for successful HTTP requests. |
201 | Created | The request has been fulfilled and resulted in a new resource being created. |
204 | No Content | The server successfully processed the request but is not returning any content. |
301 | Moved Permanently | The resource has been assigned a new permanent URI. Future requests should use the new URI. |
302 | Found | The resource temporarily resides under a different URI. (Often used for temporary redirects). |
307 | Temporary Redirect | Similar to 302, but guarantees that the method and body will not be changed when the redirected request is made. |
400 | Bad Request | The server cannot or will not process the request due to an apparent client error (e.g., malformed request syntax). |
401 | Unauthorized | Authentication is required and has failed or has not yet been provided. |
403 | Forbidden | The server understood the request but refuses to authorize it. Access is denied. |
404 | Not Found | The server has not found anything matching the Request-URI. |
500 | Internal Server Error | A generic error message, given when an unexpected condition was encountered by the server. |
503 | Service Unavailable | The server is currently unable to handle the request (e.g., overloaded or down for maintenance). |
- HTTP Message Body (Payload):Optional data sent with the request (e.g., for POST, PUT) or returned in the response (e.g., for GET). The format of the body is specified by the Content-Type header. Common formats include HTML, JSON, XML, plain text, binary data.
ESP-IDF esp_http_client
Component
The esp_http_client
component in ESP-IDF provides a high-level API for performing HTTP/HTTPS requests. It handles many complexities like connection management, request formatting, and response parsing.
Key Features:
- Supports HTTP and HTTPS (HTTPS requires additional configuration, covered in Chapter 94).
- Supports common HTTP methods (GET, POST, PUT, DELETE, HEAD, PATCH, OPTIONS).
- Automatic redirection handling (3xx status codes).
- Authentication support (Basic, Digest).
- Supports chunked transfer encoding for both request and response.
- Configurable timeouts.
- Event-driven: Emits events for various stages of the HTTP transaction (e.g., connected, header received, data received).
Core Workflow:
graph TD A[Start: Define Request Needs] --> B["1- Configuration<br>(esp_http_client_config_t)<br>- URL, method, event_handler<br>- timeouts, certs (HTTPS), etc."]; B --> C["2- Initialization<br>client = esp_http_client_init(&config)"]; C --> D{Set Custom Options?}; D -- Yes --> E["3a- Set Headers (Optional)<br>esp_http_client_set_header()"]; E --> F{Method is POST/PUT?}; F -- Yes --> G["3b- Set POST Data (Optional)<br>esp_http_client_set_post_field()"]; G --> H["4- Perform Request<br>err = esp_http_client_perform(client)<br>OR<br>Manual Open/Write/Read/Close"]; F -- No --> H; D -- No --> H; H --> I{Event Handler Registered?}; I -- Yes --> J["Events Triggered:<br>- HTTP_EVENT_ON_CONNECTED<br>- HTTP_EVENT_ON_HEADER<br>- HTTP_EVENT_ON_DATA<br>- HTTP_EVENT_ON_FINISH<br>- HTTP_EVENT_ERROR<br>- HTTP_EVENT_DISCONNECTED<br>- HTTP_EVENT_REDIRECT"]; J --> K["5- Handle Response in Event Handler<br>- Get status code, headers<br>- Process/Store body data (evt->data)"]; I -- No (Using perform() synchronously) --> L["5- Get Response Info after perform()<br>- esp_http_client_get_status_code()<br>- esp_http_client_get_content_length()<br>- esp_http_client_read() (if needed)"]; K --> M["6- Cleanup<br>esp_http_client_cleanup(client)"]; L --> M; M --> N[End: Request Complete / Cleaned up]; classDef primary fill:#EDE9FE,stroke:#5B21B6,stroke-width:2px,color:#5B21B6; classDef decision fill:#FEF3C7,stroke:#D97706,stroke-width:1px,color:#92400E; classDef process fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF; classDef io fill:#D1FAE5,stroke:#059669,stroke-width:1px,color:#065F46; classDef endo fill:#FEE2E2,stroke:#DC2626,stroke-width:1px,color:#991B1B; class A primary; class B,C,E,G,J,K,L process; class D,F,I decision; class H,M io; class N endo;
- Configuration (esp_http_client_config_t):Define the parameters for the HTTP request using the esp_http_client_config_t structure. Key fields include:
url
: The URL of the resource.host
,port
,path
,query
: Alternative tourl
for specifying components separately.method
: HTTP method (e.g.,HTTP_METHOD_GET
,HTTP_METHOD_POST
).event_handler
: A callback function to handle HTTP events.user_data
: Custom data to pass to the event handler.timeout_ms
: Connection timeout in milliseconds.disable_auto_redirect
: Set to true to disable automatic redirection.cert_pem
: For HTTPS, pointer to server root CA certificate (see Chapter 94).transport_type
:HTTP_TRANSPORT_OVER_TCP
orHTTP_TRANSPORT_OVER_SSL
.
- Initialization (esp_http_client_init()):Initialize an HTTP client instance with the configuration. Returns an esp_http_client_handle_t.
esp_http_client_config_t config = {
.url = "http://example.com/data",
.event_handler = _http_event_handler, // Your event handler function
};
esp_http_client_handle_t client = esp_http_client_init(&config);
- Setting Headers (Optional – esp_http_client_set_header()):Set custom request headers before performing the request.
esp_http_client_set_header(client, "Content-Type", "application/json");
esp_http_client_set_header(client, "User-Agent", "ESP32 HTTP Client");
- Setting POST Data (For POST/PUT – esp_http_client_set_post_field()):Set the data to be sent in the request body.
const char *post_data = "{\"key\":\"value\"}";
esp_http_client_set_post_field(client, post_data, strlen(post_data));
- Performing the Request (esp_http_client_perform()):This is a blocking function that executes the entire HTTP transaction (connect, send request, receive response). It internally handles events if no event handler is set up to read the response body directly. However, for more control and streaming large responses, using an event handler is recommended.
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %lld",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
} else {
ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
}
- Note:
esp_http_client_perform()
is a convenience function. For more fine-grained control (e.g., non-blocking operations, streaming large data), you would use functions likeesp_http_client_open()
,esp_http_client_write()
,esp_http_client_read()
,esp_http_client_fetch_headers()
, andesp_http_client_close()
. The examples will primarily use the event handler approach, which is more flexible. - HTTP Event Handler (esp_http_client_event_handler_t):A callback function that receives events during the HTTP transaction.
InsideHTTP_EVENT_ON_DATA
,evt->data
points to the received chunk of data, andevt->data_len
is its length.
esp_err_t _http_event_handler(esp_http_client_event_t *evt) {
switch(evt->event_id) {
case HTTP_EVENT_ERROR:
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADER_SENT:
ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
if (!esp_http_client_is_chunked_response(evt->client)) {
// Write data to a buffer or process it
// printf("%.*s", evt->data_len, (char*)evt->data);
}
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
break;
case HTTP_EVENT_REDIRECT: // Added in later ESP-IDF versions
ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
esp_http_client_set_redirection(evt->client); // Follow the redirect
break;
}
return ESP_OK;
}
- Getting Response Information:After esp_http_client_perform() or within/after HTTP_EVENT_ON_FINISH:
esp_http_client_get_status_code(client)
: Gets the HTTP status code.esp_http_client_get_content_length(client)
: Gets theContent-Length
from the response headers. Returns -1 if not present or if chunked encoding.esp_http_client_get_header(client, "Header-Key", &value)
: Gets a specific response header value.
- Reading Response Body:
- Small Responses (using
esp_http_client_perform
and thenesp_http_client_read
): If you don’t use an event handler to process data chunks, andesp_http_client_perform
was used, you might need to read the response body if it wasn’t buffered internally. However, the event handler is the preferred way for body processing. - Using Event Handler (
HTTP_EVENT_ON_DATA
): This is the most common and flexible way. Data arrives in chunks. You accumulate these chunks into a buffer or process them as they arrive. esp_http_client_read(client, buffer, len)
: Can be used to read data from the HTTP stream directly if needed, typically after headers are fetched.
- Small Responses (using
- Cleanup (esp_http_client_cleanup()):Release resources associated with the HTTP client instance.
esp_http_client_cleanup(client);
Key Config Fields:
Field Name | Type | Description |
---|---|---|
url |
const char * |
The full URL of the resource to access (e.g., “http://api.example.com/data”). |
host |
const char * |
Server host name or IP address. Used if url is not set or to override. |
port |
int |
Server port number. Defaults to 80 for HTTP, 443 for HTTPS if not specified. |
path |
const char * |
Path to the resource on the server (e.g., “/api/v1/status”). |
query |
const char * |
Query string part of the URL (e.g., “id=123&type=sensor”). |
method |
esp_http_client_method_t |
HTTP method to use (e.g., HTTP_METHOD_GET , HTTP_METHOD_POST ). |
event_handler |
esp_http_client_event_handler_t |
Callback function to handle HTTP events (e.g., data received, connection established). Highly recommended for flexible response handling. |
user_data |
void * |
Pointer to user-defined data that will be passed to the event handler. Useful for passing context or buffers. |
timeout_ms |
int |
Network timeout in milliseconds for the connection. Default is often 5000ms. |
disable_auto_redirect |
bool |
Set to true to disable automatic handling of HTTP 3xx redirection responses. Default is false (auto-redirect enabled). |
transport_type |
esp_http_client_transport_t |
Transport layer type: HTTP_TRANSPORT_OVER_TCP (for HTTP) or HTTP_TRANSPORT_OVER_SSL (for HTTPS). |
cert_pem |
const char * |
For HTTPS: Pointer to server root CA certificate in PEM format for server verification. (See Chapter 94) |
buffer_size |
int |
Size of the internal buffer used by the client for I/O operations. |
is_async |
bool |
Set to true for non-blocking (asynchronous) open. Default is false (blocking). If true, esp_http_client_perform() should not be used; use esp_http_client_open() , esp_http_client_write() , etc. |
Common ESP_HTTP_CLIENT_EVENTS:
Event ID (evt->event_id ) |
Description | Relevant evt Fields |
---|---|---|
HTTP_EVENT_ERROR |
An error occurred during the HTTP transaction. | evt->data (may contain error context), evt->data_len . Check esp_tls_get_and_clear_last_error() for TLS errors. |
HTTP_EVENT_ON_CONNECTED |
The client has successfully connected to the server. For HTTPS, SSL/TLS handshake is complete. | evt->client (client handle) |
HTTP_EVENT_HEADER_SENT |
All request headers have been sent to the server. | evt->client |
HTTP_EVENT_ON_HEADER |
A response header has been received. This event fires for each header. | evt->header_key , evt->header_value |
HTTP_EVENT_ON_DATA |
A chunk of the response body data has been received. | evt->data (pointer to data chunk), evt->data_len (length of chunk), evt->user_data (from config) |
HTTP_EVENT_ON_FINISH |
The HTTP response has been fully received (all data and closing markers). | evt->client |
HTTP_EVENT_DISCONNECTED |
The connection to the server has been closed. | evt->client |
HTTP_EVENT_REDIRECT |
A redirect (3xx) response was received and auto-redirect is disabled, or this event fires to inform about the redirect even if handled. | evt->client . Call esp_http_client_set_redirection(evt->client) to follow it if auto-redirect was off or to confirm. Check new URL with esp_http_client_get_url() . |
Chunked Transfer Encoding
If a server sends a response with Transfer-Encoding: chunked
, the Content-Length
header is usually absent. The body is sent in a series of chunks, each prefixed by its size in hexadecimal. The esp_http_client
handles chunked decoding transparently when you receive data via HTTP_EVENT_ON_DATA
. You can check if the response is chunked using esp_http_client_is_chunked_response(client)
.
sequenceDiagram participant Client participant Server Server->>Client: HTTP Response Headers <br>(Transfer-Encoding: chunked) Note over Server: Body sent in chunks Server->>Client: Chunk 1: Size_Hex_1 <br> Data_1 <br> Client->>Client: Process Data_1 (via HTTP_EVENT_ON_DATA) Server->>Client: Chunk 2: Size_Hex_2 <br> Data_2 <br> Client->>Client: Process Data_2 (via HTTP_EVENT_ON_DATA) Server->>Client: ... more chunks ... Server->>Client: Last Chunk: 0 <br> [Optional Trailers] Client->>Client: End of Body <br>(HTTP_EVENT_ON_FINISH triggered <br> after last chunk)
Practical Examples
Before running these examples, ensure your ESP32 is configured with Wi-Fi credentials (e.g., via idf.py menuconfig
-> Example Connection Configuration
).
Example 1: Simple HTTP GET Request
This example makes a GET request to http://worldtimeapi.org/api/ip
to fetch time information based on the public IP of your network and prints the response body.
Project Setup:
- Create a new ESP-IDF project:
idf.py create-project http_get_example
- Navigate into the project:
cd http_get_example
- Replace the content of
main/main.c
. - Configure Wi-Fi in
menuconfig
.
main/main.c
:
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_http_client.h"
#include "esp_netif.h" // Required for esp_netif_init
#define WIFI_SSID CONFIG_EXAMPLE_WIFI_SSID
#define WIFI_PASS CONFIG_EXAMPLE_WIFI_PASSWORD
#define MAX_FAILURES 10
#define MAX_HTTP_OUTPUT_BUFFER 2048
static const char *TAG = "http_get_example";
static EventGroupHandle_t s_wifi_event_group;
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static int s_retry_num = 0;
// Event handler for Wi-Fi
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < MAX_FAILURES) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG,"connect to the AP fail");
} 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, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
// Initialize Wi-Fi
void wifi_init_sta(void)
{
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init()); // Initialize TCP/IP stack
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&event_handler,
NULL,
&instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip));
wifi_config_t wifi_config = {
.sta = {
.ssid = WIFI_SSID,
.password = WIFI_PASS,
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
ESP_ERROR_CHECK(esp_wifi_start() );
ESP_LOGI(TAG, "wifi_init_sta finished.");
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "connected to ap SSID:%s", WIFI_SSID);
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG, "Failed to connect to SSID:%s", WIFI_SSID);
} else {
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
}
// HTTP event handler
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
static char *output_buffer; // Buffer to store response of http request
static int output_len; // Stores number of bytes read
switch(evt->event_id) {
case HTTP_EVENT_ERROR:
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADER_SENT:
ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
// If user_data is not NULL, it means buffer is passed from user, append data to it.
if (evt->user_data) {
memcpy(evt->user_data + output_len, evt->data, evt->data_len);
} else { // Otherwise, allocate new buffer and copy data.
if (output_buffer == NULL) {
// Allocate dynamic buffer to store response data
output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client));
output_len = 0;
if (output_buffer == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
return ESP_FAIL;
}
}
memcpy(output_buffer + output_len, evt->data, evt->data_len);
}
output_len += evt->data_len;
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
if (output_buffer != NULL) {
// Response is accumulated in output_buffer. Process it here.
ESP_LOGI(TAG, "Received data: %.*s", output_len, output_buffer);
free(output_buffer);
output_buffer = NULL;
output_len = 0;
}
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
// int mbedtls_err = 0;
// esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
// if (err != 0) {
// ESP_LOGI(TAG, "Last mbedtls error: 0x%x", mbedtls_err);
// }
if (output_buffer != NULL) { // Clean up buffer if disconnected before finish
free(output_buffer);
output_buffer = NULL;
output_len = 0;
}
break;
case HTTP_EVENT_REDIRECT:
ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
esp_http_client_set_redirection(evt->client);
break;
}
return ESP_OK;
}
static void http_get_task(void *pvParameters)
{
// Wait for Wi-Fi connection
xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
ESP_LOGI(TAG, "Connected to Wi-Fi, starting HTTP GET task.");
char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
esp_http_client_config_t config = {
.url = "http://worldtimeapi.org/api/ip",
.event_handler = _http_event_handler,
.user_data = local_response_buffer, // Pass address of local buffer to event handler
.disable_auto_redirect = false, // Handle redirects automatically
};
esp_http_client_handle_t client = esp_http_client_init(&config);
// Perform the HTTP request
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %lld",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
// The response body is printed by the event handler (HTTP_EVENT_ON_FINISH)
// using the local_response_buffer.
} else {
ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
}
esp_http_client_cleanup(client);
vTaskDelete(NULL);
}
void app_main(void)
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
wifi_init_sta();
xTaskCreate(&http_get_task, "http_get_task", 8192, NULL, 5, NULL);
}
CMakeLists.txt
(in main
directory):
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")
Project CMakeLists.txt (root of the project):
Ensure esp_http_client is linked by adding it to REQUIRES or PRIV_REQUIRES if not already present by default. Usually, it’s pulled in by other components like esp_netif. If you get linking errors, add it explicitly:
# ...
set(EXTRA_COMPONENT_DIRS)
# ...
idf_build_set_property(REQUIRES "esp_http_client" APPEND) # Or PRIV_REQUIRES
# ...
However, for most ESP-IDF v5.x projects, esp_http_client
should be available without explicit addition here if networking components are used.
Build and Flash Instructions:
- Set target:
idf.py set-target esp32
(or other variant) - Configure Wi-Fi:
idf.py menuconfig
->Example Connection Configuration
. - Build:
idf.py build
- Flash:
idf.py -p /dev/ttyUSB0 flash monitor
(replace port if needed)
Observe:
The ESP32 will connect to Wi-Fi, make the GET request, and the _http_event_handler will print the received JSON data from worldtimeapi.org to the serial monitor. The status code and content length will also be logged.
Example 2: HTTP POST Request
This example sends JSON data via a POST request to http://httpbin.org/post
, which is a service that echoes back the request details.
Project Setup: (Similar to GET example, new project http_post_example
)
main/main.c
:
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_http_client.h"
#include "esp_netif.h"
#define WIFI_SSID CONFIG_EXAMPLE_WIFI_SSID
#define WIFI_PASS CONFIG_EXAMPLE_WIFI_PASSWORD
#define MAX_FAILURES 10
#define MAX_HTTP_OUTPUT_BUFFER 2048
static const char *TAG = "http_post_example";
// Wi-Fi event group and event_handler, wifi_init_sta (same as GET example)
static EventGroupHandle_t s_wifi_event_group;
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static int s_retry_num = 0;
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < MAX_FAILURES) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG,"connect to the AP fail");
} 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, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
void wifi_init_sta(void)
{
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
wifi_config_t wifi_config = {
.sta = { .ssid = WIFI_SSID, .password = WIFI_PASS, .threshold.authmode = WIFI_AUTH_WPA2_PSK },
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
ESP_ERROR_CHECK(esp_wifi_start() );
ESP_LOGI(TAG, "wifi_init_sta finished.");
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
if (bits & WIFI_CONNECTED_BIT) { ESP_LOGI(TAG, "connected to ap SSID:%s", WIFI_SSID); }
else if (bits & WIFI_FAIL_BIT) { ESP_LOGI(TAG, "Failed to connect to SSID:%s", WIFI_SSID); }
else { ESP_LOGE(TAG, "UNEXPECTED EVENT"); }
}
// HTTP event handler (same as GET example, or simplified if only logging)
esp_err_t _http_event_handler_post(esp_http_client_event_t *evt)
{
static char *output_buffer_post; // Buffer to store response of http request
static int output_len_post; // Stores number of bytes read
switch(evt->event_id) {
case HTTP_EVENT_ERROR: ESP_LOGD(TAG, "HTTP_EVENT_ERROR"); break;
case HTTP_EVENT_ON_CONNECTED: ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED"); break;
case HTTP_EVENT_HEADER_SENT: ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT"); break;
case HTTP_EVENT_ON_HEADER: ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value); break;
case HTTP_EVENT_ON_DATA:
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
// For httpbin.org/post, the response body can be large, handle it carefully
// This example will just print parts of it or accumulate to a fixed buffer if small enough.
if (output_buffer_post == NULL && esp_http_client_get_content_length(evt->client) > 0 && esp_http_client_get_content_length(evt->client) < MAX_HTTP_OUTPUT_BUFFER) {
output_buffer_post = (char *) malloc(esp_http_client_get_content_length(evt->client) +1); // +1 for null terminator
output_len_post = 0;
if (output_buffer_post == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
return ESP_FAIL;
}
}
if (output_buffer_post && (output_len_post + evt->data_len < esp_http_client_get_content_length(evt->client))) {
memcpy(output_buffer_post + output_len_post, evt->data, evt->data_len);
output_len_post += evt->data_len;
} else if (output_buffer_post) { // Last chunk or buffer too small
memcpy(output_buffer_post + output_len_post, evt->data, esp_http_client_get_content_length(evt->client) - output_len_post);
output_buffer_post[esp_http_client_get_content_length(evt->client)] = '\0'; // Null terminate
ESP_LOGI(TAG, "Received POST response data: %s", output_buffer_post);
} else {
// If content length is unknown or too large, just print the chunk
ESP_LOGI(TAG, "Received chunk (%d bytes):", evt->data_len);
printf("%.*s\n", evt->data_len, (char*)evt->data);
}
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
if (output_buffer_post != NULL) {
// Ensure final part is logged if not done in ON_DATA
if (output_len_post < esp_http_client_get_content_length(evt->client) && esp_http_client_get_content_length(evt->client) > 0) {
// This case might happen if ON_DATA logic for last chunk was not hit
// For simplicity, we assume ON_DATA handled it or content_length was 0/too large
}
ESP_LOGI(TAG, "Final POST response (if fully buffered):\n%s", output_buffer_post);
free(output_buffer_post);
output_buffer_post = NULL;
output_len_post = 0;
}
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
if (output_buffer_post != NULL) {
free(output_buffer_post);
output_buffer_post = NULL;
output_len_post = 0;
}
break;
case HTTP_EVENT_REDIRECT:
ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
esp_http_client_set_redirection(evt->client);
break;
}
return ESP_OK;
}
static void http_post_task(void *pvParameters)
{
xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
ESP_LOGI(TAG, "Connected to Wi-Fi, starting HTTP POST task.");
esp_http_client_config_t config = {
.url = "http://httpbin.org/post",
.method = HTTP_METHOD_POST,
.event_handler = _http_event_handler_post,
// .user_data = local_response_buffer, // Can pass a buffer for response if needed
};
esp_http_client_handle_t client = esp_http_client_init(&config);
// Set POST data and Content-Type header
const char *post_data = "{\"sensor\":\"ESP32\", \"temperature\":25.7}";
esp_http_client_set_header(client, "Content-Type", "application/json");
esp_http_client_set_post_field(client, post_data, strlen(post_data));
ESP_LOGI(TAG, "Performing HTTP POST to %s", config.url);
ESP_LOGI(TAG, "POST data: %s", post_data);
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %lld",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
// Response body is handled by the event handler
} else {
ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
}
esp_http_client_cleanup(client);
vTaskDelete(NULL);
}
void app_main(void)
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
wifi_init_sta();
xTaskCreate(&http_post_task, "http_post_task", 8192, NULL, 5, NULL);
}
Build and Flash Instructions: (Same as GET example)
Observe:
The ESP32 will connect to Wi-Fi and send a POST request with JSON data to httpbin.org/post. The response from httpbin.org (which includes the data you sent, headers, etc.) will be printed to the serial monitor, handled by the _http_event_handler_post.
Example 3: Handling Chunked Data and Large Responses (Conceptual)
When expecting large responses or responses where the server uses Transfer-Encoding: chunked
, the HTTP_EVENT_ON_DATA
event is crucial. The esp_http_client
handles the de-chunking process transparently. Your event handler receives the actual data payload in evt->data
.
// ... (Inside _http_event_handler)
case HTTP_EVENT_ON_DATA:
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
// Check if it's a chunked response (optional, client handles de-chunking)
// if (esp_http_client_is_chunked_response(evt->client)) {
// ESP_LOGI(TAG, "Response is chunked.");
// }
// Dynamically allocate or append to a larger buffer
// For example, using a realloc strategy or a fixed large buffer.
// This example just prints the current chunk.
printf("Received chunk: %.*s\n", evt->data_len, (char *)evt->data);
// If you need to process the entire response at once, you'd accumulate
// evt->data into a larger buffer here.
// Remember to handle potential out-of-memory issues.
// Example:
// if (total_response_len + evt->data_len < MAX_MY_BUFFER) {
// memcpy(my_buffer + total_response_len, evt->data, evt->data_len);
// total_response_len += evt->data_len;
// } else {
// ESP_LOGE(TAG, "Response buffer overflow!");
// }
break;
// ...
Key considerations for large/chunked data:
- Memory Management: Be mindful of ESP32’s limited RAM. Avoid allocating excessively large static buffers. Consider processing data in chunks as it arrives or using
realloc
carefully if you need to accumulate the entire response. - Streaming: For very large files (e.g., firmware updates), you might stream the data directly to flash or another peripheral instead of buffering it all in RAM.
- Timeouts: Long downloads might require adjusting HTTP client timeouts (
timeout_ms
in config, oresp_http_client_set_timeout_ms
).
Variant Notes
The esp_http_client
component and its API are generally consistent across all ESP32 variants (ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6, ESP32-H2) when using ESP-IDF v5.x.
- Network Interface: The examples use Wi-Fi. If Ethernet is used, the network initialization part needs to change, but the
esp_http_client
usage remains the same. - Performance:
- CPU speed and available RAM can affect how quickly HTTP requests are processed and how large a response can be handled efficiently. Newer variants (ESP32-S3, C6, H2) generally offer better performance.
- For HTTPS (covered in Chapter 94), variants with hardware cryptographic acceleration (like ESP32, ESP32-S2, S3) will perform significantly better than those relying solely on software crypto.
- Memory Usage:
- The
esp_http_client
itself consumes some RAM for its internal buffers and state. - The size of buffers you allocate for receiving response data is a critical factor. Be particularly cautious on single-core variants (ESP32-C3) or those with less RAM.
- The
- TLS/SSL Stack: For HTTPS, the underlying mbedTLS library is used. Its memory footprint and performance characteristics are relevant.
The provided code examples should work on any supported ESP32 variant with appropriate Wi-Fi configuration and sufficient resources for the HTTP transaction and response handling.
Common Mistakes & Troubleshooting Tips
Mistake / Issue | Symptom(s) | Troubleshooting / Solution |
---|---|---|
Forgetting Network Initialization | HTTP requests fail with DNS lookup errors (ESP_ERR_HTTP_DNS_LOOKUP_FAILED ) or connection timeouts (ESP_ERR_HTTP_CONNECT ). |
Fix: Ensure Wi-Fi/Ethernet is connected and an IP address is obtained before initiating HTTP client operations. Use event groups for synchronization. |
Incorrect URL / Host / Path | DNS lookup failures, connection errors, or 404 Not Found status codes. |
Fix: Double-check the URL for typos. Verify scheme (http vs https ). Test the URL with curl or a browser. Log the configured URL from ESP32. |
Not Checking HTTP Status Codes | Application processes error pages or unexpected data as if it were a successful response, leading to crashes or bugs. | Fix: Always call esp_http_client_get_status_code() after esp_http_client_perform() or in the HTTP_EVENT_ON_FINISH event. Handle 4xx and 5xx errors appropriately. |
Response Body Buffer Overflows | Data corruption, crashes (Guru Meditation Error) due to writing past buffer boundaries when handling response data. | Fix: Check Content-Length (if available) to size buffers. In HTTP_EVENT_ON_DATA , carefully manage buffer offsets and sizes. For large/chunked data, process in chunks or stream to flash instead of buffering all in RAM. |
Missing/Incorrect Content-Type for POST/PUT |
Server rejects request (e.g., 400 Bad Request , 415 Unsupported Media Type ) or fails to parse the request body. |
Fix: Use esp_http_client_set_header(client, "Content-Type", "your_type") (e.g., application/json ) when sending data in the request body. |
Forgetting esp_http_client_cleanup() |
Memory leaks over time as client instances are not properly deallocated. | Fix: Always call esp_http_client_cleanup(client_handle) when the HTTP client is no longer needed to free allocated resources. |
Handling HTTPS without Proper Setup | Connection fails for HTTPS URLs, often with TLS/SSL handshake errors. | Fix: For HTTPS, ensure transport_type is HTTP_TRANSPORT_OVER_SSL and provide a valid server root CA certificate via cert_pem in the config. (Covered in Chapter 94). |
Stack Overflow in HTTP Task | Random crashes or Guru Meditation errors, especially when handling large responses or complex parsing. | Fix: Increase the stack size for the FreeRTOS task that runs the HTTP client operations, especially if significant processing or large local buffers are used within the task or event handler. |
Tip: Use
ESP_LOGx
extensively to trace the HTTP client’s behavior, including configured URLs, headers, status codes, and data events. Tools likecurl
or Postman are invaluable for testing HTTP endpoints from a PC before implementing on ESP32.
Exercises
- Fetch and Parse Weather Data:
- Choose a free public weather API that provides data in JSON format (e.g., OpenWeatherMap, WeatherAPI.com – check their terms for free tiers and API key requirements).
- Write an ESP32 application to make an HTTP GET request to the weather API for a specific city.
- In the
HTTP_EVENT_ON_DATA
orHTTP_EVENT_ON_FINISH
handler, accumulate the JSON response. - Use the
cJSON
library (available as an ESP-IDF component) to parse the JSON response and extract key information like temperature, humidity, and weather description. Log these values.
- POST ESP32 Chip Information:
- Write an application that collects some ESP32 chip information (e.g., using
esp_chip_info()
, Free Heap size usingesp_get_free_heap_size()
). - Format this information as a JSON object.
- Send this JSON object via an HTTP POST request to
http://httpbin.org/post
. - Verify from the
httpbin.org
response (which echoes your request) that the data was sent correctly.
- Write an application that collects some ESP32 chip information (e.g., using
- Implement Retry Logic for HTTP Requests:
- Modify the HTTP GET example. If
esp_http_client_perform()
fails or returns a server error status code (5xx), implement a retry mechanism. - The task should wait for a short period (e.g., 5 seconds) and then attempt the request again, up to a maximum number of retries (e.g., 3 times).
- Modify the HTTP GET example. If
- Custom HTTP Headers and Query Parameters:
- Extend the HTTP GET example to
http://httpbin.org/get
. - Add custom request headers:
User-Agent: My ESP32 Weather Station v1.0
X-API-Key: dummy-api-key-12345
(a fictional API key header)
- Modify the URL to include query parameters, for example:
http://httpbin.org/get?sensor_id=esp32_001&location=lab
. - Inspect the response from
httpbin.org/get
to verify that your custom headers and query parameters were received by the server.
- Extend the HTTP GET example to
Summary
- HTTP is a fundamental request-response protocol for web communication. Key elements include URLs, methods (GET, POST), headers, status codes, and message bodies.
- The ESP-IDF
esp_http_client
component provides a convenient API for ESP32 to act as an HTTP client. - Configuration is done via
esp_http_client_config_t
, specifying URL, method, event handler, etc. esp_http_client_init()
creates a client handle.esp_http_client_set_header()
andesp_http_client_set_post_field()
are used to customize requests.esp_http_client_perform()
executes the request, but using an event handler (HTTP_EVENT_ON_DATA
,HTTP_EVENT_ON_FINISH
, etc.) is recommended for flexible response processing, especially for large or chunked data.- Always check the HTTP status code (
esp_http_client_get_status_code()
) to determine the outcome of a request. - Properly manage memory when handling response bodies, especially large ones.
esp_http_client_cleanup()
must be called to release resources.- HTTP client functionality is essential for IoT devices to interact with web services, APIs, and cloud platforms.
Further Reading
- ESP-IDF Programming Guide – HTTP Client:
- MDN Web Docs – HTTP:
- RFC 7230-7235: Hypertext Transfer Protocol (HTTP/1.1) specifications (for deep understanding).
- httpbin.org: A great service for testing HTTP requests and responses.