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.