ESP8266 SSE przykład kodu Arduino
text/event-stream
). id: 37
event: update
data: {"temp":24.7,"gpio":1}
Podwójna pusta linia kończy ramkę. Przeglądarka gwarantuje kolejność i dostarcza Last-Event-ID
przy ponownym łączeniu.
Aktualny trend (2024) w świecie ESP8266/ESP32 to biblioteki asynchroniczne:
loop()
)Synchronous ESP8266WebServer
nadal działa, lecz skaluje się jedynie na 1–2 klientów i wymaga ostrożnego unikania „while(true)” w handlerze (patrz poprawka poniżej).
/*****************************************************************
* ESP8266 | Server-Sent Events (SSE) – przykładowy projekt
* Biblioteki: ESPAsyncTCP, ESPAsyncWebServer (GitHub @me-no-dev)
*****************************************************************/
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
const char* ssid = "Twoja_SSID";
const char* password = "Twoje_Haslo";
AsyncWebServer server(80); // HTTP
AsyncEventSource events("/events"); // Endpoint SSE
//--- Symulowane dane -------------------------------------------------
float temperature = 24.0; // przykładowy czujnik
uint8_t gpioState = 0; // stan pinu D1
unsigned long lastMux = 0;
const unsigned long interval = 2000; // 2 s
//--------------------------------------------------------------------
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Łączenie");
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.printf("\nPołączono, IP: %s\n", WiFi.localIP().toString().c_str());
// Statyczna strona główna – minifikowany HTML z JS (EventSource)
static const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html><html><head><meta charset="utf-8"/>
<title>ESP8266 SSE</title><style>
body{font-family:Arial;text-align:center}#log{font-family:monospace;height:160px;
overflow-y:auto;border:1px solid #ccc;padding:6px}</style></head><body>
<h2>Server-Sent Events Demo</h2>
<p>Temp: <span id=t>--</span> °C | GPIO D1: <span id=g>--</span></p>
<div id=log></div>
<script>
let es=new EventSource("/events");
es.onopen =_=>add("SSE OPEN");
es.onerror =_=>add("SSE ERROR");
es.onmessage=e=>{ try{
let d=JSON.parse(e.data);
t.textContent=d.temp.toFixed(1);
g.textContent=d.gpio;
add("Upd "+e.data);
}catch(x){add("Bad JSON")}};
function add(msg){log.innerHTML+="["+new Date().toLocaleTimeString()+"] "+msg+"<br>";
log.scrollTop=log.scrollHeight;}
</script></body></html>)rawliteral";
// Routy ----------------------------------------------------------------
server.on("/", HTTP_GET, [](AsyncWebServerRequest *req){
req->send_P(200, "text/html", index_html);
});
server.addHandler(&events); // Rejestracja endpointu /events
// CORS, gdy podglądamy z innej domeny
events.setAllowedOrigins("*");
// Opcjonalnie info podczas połączenia klienta
events.onConnect([](AsyncEventSourceClient *client){
Serial.printf("Nowy klient SSE ID %u\n", client->client()->remotePort());
client->send("hi", NULL, millis()); // „hello” przy starcie
});
server.begin();
Serial.println("HTTP/SSE online");
}
void loop() {
unsigned long now = millis();
if (now - lastMux > interval) {
lastMux = now;
// --- aktualizacja zmiennych demo
temperature += (random(-3, 4))*0.1; // ±0,3°C
gpioState = digitalRead(D1);
// --- JSON (lekki, bez ArduinoJson)
String json = String("{\"temp\":") + String(temperature,1) +
",\"gpio\":" + gpioState + "}";
events.send(json.c_str(), "update", now); // id==millis()
// debug
Serial.println("SSE >> " + json);
}
}
Kluczowe elementy:
AsyncEventSource events("/events");
– deklaracja strumienia. setup()
dodajemy go do serwera: server.addHandler(&events);
. loop()
metodą events.send()
. Parametry: dane, typ zdarzenia, id. Widziany w sieci przykład:
server.on("/events", handleSSE);
void handleSSE(){
server.sendHeader("Content-Type","text/event-stream");
server.send(200);
while(true){ /* tu delay(1000) */ }
}
jest niezalecany – blokuje pętlę serwera, więc żaden inny request nie przejdzie. Jeśli koniecznie musisz użyć ESP8266WebServer
, w handleSSE()
tylko otwórz nagłówki, zapamiętaj WiFiClient c = server.client();
, a wysyłaj dane w loop()
(zob. sekcja „wersja synchroniczna” w rozdziale „Praktyczne wskazówki”).
events.send(NULL, NULL, millis());
), by routery NAT nie zamknęły portu. id:
: po reconnect klient przekaże Last-Event-ID
; serwer może zbuforować zdarzenia i wysłać brakujące. ESP8266WebServer
, bez pętli while! /events
– zobacz surowy strumień.curl http://<IP>/events -H "Accept:text/event-stream"
w terminalu. send_P
). retry:
(events.send("keepalive", "", millis());
).Server-Sent Events to lekki, natywny w HTTP sposób wysyłania danych w czasie rzeczywistym. W ESP8266 najwydajniej realizuje się go poprzez biblioteki asynchroniczne (ESPAsyncWebServer). Powyższy kod:
• utrzymuje wielu klientów,
• przesyła JSON co 2 s,
• pokazuje pełną stronę HTML,
• nie blokuje pętli loop()
.
Zwróć uwagę na poprawne nagłówki, podwójną pustą linię oraz obsługę TLS i autoryzacji w projektach produkcyjnych. Powodzenia w eksperymentach i dalszym rozwijaniu projektu!