AsyncHTTPClientLight — Libreria HTTP asincrona (e sincrona!) per ESP32
Autore: Davide
Licenza: MIT
Versione: 2.0 (AsyncClient Evolution)
AsyncHTTPClientLight è una libreria HTTP leggera per ESP32 che offre richieste non bloccanti (asincrone) e bloccanti (sincrone), con gestione automatica di redirect, retry, timeout e logging dettagliato.
Nata per sostituire HTTPClient nei progetti dove la stabilità conta:
- Niente memory leak da connessioni non chiuse bene
- Redirect 302 gestiti correttamente (es. Google Apps Script, Adafruit IO)
- Log leggibile di ogni fase, per capire perché una richiesta fallisce
- Memoria prevedibile (buffer di risposta scelto da te)
✅ Modalità Asincrona — Richieste non bloccanti con state machine
✅ Modalità Sincrona — Richieste bloccanti (per setup o test)
✅ Modalità Mista — Usa entrambe nello stesso sketch
✅ HTTPS Automatico — Abilita WiFiClientSecure se l'URL contiene https://
✅ Redirect Automatico — Segue 301, 302, 303, 307, 308
✅ Retry Intelligenti — Riconnessioni automatiche configurabili
✅ Chunked Transfer — Supporto transfer-encoding: chunked
✅ Callback Unificata — Un'unica callback per tutti gli eventi
✅ Header Personalizzati — Aggiungi header HTTP custom (es. Authorization)
✅ Logging Avanzato — Debug su Serial e file (SD/SPIFFS/LittleFS)
✅ Buffer Esterno — Usa PSRAM per payload grandi (es. 50KB)
✅ FreeRTOS Compatible — Pensata per ambienti multi-task ESP32
- Clona o scarica il repository
- Copia la cartella nella tua libreria Arduino:
~/Arduino/libraries/AsyncHTTPClientLight - Riavvia Arduino IDE
Sketch → Include Library → Manage Libraries → AsyncHTTPClientLight
- Arduino.h (standard ESP32)
- WiFiClient.h (standard ESP32)
- WiFiClientSecure.h (standard ESP32, per HTTPS)
- vector, functional (STL standard)
- SD.h (opzionale, per logging su SD card)
- SPIFFS.h (opzionale, per logging su SPIFFS)
- LittleFS.h (opzionale, per logging su LittleFS)
#include <WiFi.h>
#include "AsyncHTTPClientLight.h"
AsyncHTTPClientLight http;
void handleEvent(HTTPEventType type, const HTTPResponse* res) {
if (type == HTTPEventType::Response) {
Serial.printf("HTTP %d\n", res->statusCode);
Serial.println(http.getResponsePayload());
}
}
void setup() {
Serial.begin(115200);
WiFi.begin("SSID", "PASSWORD");
while (WiFi.status() != WL_CONNECTED) delay(500);
http.setDebug(true);
http.onEvent(handleEvent);
http.addTitle("Mia richiesta");
http.beginRequest("https://api.example.com/data", "GET");
}
void loop() {
http.poll(); // ← IMPORTANTE: chiamare a ogni loop()
delay(100);
}void setup() {
WiFi.begin("SSID", "PASSWORD");
while (WiFi.status() != WL_CONNECTED) delay(500);
int httpCode = http.runSync("https://api.example.com/data", "GET");
Serial.printf("HTTP %d\n", httpCode);
Serial.println(http.getResponsePayload());
}
void loop() {}Ideale per applicazioni real-time dove il loop deve continuare a girare.
http.beginRequest(url, "POST", jsonPayload); // Avvia, non aspetta
// Nel loop():
http.poll(); // Gestisci state machine
if (http.isFinished()) {
Serial.println(http.getResponsePayload());
}Vantaggi:
- Loop non si ferma
- Puoi gestire sensori, pulsanti, display mentre la richiesta è in corso
- Callback notifica quando la risposta arriva
Svantaggi:
- Un po' più complessa da usare
- Una sola richiesta alla volta (le altre arrivano con
Overload)
Ideale per setup iniziale, configurazione, oppure sketch semplici.
int httpCode = http.runSync(url, "GET"); // Aspetta risposta
Serial.println(http.getResponsePayload());Vantaggi:
- Semplice da usare
- API diretta: chiami e hai subito la risposta
Svantaggi:
- Loop è bloccato durante la richiesta
- Non puoi controllare sensori/pulsanti/display durante
Usa modalità asincrona nel loop, e sincrona dove serve una risposta immediata.
void loop() {
http.poll(); // Asincrona
if (someEvent) {
int code = http.runSync(url, "GET"); // Sincrona
// runSync() completa la richiesta asincrona precedente, se in corso
}
}| Funzione | Descrizione |
|---|---|
beginRequest(url, method, payload) |
Avvia richiesta asincrona |
runSync(url, method, payload) |
Richiesta sincrona, ritorna HTTP code |
poll() |
Chiama a ogni loop(): gestisce state machine |
isFinished() |
Verifica se richiesta completata |
getLastHTTPcode() |
Codice HTTP (200, 404, ecc.) |
getResponsePayload() |
Buffer della risposta |
setResponsePayload(buffer, size) |
Buffer esterno (PSRAM) |
addHeader(key, value) |
Aggiungi header HTTP |
addTitle(label) |
Etichetta per logging |
setTimeout(ms) |
Timeout richiesta (default 10000) |
setMaxRetries(n) |
Tentativi su timeout (default 1) |
setmaxRedirects(n) |
Max redirect da seguire (default 1) |
setDebug(true) |
Abilita log su Serial |
setLogToFile(true) |
Salva log su SD/SPIFFS/LittleFS |
onEvent(callback) |
Callback per eventi HTTP |
void handleEvent(HTTPEventType type, const HTTPResponse* res) {
switch (type) {
case HTTPEventType::Response:
Serial.printf("✅ HTTP %d\n", res->statusCode);
Serial.println(http.getResponsePayload()); // ← valido solo qui!
break;
case HTTPEventType::Timeout:
Serial.printf("⏱️ Timeout: %s (retry...)\n", res->msg_error);
break;
case HTTPEventType::Error:
Serial.printf("❌ Errore: %s\n", res->msg_error);
break;
case HTTPEventType::Overload:
Serial.println("⚠️ Richiesta precedente ancora in corso");
break;
case HTTPEventType::Chunk:
Serial.printf("📦 Chunk: %d bytes\n", res->contentLength);
break;
default:
break;
}
}
http.onEvent(handleEvent);Nota importante: Il payload http.getResponsePayload() è valido solo dentro la callback. Dopo che la callback torna, il buffer viene liberato per la prossima richiesta.
Automatico. Se l'URL contiene https://, la libreria abilita da sola WiFiClientSecure e usa setInsecure().
// Questo basta:
http.beginRequest("https://api.example.com/data", "GET");setInsecure()). La connessione è cifrata ma non autenticata — chi sniffa la rete potrebbe fingersi il server. Va bene per dati non sensibili (meteo, log, telemetria). Per token o credenziali importanti, non è adatto (serve un'upgrade con setCACert()).
Mostra GET e POST bloccanti, utile per setup.
- Invia JSON ogni 60s
- Gestisce il 302 redirect di Apps Script
- Callback unificata
- Riconnessione WiFi automatica
- Buffer PSRAM 50KB
- Parse JSON con ArduinoJson v7
- API key negli header (X-AIO-Key)
- Caso d'uso reale: scarica 1000 record e li processa
Copia uno di questi file dal folder examples/ e adattalo ai tuoi parametri.
http.setDebug(true);Output di esempio:
[REQ 1] === Mia richiesta ===
[REQ 1] Protocollo: HTTPS
[REQ 1] Host: api.example.com
[REQ 1] Porta: 443
[REQ 1] Tentativo 1
[REQ 1] Connessione riuscita
[REQ 1] Sending...
[REQ 1] Status code: 200
[REQ 1] Content-Length: 512
- Apri
src/AsyncHTTPClientLight.cpp - Cambia le linee iniziali:
#define ASYNC_HTTP_DEBUG 1 // 0 per disabilitare
#if ASYNC_HTTP_DEBUG
#define ASYNC_HTTP_LOG_SD // oppure _SPIFFS o _LittleFS
#define MAXSIZEFILE_LOG 512000 // Max 512 KB prima rotazione
#endif- Nel tuo sketch:
http.setLogToFile(true);- I log vanno in:
/http_log.txt(attivo)/old_Log.txt(rotazione precedente)
// ✅ GIUSTO: leggi dentro la callback
void handleEvent(HTTPEventType type, const HTTPResponse* res) {
if (type == HTTPEventType::Response) {
Serial.println(http.getResponsePayload());
}
}
// ❌ SBAGLIATO: il buffer è stato già liberato
Serial.println(http.getResponsePayload()); // → garbagevoid loop() {
http.poll(); // ← OBBLIGATORIO per modalità asincrona
// ... resto del codice
}Se avvi una nuova richiesta mentre ce n'è una in corso, ricevi Overload nella callback.
if (http.isFinished()) {
http.beginRequest(url, "GET"); // OK
} else {
Serial.println("Richiesta precedente ancora in corso");
}Il buffer interno è 768 byte. Per download di decine di KB, usa PSRAM:
char* bigBuffer = (char*)ps_malloc(50000); // 50 KB
http.setResponsePayload(bigBuffer, 50000);
http.beginRequest(url, "GET");
// Dopo la callback:
free(bigBuffer);→ Abilita il log: http.setDebug(true). Leggi il prefisso [REQ n] nel Serial Monitor per capire dove blocca (connessione, timeout, DNS, ecc).
→ Aumenta il timeout: http.setTimeout(15000) (15 secondi). Alcuni server rispondono lentamente al primo hit.
→ Aumenta i redirect: http.setmaxRedirects(5). Default è 1.
→ Usa un buffer esterno più grande: http.setResponsePayload(bigBuf, bigSize). Il buffer interno è solo 768 byte.
→ Controlla che chiami poll() a ogni loop(). Se la salti, le risorse non si liberano.
→ Aggiungi controllo WiFi nel loop:
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi perso, riconnetto...");
WiFi.reconnect();
return;
}struct HTTPResponse {
int statusCode; // 200, 404, 500, -1 se errore
uint32_t restime; // Tempo di risposta (ms)
char inprogressTitle[64]; // Etichetta della richiesta
char contentType[45]; // "application/json", ecc.
int contentLength; // Lunghezza payload (bytes)
bool isStream; // Trasferimento a lunghezza fissa
bool isChunked; // Trasferimento chunked
int expectedLength; // Lunghezza attesa chunk
char* ptr_workbuffer; // Buffer interno
char msg_error[50]; // Messaggio errore
};enum class HTTPEventType {
Response, // Risposta ricevuta (status 200, 404, ecc)
Error, // Errore generico (connessione, parsing)
Timeout, // Timeout raggiunto (retry automatico)
Overload, // Richiesta già in corso
Chunk, // Dati chunked ricevuti (parziale)
Receiving, // Ricezione in corso
Line // Linea ricevuta (non chunked)
};| Caso d'uso | Usa | Perché |
|---|---|---|
| Setup WiFi, carica config | runSync() |
Semplice, una volta sola |
| Sensore periodico ogni 1 min | beginRequest() + poll() |
Loop non si ferma |
| Download file grande | setResponsePayload() + beginRequest() |
Buffer PSRAM |
| API con auth Bearer | addHeader("Authorization", "Bearer...") |
Header custom |
| Google Sheets o Adafruit IO | setmaxRedirects(3) |
Gestiscono redirect |
| Debug: perché fallisce? | setDebug(true) + Serial |
Log dettagliato |
- Richiesta lenta:
https://httpbin.org/delay/5(aspetta 5s) - Errore 404:
https://httpbin.org/status/404 - JSON valido:
https://httpbin.org/json - POST echo:
https://httpbin.org/post(ritorna quello che invii)
Questa libreria è progettata per chi fa IoT, data logging e telemetria su ESP32 e vuole stabilità e trasparenza. Ogni funzione è stata scelta per offrire controllo senza complicazioni.
Se HTTPClient ti ha dato problemi, AsyncHTTPClientLight risolve quelli più comuni (memory leak, redirect, timeout misterioso).
MIT License — usala, modificala, condividila liberamente.
Maintainer: Davide (copida.soft@gmail.com)
Repository: https://github.com/copida/AsyncHTTPClientLight