Esp8266, odbiór danych od serwera przez WiFiClient w callback
WiFiClient w rdzeniu Arduino-ESP8266 nie ma wbudowanych callbacków dla zdarzenia dane dostępne. loop() lub timerze (polling nieblokujący). ESPAsyncTCP (lub wyższego poziomu ESPAsyncWebServer/WebSocket/MQTT), która udostępnia natywne zdarzenia onData(). Kluczowe punkty
• WiFiClient = synchroniczny; callback wymaga warstwy pośredniej.
• Podejście z pollingiem działa wszędzie, ale blokada pętli jest niedozwolona.
• ESPAsyncTCP daje prawdziwą asynchroniczność i czyste callbacki.
WiFiClient korzysta z górnej warstwy LWIP; w API Arduino wystawiono tylko funkcje blokujące (read, write, available), co upraszcza użycie, ale wymaga aktywnego sprawdzania stanu gniazda.
Tworzymy maszynę stanów; w każdej iteracji sprawdzamy:
void loop() {
if (client.connected() && client.available()) {
handleIncoming(); // <- nasz „callback”
}
otherTasks(); // czujniki, UI…
}
void handleIncoming() {
static String buf;
while (client.available()) {
char c = client.read();
buf += c;
}
if (buf.endsWith("\n")) { // np. kompletna linia
processLine(buf); // właściwy callback
buf = "";
}
}
• Brak blokowania — żadnych while(client.connected()), delay() ani długich printów.
• W długich pętlach zawsze yield(); lub delay(0); aby nie wywołać resetu WDT.
Ticker rxTicker;
void setup() {
rxTicker.attach_ms(50, []() { if (client.available()) handleIncoming(); });
}
• Ticker korzysta z systemowego timera i działa w tle; wciąż nie wolno wykonywać długich operacji w jego ISR — tylko szybkie skanowanie i ewentualnie ustawienie flagi do obróbki w loop().
ESPAsyncTCP#include <ESPAsyncTCP.h>
AsyncClient *async = nullptr;
void setup() {
async = new AsyncClient;
async->onConnect([](void*, AsyncClient*c){
c->onData([](void*, AsyncClient*, void* data, size_t len){
processData((char*)data, len); // natywny callback
}, nullptr);
c->write("GET / HTTP/1.1\r\nHost: ex.com\r\n\r\n");
}, nullptr);
async->connect("93.184.216.34", 80);
}
• Biblioteka wykorzystuje wewnętrzny core-timer i zadania LWIP → brak blokowania, brak pracy w ISR.
• Trzeba doinstalować ESPAsyncTCP (kompatybilna z core ≥ 2.7.4; dla core 3.x dostępny fork z gałęzi tekwiz).
Jeżeli serwer może publikować do brokera MQTT, najprościej użyć PubSubClient (polling, ale ma callback) lub AsyncMQTT. Analogicznie WebSocket (AsyncWebSocketClient).
String – lepiej użyć statycznego bufora char[512]. Długa obróbka w callbacku? Użyj kolejki i obróbki w loop(); w samym callbacku tylko kopiuj dane.
• Core Arduino-ESP8266 3.1.2 (2024-02) nadal nie dodał callbacków do WiFiClient.
• Forki AsyncTCP dla ESP8266 są aktualizowane; główna gałąź me-no-dev jest zamrożona, aktywne rozwidlenie: https://github.com/tekwiz/ESPAsyncTCP.
• Na nowych projektach coraz częściej migruje się do ESP32-C3/S3, gdzie IDF oferuje FreeRTOS + event-loop (callback natywny).
client.setTimeout(ms) tylko skraca blokujące funkcje; nie robi ich nieblokującymi. WiFiClientSecure lub BearSSL::WiFiClientSecure (pamiętaj o ładunku certyfikatu w PEM i limicie ~2 kB). 0\r\n\r\n. ESPAsyncTCP – LGPL-2.1); przy dystrybucji gotowego firmware należy udostępnić kod źródłowy zmian. Serial.setDebugOutput(true); podczas testów – zobaczysz logi LWIP. WiFi.setSleep(false) w czasie transmisji strumieniowej, aby uniknąć mikro-przerw. client.keepAlive(maxIdle, interval, probe);. WiFi.status(), a nie tylko client.connected(). ESPAsyncTCP nie współpracuje z delay() > 15 ms w loop() – zakłóca time-slice. Standardowy WiFiClient nie zapewnia callbacków – musisz:
loop()/Ticker → prostsze, przenośne. ESPAsyncTCP/AsyncWebServer/MQTT → prawdziwa asynchroniczność, czystszy kod, większa responsywność. Wybór zależy od złożoności projektu. Dla prototypu – polling; dla produkcyjnego, wielozadaniowego systemu – ESPAsyncTCP albo migracja na ESP32 z natywnym event-loop.