Esp8266 client, odbiór danych od serwera przez SSE
text/event-stream
. WiFiClient
(lub WiFiClientSecure
dla HTTPS) i własne parsowanie ramek SSE (data: …\n\n
). Accept: text/event-stream
, Connection: keep-alive
), nieblokujące odczyty, automatyczne ponowne łączenie i opcjonalne wykorzystanie pól id:
/retry:
do wznawiania strumienia.id: 157
event: alarm
data: {"level": "HIGH", "ts": 1680042000}
\n\n
). id:
umożliwia wznowienie strumienia (Last-Event-ID
w nagłówku żądania). retry:
podpowiada klientowi, po ilu ms ma próbować ponownie po zerwaniu.#include <ESP8266WiFi.h>
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASS";
const char* host = "192.168.1.100";
const uint16_t port = 5000;
const char* path = "/events";
WiFiClient client;
String lastEventID = "";
uint32_t lastReconnect = 0;
const uint32_t reconnectMs = 5000;
void connectSSE() {
if (!client.connect(host, port)) return;
client.printf("GET %s HTTP/1.1\r\nHost: %s\r\n"
"Accept: text/event-stream\r\n"
"Connection: keep-alive\r\n"
"%s\r\n",
path, host,
lastEventID.length() ? ("Last-Event-ID: " + lastEventID + "\r\n").c_str() : "\r\n");
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) delay(250);
connectSSE();
}
void loop() {
// automatyczne ponowne łączenie
if (!client.connected() && millis() - lastReconnect > reconnectMs) {
client.stop();
connectSSE();
lastReconnect = millis();
return;
}
static String buffer; // gromadzi linie
while (client.connected() && client.available()) {
String line = client.readStringUntil('\n'); // wczytaj linię
if (line.length() && line[0] == '\r') line = ""; // CRLF -> usuń CR
if (line == "") { // koniec ramki
if (buffer.length()) {
Serial.println("[EVENT]\n" + buffer);
buffer = "";
}
continue;
}
if (line.startsWith("id:")) lastEventID = line.substring(3);
else if (line.startsWith("data:")) buffer += line.substring(5) + "\n";
// opcjonalnie: obsługa event:, retry:
}
}
lastEventID
, by przy ponownym łączeniu dosłać brakujące zdarzenia.#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
WiFiClientSecure client;
// client.setFingerprint("AB:CD:…"); // lub client.setInsecure() do testów
TLS zwiększa zużycie RAM (~15 kB) i wymaga wydłużonych timeoutów.
Specyfikacja dopuszcza kilka linii data:
wewnątrz jednej wiadomości. Należy je scalać separatorami \n
, co w przykładzie realizuje zmienna buffer
.
String
jest wygodny, ale fragmentuje heap. char buf[256];
size_t idx = 0;
int c;
while ((c = client.read()) >= 0 && idx < sizeof(buf)-1) { … }
StaticJsonDocument
.retry:
serwera => adaptacyjne ponawianie. yield()
. setTimeout()
dla WiFiClient
, co ułatwia kontrolę blokujących operacji. bblanchon/ArduinoSSEClient
(2024-03) pojawiła się pierwsza, lekka biblioteka obsługująca SSE z automatycznym parsowaniem event
/data
. Wciąż eksperymentalna. AsyncEventSource
(część ESPAsyncWebServer) – na razie dostępna tylko dla serwera; prace nad klientem są w toku. deserializeJson()
:DynamicJsonDocument doc(256);
deserializeJson(doc, buffer);
float temp = doc["temp"];
:\n
) zapobiega time-outom w niektórych proxy.curl -N http://…/events
). MODEM_SLEEP
, ale nie usypiaj całego radia – zerwie to połączenie SSE. /events/temperature
, /events/humidity
, by uprościć parsowanie.ESP8266HTTPClient
nie był projektowany do długotrwałych połączeń; przy strumieniach > 15 min potrafi błędnie zwalniać bufor. Lepiej użyć „gołego” WiFiClient
. Cache-Control: no-transform
), bo ESP8266 nie ma wbudowanego dekompresora. ArduinoSSEClient
pod kątem stabilności i zużycia RAM. ESP8266 potrafi w pełni obsłużyć protokół Server-Sent Events w roli klienta – wystarczy utrzymać otwarte połączenie HTTP, poprawnie zbudować nagłówki i linia po linii parsować ramki zakończone \n\n
. Najpewniejsze jest użycie WiFiClient
, własnego bufora i logiki ponawiania połączeń z uwzględnieniem id:
/retry:
. Zapewnienie HTTPS, zarządzanie pamięcią i watchdogiem podnosi niezawodność w aplikacjach produkcyjnych.