{"id":99657,"date":"2020-10-21T13:42:33","date_gmt":"2020-10-21T13:42:33","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=99657"},"modified":"2025-03-17T11:48:09","modified_gmt":"2025-03-17T11:48:09","slug":"esp8266-nodemcu-web-server-sent-events-sse","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-web-server-sent-events-sse\/","title":{"rendered":"ESP8266 NodeMCU Web Server using Server-Sent Events (Update Sensor Readings Automatically)"},"content":{"rendered":"\n<p>This tutorial shows how to use Server-Sent Events (SSE) in an ESP8266 NodeMCU Web Server programmed with Arduino IDE. SSE allows the browser to receive automatic updates from a server via HTTP connection. This is useful to send updated sensor readings to the browser, for example. Whenever a new reading is available, the ESP8266 sends it to the client and the web page can be updated automatically without the need to make additional requests.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP8266-NodeMCU-Web-Server-Server-Sent-Events-SSE-Update-Sensor-Readings-Automatically-Arduino.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU Web Server using Server-Sent Events (SSE) Update Sensor Readings Automatically Arduino\" class=\"wp-image-99651\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP8266-NodeMCU-Web-Server-Server-Sent-Events-SSE-Update-Sensor-Readings-Automatically-Arduino.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP8266-NodeMCU-Web-Server-Server-Sent-Events-SSE-Update-Sensor-Readings-Automatically-Arduino.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP8266-NodeMCU-Web-Server-Server-Sent-Events-SSE-Update-Sensor-Readings-Automatically-Arduino.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP8266-NodeMCU-Web-Server-Server-Sent-Events-SSE-Update-Sensor-Readings-Automatically-Arduino.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p>As an example, we&#8217;ll build a web server that displays sensor readings from a BME280 temperature, humidity and pressure sensor. To learn more about the BME280, read our guide:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp8266-bme280-arduino-ide\/\">ESP8266 NodeMCU with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity)<\/a><\/li>\n<\/ul>\n\n\n\n<p>We also have a similar&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/esp32-web-server-sent-events-sse\/\">Server-Sent Events guide for the ESP32<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Introducing Server-Sent Events (SSE)<\/h2>\n\n\n\n<p>Server-Sent Events (SSE) allows the client to receive automatic updates from a server via HTTP connection.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"740\" height=\"772\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-ESP8266-Server-Sent-Events-How-it-Works.png?resize=740%2C772&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU Server-Sent Events Web Server How it Works\" class=\"wp-image-99476\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-ESP8266-Server-Sent-Events-How-it-Works.png?w=740&amp;quality=100&amp;strip=all&amp;ssl=1 740w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-ESP8266-Server-Sent-Events-How-it-Works.png?resize=288%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 288w\" sizes=\"(max-width: 740px) 100vw, 740px\" \/><\/figure><\/div>\n\n\n<p>The client initiates the SSE connection and the server uses the event source protocol to send updates to the client. The client will receive updates from the server, but it can\u2019t send any data to the server after the initial handshake.<\/p>\n\n\n\n<p>This is useful to send updated sensor readings to the browser. Whenever a new reading is available, the ESP8266 sends it to the client and the web page can be updated automatically without the need for further requests.&nbsp;Instead of sensor readings, you can send any data that might be useful for your project like GPIO states, notifications when motion is detected, etc.<\/p>\n\n\n\n<p class=\"rntbox rntcred\"><strong>Important: <\/strong> Server-Sent Events (SSE) are not supported on Internet Explorer.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Project Overview<\/h2>\n\n\n\n<p>Here&#8217;s the web page we&#8217;ll build for this project.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"790\" height=\"441\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/BME28-Web-Server-with-Server-Sent-Events-Overview.png?resize=790%2C441&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"BME280 Web Server using Server-Sent Events (SSE) ESP8266 NodeMCU Arduino\" class=\"wp-image-99477\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/BME28-Web-Server-with-Server-Sent-Events-Overview.png?w=790&amp;quality=100&amp;strip=all&amp;ssl=1 790w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/BME28-Web-Server-with-Server-Sent-Events-Overview.png?resize=300%2C167&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/BME28-Web-Server-with-Server-Sent-Events-Overview.png?resize=768%2C429&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 790px) 100vw, 790px\" \/><\/figure><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>The ESP8266 web server displays three cards with BME280 temperature, humidity and pressure readings;<\/li>\n\n\n\n<li>The ESP8266 gets new readings from the sensor every 30 seconds;<\/li>\n\n\n\n<li>Whenever a new reading is available, the board (server) sends it to the client using server-sent events;<\/li>\n\n\n\n<li>The client receives the data and updates the web page accordingly;<\/li>\n\n\n\n<li>This allows the web page to be updated automatically whenever new readings are available.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">How it Works?<\/h3>\n\n\n\n<p>The following diagram summarizes how Server-Sent Events work to update the web page.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"877\" height=\"825\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Web-Server-Server-Sent-Events-How-it-Works.png?resize=877%2C825&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU BME280 Web Server with Server Sent Events (SSE) How it Works\" class=\"wp-image-99494\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Web-Server-Server-Sent-Events-How-it-Works.png?w=877&amp;quality=100&amp;strip=all&amp;ssl=1 877w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Web-Server-Server-Sent-Events-How-it-Works.png?resize=300%2C282&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Web-Server-Server-Sent-Events-How-it-Works.png?resize=768%2C722&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 877px) 100vw, 877px\" \/><\/figure><\/div>\n\n\n<ol class=\"wp-block-list\">\n<li>The client initiates the SSE connection and the server uses the event source protocol on the \/events URL to send updates to the client;<\/li>\n\n\n\n<li>The ESP8266 gets new sensor readings;<\/li>\n\n\n\n<li>It sends the readings as events with the following names to the client: <span class=\"rnthl rntliteral\">&#8216;temperature&#8217;<\/span>, <span class=\"rnthl rntliteral\">&#8216;humidity&#8217;<\/span> and <span class=\"rnthl rntliteral\">&#8216;pressure&#8217;<\/span>;<\/li>\n\n\n\n<li>The client has event listeners for the events sent by the server and receives the updated sensor readings on those events;<\/li>\n\n\n\n<li>It updates the web page with the newest readings.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Preparing Arduino IDE<\/h2>\n\n\n\n<p>We\u2019ll program the&nbsp;ESP8266 board using Arduino IDE, so make sure you have it installed in your Arduino IDE.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-esp8266-nodemcu-arduino-ide-2-0\/\" title=\"\">Installing the ESP8266 NodeMCU Board in Arduino IDE (Windows, Mac OS X, Linux)<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Installing Libraries \u2013 Async Web Server<\/h3>\n\n\n\n<p>We&#8217;ll build the web server using the following libraries:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncWebServer\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncWebServer by ESP32Async<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncTCP\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncTCP&nbsp;by ESP32Async<\/a><\/li>\n<\/ul>\n\n\n\n<p>You can install these libraries using the Arduino Library Manager. Go to&nbsp;<strong>Sketch&nbsp;<\/strong>&gt;&nbsp;<strong>Include Library<\/strong>&nbsp;&gt;&nbsp;<strong>Manage Libraries<\/strong>&nbsp;and search for the libraries&#8217; names..<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Installing Libraries &#8211; BME280 Sensor<\/h3>\n\n\n\n<p>To get readings from the BME280 sensor module, we&#8217;ll use the\u00a0<a href=\"https:\/\/github.com\/adafruit\/Adafruit_BME280_Library\" target=\"_blank\" rel=\"noreferrer noopener\">Adafruit_BME280 library<\/a>. You also need to install the <a href=\"https:\/\/github.com\/adafruit\/Adafruit_Sensor\" target=\"_blank\" rel=\"noreferrer noopener\">Adafruit_Sensor library<\/a>. <\/p>\n\n\n\n<p>You can install these libraries using the Arduino Library Manager. Go to\u00a0<strong>Sketch\u00a0<\/strong>>\u00a0<strong>Include Library<\/strong>\u00a0>\u00a0<strong>Manage Libraries<\/strong>\u00a0and search for the libraries&#8217; names.<\/p>\n\n\n\n<p class=\"rntbox rntclblue\">To learn more about the BME280 sensor, read our guide: <a href=\"https:\/\/randomnerdtutorials.com\/esp8266-bme280-arduino-ide\/\">ESP8266 with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity)<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Building the Circuit<\/h2>\n\n\n\n<p>To exemplify how to use server-sent events with the ESP8266, we&#8217;ll send sensor readings from a BME280 sensor to the browser. So, you need to wire a BME280 sensor to your ESP8266.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Parts Required<\/h3>\n\n\n\n<p>To complete this tutorial you need the following parts:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a rel=\"noreferrer noopener\" href=\"https:\/\/makeradvisor.com\/tools\/bme280-sensor-module\/\" target=\"_blank\">BME280 sensor module<\/a><\/li>\n\n\n\n<li><a style=\"font-size: inherit; background-color: initial;\" rel=\"noreferrer noopener\" href=\"https:\/\/makeradvisor.com\/tools\/esp8266-esp-12e-nodemcu-wi-fi-development-board\/\" target=\"_blank\">ESP8266<\/a><span style=\"font-size: inherit; background-color: initial;\"> (read&nbsp;<\/span><a style=\"font-size: inherit; background-color: initial;\" href=\"https:\/\/makeradvisor.com\/best-esp8266-wi-fi-development-board\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP8266 development boards<\/a><span style=\"font-size: inherit; background-color: initial;\">)<\/span><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noreferrer noopener\">Breadboard<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noreferrer noopener\">Jumper wires<\/a><\/li>\n<\/ul>\n\n\n<p>You can use the preceding links or go directly to <a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\">MakerAdvisor.com\/tools<\/a> to find all the parts for your projects at the best price!<\/p><p style=\"text-align:center;\"><a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2017\/10\/header-200.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\"><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Schematic &#8211; ESP8266 with BME280 using I2C<\/h2>\n\n\n\n<p>We\u2019re going to use I2C communication with the BME280 sensor module. For that, wire the sensor to the ESP8266&nbsp;<span class=\"rnthl rntclgray\">SDA<\/span>&nbsp;and&nbsp;<span class=\"rnthl rntcyellow\">SCL<\/span>&nbsp;pins, as shown in the following schematic diagram. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"705\" height=\"532\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/06\/ESP8266-BME280-Arduino-IDE.png?resize=705%2C532&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Schematic Wiring diagram ESP8266 NodeMCU with BME280 using I2C\" class=\"wp-image-85980\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/06\/ESP8266-BME280-Arduino-IDE.png?w=705&amp;quality=100&amp;strip=all&amp;ssl=1 705w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/06\/ESP8266-BME280-Arduino-IDE.png?resize=300%2C226&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclblue\"><strong>Recommended reading:<\/strong> <a href=\"https:\/\/randomnerdtutorials.com\/esp8266-pinout-reference-gpios\/\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"ESP8266 Pinout Reference Guide (opens in a new tab)\">ESP8266 Pinout Reference Guide<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Code for ESP8266 Web Server using Server-Sent Events (SSE)<\/h2>\n\n\n\n<p>Copy the following code to your Arduino IDE.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*********\n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp8266-nodemcu-web-server-sent-events-sse\/\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*********\/\n\n#include &lt;ESP8266WiFi.h&gt;\n#include &lt;ESPAsyncTCP.h&gt;\n#include &lt;ESPAsyncWebServer.h&gt;\n#include &lt;Adafruit_BME280.h&gt;\n#include &lt;Adafruit_Sensor.h&gt;\n\n\/\/ Replace with your network credentials\nconst char* ssid = &quot;REPLACE_WITH_YOUR_SSID&quot;;\nconst char* password = &quot;REPLACE_WITH_YOUR_PASSWORD&quot;;\n\n\/\/ Create AsyncWebServer object on port 80\nAsyncWebServer server(80);\n\n\/\/ Create an Event Source on \/events\nAsyncEventSource events(&quot;\/events&quot;);\n\n\/\/ Timer variables\nunsigned long lastTime = 0;  \nunsigned long timerDelay = 30000;\n\n\/\/ Create a sensor object\nAdafruit_BME280 bme; \/\/ BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL)\n\nfloat temperature;\nfloat humidity;\nfloat pressure;\n\n\/\/ Init BME280\nvoid initBME(){\n    if (!bme.begin(0x76)) {\n    Serial.println(&quot;Could not find a valid BME280 sensor, check wiring!&quot;);\n    while (1);\n  }\n}\n\nvoid getSensorReadings(){\n  temperature = bme.readTemperature();\n  \/\/ Convert temperature to Fahrenheit\n  \/\/temperature = 1.8 * bme.readTemperature() + 32;\n  humidity = bme.readHumidity();\n  pressure = bme.readPressure()\/ 100.0F;\n}\n\n\/\/ Initialize WiFi\nvoid initWiFi() {\n    WiFi.mode(WIFI_STA);\n    WiFi.begin(ssid, password);\n    Serial.print(&quot;Connecting to WiFi ..&quot;);\n    while (WiFi.status() != WL_CONNECTED) {\n        Serial.print('.');\n        delay(1000);\n    }\n    Serial.println(WiFi.localIP());\n}\n\nString processor(const String&amp; var){\n  getSensorReadings();\n  \/\/Serial.println(var);\n  if(var == &quot;TEMPERATURE&quot;){\n    return String(temperature);\n  }\n  else if(var == &quot;HUMIDITY&quot;){\n    return String(humidity);\n  }\n  else if(var == &quot;PRESSURE&quot;){\n    return String(pressure);\n  }\n  return String();\n}\n\nconst char index_html[] PROGMEM = R&quot;rawliteral(\n&lt;!DOCTYPE HTML&gt;&lt;html&gt;\n&lt;head&gt;\n  &lt;title&gt;ESP Web Server&lt;\/title&gt;\n  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\n  &lt;link rel=&quot;stylesheet&quot; href=&quot;https:\/\/use.fontawesome.com\/releases\/v5.7.2\/css\/all.css&quot; integrity=&quot;sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr&quot; crossorigin=&quot;anonymous&quot;&gt;\n  &lt;link rel=&quot;icon&quot; href=&quot;data:,&quot;&gt;\n  &lt;style&gt;\n    html {font-family: Arial; display: inline-block; text-align: center;}\n    p { font-size: 1.2rem;}\n    body {  margin: 0;}\n    .topnav { overflow: hidden; background-color: #50B8B4; color: white; font-size: 1rem; }\n    .content { padding: 20px; }\n    .card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }\n    .cards { max-width: 800px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }\n    .reading { font-size: 1.4rem; }\n  &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;div class=&quot;topnav&quot;&gt;\n    &lt;h1&gt;BME280 WEB SERVER (SSE)&lt;\/h1&gt;\n  &lt;\/div&gt;\n  &lt;div class=&quot;content&quot;&gt;\n    &lt;div class=&quot;cards&quot;&gt;\n      &lt;div class=&quot;card&quot;&gt;\n        &lt;p&gt;&lt;i class=&quot;fas fa-thermometer-half&quot; style=&quot;color:#059e8a;&quot;&gt;&lt;\/i&gt; TEMPERATURE&lt;\/p&gt;&lt;p&gt;&lt;span class=&quot;reading&quot;&gt;&lt;span id=&quot;temp&quot;&gt;%TEMPERATURE%&lt;\/span&gt; &amp;deg;C&lt;\/span&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n      &lt;div class=&quot;card&quot;&gt;\n        &lt;p&gt;&lt;i class=&quot;fas fa-tint&quot; style=&quot;color:#00add6;&quot;&gt;&lt;\/i&gt; HUMIDITY&lt;\/p&gt;&lt;p&gt;&lt;span class=&quot;reading&quot;&gt;&lt;span id=&quot;hum&quot;&gt;%HUMIDITY%&lt;\/span&gt; &amp;percnt;&lt;\/span&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n      &lt;div class=&quot;card&quot;&gt;\n        &lt;p&gt;&lt;i class=&quot;fas fa-angle-double-down&quot; style=&quot;color:#e1e437;&quot;&gt;&lt;\/i&gt; PRESSURE&lt;\/p&gt;&lt;p&gt;&lt;span class=&quot;reading&quot;&gt;&lt;span id=&quot;pres&quot;&gt;%PRESSURE%&lt;\/span&gt; hPa&lt;\/span&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n    &lt;\/div&gt;\n  &lt;\/div&gt;\n&lt;script&gt;\nif (!!window.EventSource) {\n var source = new EventSource('\/events');\n \n source.addEventListener('open', function(e) {\n  console.log(&quot;Events Connected&quot;);\n }, false);\n source.addEventListener('error', function(e) {\n  if (e.target.readyState != EventSource.OPEN) {\n    console.log(&quot;Events Disconnected&quot;);\n  }\n }, false);\n \n source.addEventListener('message', function(e) {\n  console.log(&quot;message&quot;, e.data);\n }, false);\n \n source.addEventListener('temperature', function(e) {\n  console.log(&quot;temperature&quot;, e.data);\n  document.getElementById(&quot;temp&quot;).innerHTML = e.data;\n }, false);\n \n source.addEventListener('humidity', function(e) {\n  console.log(&quot;humidity&quot;, e.data);\n  document.getElementById(&quot;hum&quot;).innerHTML = e.data;\n }, false);\n \n source.addEventListener('pressure', function(e) {\n  console.log(&quot;pressure&quot;, e.data);\n  document.getElementById(&quot;pres&quot;).innerHTML = e.data;\n }, false);\n}\n&lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;)rawliteral&quot;;\n\nvoid setup() {\n  Serial.begin(115200);\n  initWiFi();\n  initBME();\n\n  \/\/ Handle Web Server\n  server.on(&quot;\/&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\n    request-&gt;send(200, &quot;text\/html&quot;, index_html, processor);\n  });\n\n  \/\/ Handle Web Server Events\n  events.onConnect([](AsyncEventSourceClient *client){\n    if(client-&gt;lastId()){\n      Serial.printf(&quot;Client reconnected! Last message ID that it got is: %u\\n&quot;, client-&gt;lastId());\n    }\n    \/\/ send event with message &quot;hello!&quot;, id current millis\n    \/\/ and set reconnect delay to 1 second\n    client-&gt;send(&quot;hello!&quot;, NULL, millis(), 10000);\n  });\n  server.addHandler(&amp;events);\n  server.begin();\n}\n\nvoid loop() {\n  if ((millis() - lastTime) &gt; timerDelay) {\n    getSensorReadings();\n    Serial.printf(&quot;Temperature = %.2f \u00baC \\n&quot;, temperature);\n    Serial.printf(&quot;Humidity = %.2f \\n&quot;, humidity);\n    Serial.printf(&quot;Pressure = %.2f hPa \\n&quot;, pressure);\n    Serial.println();\n\n    \/\/ Send Events to the Web Server with the Sensor Readings\n    events.send(&quot;ping&quot;,NULL,millis());\n    events.send(String(temperature).c_str(),&quot;temperature&quot;,millis());\n    events.send(String(humidity).c_str(),&quot;humidity&quot;,millis());\n    events.send(String(pressure).c_str(),&quot;pressure&quot;,millis());\n    \n    lastTime = millis();\n  }\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP8266\/ESP8266_Server_Sent_Events.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Insert your network credentials in the following variables and the code will work straight away.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const char* ssid = \"REPLACE_WITH_YOUR_SSID\";\nconst char* password = \"REPLACE_WITH_YOUR_PASSWORD\";<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">How the Code Works<\/h2>\n\n\n\n<p>Continue reading to learn how the code works or skip to the&nbsp;<a href=\"#demonstration\">Demonstration<\/a>&nbsp;section.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Including Libraries<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">Adafruit_Sensor<\/span> and <span class=\"rnthl rntliteral\">Adafruit_BME280<\/span> libraries are needed to interface with the BME280 sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;Adafruit_BME280.h&gt;\n#include &lt;Adafruit_Sensor.h&gt;<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">WiFi<\/span>, <span class=\"rnthl rntliteral\">ESPAsyncWebServer<\/span> and <span class=\"rnthl rntliteral\">AsyncTCP<\/span> libraries are used to create the web server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;WiFi.h&gt;\n#include \"ESPAsyncWebServer.h\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Network Credentials<\/h3>\n\n\n\n<p>Insert your network credentials in the following variables, so that the ESP8266 can connect to your local network using Wi-Fi.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const char* ssid = \"REPLACE_WITH_YOUR_SSID\";\nconst char* password = \"REPLACE_WITH_YOUR_PASSWORD\";<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">AsyncWebServer and AsyncEventSource<\/h3>\n\n\n\n<p>Create an <span class=\"rnthl rntliteral\">AsyncWebServer<\/span> object on port 80.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>AsyncWebServer server(80);<\/code><\/pre>\n\n\n\n<p>The following line creates a new event source on <span class=\"rnthl rntliteral\">\/events<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>AsyncEventSource events(\"\/events\");<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Declaring Variables<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">lastTime<\/span> and the <span class=\"rnthl rntliteral\">timerDelay<\/span> variables will be used to update sensor readings every X number of seconds. As an example, we&#8217;ll get new sensor readings every 30 seconds (30000 milliseconds). You can change that delay time in the <span class=\"rnthl rntliteral\">timerDelay<\/span> variable.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>unsigned long lastTime = 0;\nunsigned long timerDelay = 30000;<\/code><\/pre>\n\n\n\n<p>Create an <span class=\"rnthl rntliteral\">Adafruit_BME280<\/span> object called <span class=\"rnthl rntliteral\">bme<\/span> on the default ESP8266 I2C pins.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Adafruit_BME280 bme;<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">temperature<\/span>, <span class=\"rnthl rntliteral\">humidity<\/span> and <span class=\"rnthl rntliteral\">pressure<\/span> float variables will be used to hold BME280 sensor readings.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>float temperature;\nfloat humidity;\nfloat pressure;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Initialize BME280<\/h3>\n\n\n\n<p>The following function can be called to initialize the BME280 sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void initBME(){\n  if (!bme.begin(0x76)) {\n    Serial.println(\"Could not find a valid BME280 sensor, check wiring!\");\n    while (1);\n  }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Get BME280 Readings<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">getSensorReading()<\/span> function gets temperature, humidity and pressure readings from the BME280 sensor and saves them on the <span class=\"rnthl rntliteral\">temperature<\/span>, <span class=\"rnthl rntliteral\">humidity<\/span> and <span class=\"rnthl rntliteral\">pressure<\/span> variables.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void getSensorReadings(){\n  temperature = bme.readTemperature();\n  \/\/ Convert temperature to Fahrenheit\n  \/\/temperature = 1.8 * bme.readTemperature() + 32;\n  humidity = bme.readHumidity();\n  pressure = bme.readPressure()\/ 100.0F;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Initialize Wi-Fi<\/h3>\n\n\n\n<p>The following function sets the ESP8266 as a Wi-Fi station and connects to your router using the ssid and password defined earlier.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void initWiFi() {\n  WiFi.mode(WIFI_STA);\n  WiFi.begin(ssid, password);\n  Serial.print(\"Connecting to WiFi ..\");\n  while (WiFi.status() != WL_CONNECTED) {\n    Serial.print('.');\n    delay(1000);\n  }\n  Serial.println(WiFi.localIP());\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Processor<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">processor()<\/span> function replaces any placeholders on the HTML text used to build the web page with the current sensor readings before sending it to the browser.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>String processor(const String&amp; var){\n  getSensorReadings();\n  \/\/Serial.println(var);\n  if(var == \"TEMPERATURE\"){\n    return String(temperature);\n  }\n  else if(var == \"HUMIDITY\"){\n    return String(humidity);\n  }\n  else if(var == \"PRESSURE\"){\n    return String(pressure);\n  }\n}<\/code><\/pre>\n\n\n\n<p>This allows us to display the current sensor readings on the web page when you access it for the first time. Otherwise, you would see a blank space until new readings were available (which can take some time depending on the delay time you&#8217;ve defined on the code).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Building the Web Page<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">index_html<\/span> variable contains all the HTML, CSS and JavaScript to build the web page. <\/p>\n\n\n\n<p class=\"rntbox rntclgray\"><strong>Note:&nbsp;<\/strong>for the simplicity of this tutorial, we\u2019re placing everything needed to build the web page on the&nbsp;index_html&nbsp;variable that we use on the Arduino sketch. Note that it may be more practical to have separated HTML, CSS and JavaScript files that then you upload to the ESP8266 filesystem and reference them on the code.<\/p>\n\n\n\n<p>Here\u2019s the content&nbsp;<span class=\"rnthl rntliteral\">index_html<\/span>&nbsp;variable:<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;!DOCTYPE HTML&gt;\n&lt;html&gt;\n&lt;head&gt;\n  &lt;title&gt;ESP Web Server&lt;\/title&gt;\n  &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;\n  &lt;link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.5.1\/css\/all.min.css\"&gt;\n  &lt;link rel=\"icon\" href=\"data:,\"&gt;\n  &lt;style&gt;\n    html {\n      font-family: Arial; \n      display: inline-block; \n      text-align: center;\n    }\n    p { \n      font-size: 1.2rem;\n    }\n    body {  \n      margin: 0;\n    }\n    .topnav { \n      overflow: hidden; \n      background-color: #50B8B4; \n      color: white; \n      font-size: 1rem; \n    }\n    .content { \n      padding: 20px; \n    }\n    .card { \n      background-color: white; \n      box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); \n    }\n    .cards { \n      max-width: 800px; \n      margin: 0 auto; \n      display: grid; \n      grid-gap: 2rem; \n      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }\n    .reading { \n      font-size: 1.4rem;  \n    }\n  &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;div class=\"topnav\"&gt;\n    &lt;h1&gt;BME280 WEB SERVER (SSE)&lt;\/h1&gt;\n  &lt;\/div&gt;\n  &lt;div class=\"content\"&gt;\n    &lt;div class=\"cards\"&gt;\n      &lt;div class=\"card\"&gt;\n        &lt;p&gt;&lt;i class=\"fas fa-thermometer-half\" style=\"color:#059e8a;\"&gt;&lt;\/i&gt; TEMPERATURE&lt;\/p&gt;\n        &lt;p&gt;&lt;span class=\"reading\"&gt;&lt;span id=\"temp\"&gt;%TEMPERATURE%&lt;\/span&gt; &amp;deg;C&lt;\/span&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n      &lt;div class=\"card\"&gt;\n        &lt;p&gt;&lt;i class=\"fas fa-tint\" style=\"color:#00add6;\"&gt;&lt;\/i&gt; HUMIDITY&lt;\/p&gt;\n        &lt;p&gt;&lt;span class=\"reading\"&gt;&lt;span id=\"hum\"&gt;%HUMIDITY%&lt;\/span&gt; &amp;percnt;&lt;\/span&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n      &lt;div class=\"card\"&gt;\n        &lt;p&gt;&lt;i class=\"fas fa-angle-double-down\" style=\"color:#e1e437;\"&gt;&lt;\/i&gt; PRESSURE&lt;\/p&gt;&lt;p&gt;&lt;span class=\"reading\"&gt;&lt;span id=\"pres\"&gt;%PRESSURE%&lt;\/span&gt; hPa&lt;\/span&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n    &lt;\/div&gt;\n  &lt;\/div&gt;\n&lt;script&gt;\nif (!!window.EventSource) {\n var source = new EventSource('\/events');\n\n source.addEventListener('open', function(e) {\n  console.log(\"Events Connected\");\n }, false);\n source.addEventListener('error', function(e) {\n  if (e.target.readyState != EventSource.OPEN) {\n    console.log(\"Events Disconnected\");\n  }\n }, false);\n\n source.addEventListener('message', function(e) {\n  console.log(\"message\", e.data);\n }, false);\n\n source.addEventListener('temperature', function(e) {\n  console.log(\"temperature\", e.data);\n  document.getElementById(\"temp\").innerHTML = e.data;\n }, false);\n\n source.addEventListener('humidity', function(e) {\n  console.log(\"humidity\", e.data);\n  document.getElementById(\"hum\").innerHTML = e.data;\n }, false);\n\n source.addEventListener('pressure', function(e) {\n  console.log(\"pressure\", e.data);\n  document.getElementById(\"pres\").innerHTML = e.data;\n }, false);\n}\n&lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n\n\n\n<p>We won\u2019t go into detail on how the HTML and CSS works. We\u2019ll just take a look at how to handle the events sent by the server.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">CSS<\/h3>\n\n\n\n<p>Between the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;style&gt;<\/span><\/span> <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;\/style&gt;<\/span><\/span> tags we include the styles to style the web page using CSS. Feel free to change it to make the web page look as you wish. We won&#8217;t explain how the CSS for this web page works because it is not relevant for this tutorial.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;style&gt;\n  html {\n    font-family: Arial; \n    display: inline-block; \n    text-align: center;\n  }\n  p { \n    font-size: 1.2rem;\n  }\n  body {  \n    margin: 0;\n  }\n  .topnav { \n    overflow: hidden; \n    background-color: #50B8B4; \n    color: white; \n    font-size: 1rem; \n  }\n  .content { \n    padding: 20px; \n  }\n  .card { \n    background-color: white; \n    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); \n  }\n  .cards { \n    max-width: 800px; \n    margin: 0 auto; \n    display: grid; \n    grid-gap: 2rem; \n    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }\n  .reading { \n    font-size: 1.4rem;  \n  }\n&lt;\/style&gt;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">HTML<\/h3>\n\n\n\n<p>Between the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;body&gt;<\/span><\/span> <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;\/body&gt;<\/span><\/span> tags we add the web page content that is visible to the user.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;body&gt;\n  &lt;div class=\"topnav\"&gt;\n    &lt;h1&gt;BME280 WEB SERVER (SSE)&lt;\/h1&gt;\n  &lt;\/div&gt;\n  &lt;div class=\"content\"&gt;\n    &lt;div class=\"cards\"&gt;\n      &lt;div class=\"card\"&gt;\n        &lt;p&gt;&lt;i class=\"fas fa-thermometer-half\" style=\"color:#059e8a;\"&gt;&lt;\/i&gt; TEMPERATURE&lt;\/p&gt;\n        &lt;p&gt;&lt;span class=\"reading\"&gt;&lt;span id=\"temp\"&gt;%TEMPERATURE%&lt;\/span&gt; &amp;deg;C&lt;\/span&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n      &lt;div class=\"card\"&gt;\n        &lt;p&gt;&lt;i class=\"fas fa-tint\" style=\"color:#00add6;\"&gt;&lt;\/i&gt; HUMIDITY&lt;\/p&gt;\n        &lt;p&gt;&lt;span class=\"reading\"&gt;&lt;span id=\"hum\"&gt;%HUMIDITY%&lt;\/span&gt; &amp;percnt;&lt;\/span&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n      &lt;div class=\"card\"&gt;\n        &lt;p&gt;&lt;i class=\"fas fa-angle-double-down\" style=\"color:#e1e437;\"&gt;&lt;\/i&gt; PRESSURE&lt;\/p&gt;&lt;p&gt;&lt;span class=\"reading\"&gt;&lt;span id=\"pres\"&gt;%PRESSURE%&lt;\/span&gt; hPa&lt;\/span&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n    &lt;\/div&gt;\n  &lt;\/div&gt;<\/code><\/pre>\n\n\n\n<p>There&#8217;s a heading 1 with the content &#8220;BME280 WEB SERVER (SSE)&#8221;. That&#8217;s the text that shows up on the top bar. Feel free to modify that text.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;h1&gt;BME280 WEB SERVER (SSE)&lt;\/h1&gt;<\/code><\/pre>\n\n\n\n<p>Then, we display the sensor readings in separated div tags. Let&#8217;s take a quick look at the paragraphs that displays the temperature:<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;p&gt;&lt;i class=\"fas fa-thermometer-half\" style=\"color:#059e8a;\"&gt;&lt;\/i&gt; TEMPERATURE&lt;\/p&gt;\n&lt;p&gt;&lt;span class=\"reading\"&gt;&lt;span id=\"temp\"&gt;%TEMPERATURE%&lt;\/span&gt; &amp;deg;C&lt;\/span&gt;&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>The first paragraph simply displays the &#8220;TEMPERATURE&#8221; text. We define the color and also an icon.<\/p>\n\n\n\n<p>On the second paragraph, you can see that the <span class=\"rnthl rntliteral\">%TEMPERATURE%<\/span> placeholder is surrounded by <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;span id=&#8221;temp&#8221;&gt;<\/span><\/span> <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;\/span&gt;<\/span><\/span> tags. The HTML <span class=\"rnthl rntliteral\">id<\/span> attribute is used to specify a unique id for an HTML element.<\/p>\n\n\n\n<p>It is used to point to a specific style or it can be used by JavaScript to access and manipulate the element with that specific id. That&#8217;s what we&#8217;re going to do. For instance, when the client receives a new event with the latest temperature reading, it updates the HTML element with the id &#8220;<span class=\"rnthl rntliteral\">temp<\/span>&#8221; with the new reading.<\/p>\n\n\n\n<p>A similar process is done to update the other readings.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">JavaScript &#8211; EventSource<\/h3>\n\n\n\n<p>The JavaScript goes between the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;script&gt;<\/span><\/span> <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;\/script&gt;<\/span><\/span> tags. It is responsible for initializing an EventSource connection with the server and handle the events received from the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;script&gt;\nif (!!window.EventSource) {\n  var source = new EventSource('\/events');\n  source.addEventListener('open', function(e) {\n    console.log(\"Events Connected\");\n  }, false);\n  source.addEventListener('error', function(e) {\n    if (e.target.readyState != EventSource.OPEN) {\n      console.log(\"Events Disconnected\");\n    }\n  }, false);\n\n  source.addEventListener('message', function(e) {\n    console.log(\"message\", e.data);\n  }, false);\n\n  source.addEventListener('temperature', function(e) {\n    console.log(\"temperature\", e.data);\n    document.getElementById(\"temp\").innerHTML = e.data;\n  }, false);\n\n  source.addEventListener('humidity', function(e) {\n    console.log(\"humidity\", e.data);\n    document.getElementById(\"hum\").innerHTML = e.data;\n  }, false);\n\n  source.addEventListener('pressure', function(e) {\n    console.log(\"pressure\", e.data);\n    document.getElementById(\"pres\").innerHTML = e.data;\n  }, false);\n}\n&lt;\/script&gt;<\/code><\/pre>\n\n\n\n<p>Let&#8217;s take a look at how this works.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Handle Events<\/h4>\n\n\n\n<p>Create a new <span class=\"rnthl rntliteral\">EventSource<\/span> object and specify the URL of the page sending the updates. In our case, it\u2019s <span class=\"rnthl rntliteral\">\/events<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (!!window.EventSource) {\n  var source = new EventSource('\/events');<\/code><\/pre>\n\n\n\n<p>Once you\u2019ve instantiated an event source, you can start listening for messages from the server with <span class=\"rnthl rntliteral\">addEventListener()<\/span>.<\/p>\n\n\n\n<p>These are the default event listeners, as shown here in the AsyncWebServer&nbsp;<a href=\"https:\/\/github.com\/me-no-dev\/ESPAsyncWebServer#setup-event-source-in-the-browser\" target=\"_blank\" rel=\"noreferrer noopener\">documentation<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>source.addEventListener('open', function(e) {\n  console.log(\"Events Connected\");\n}, false);\n\nsource.addEventListener('error', function(e) {\n  if (e.target.readyState != EventSource.OPEN) {\n    console.log(\"Events Disconnected\");\n  }\n}, false);\n\nsource.addEventListener('message', function(e) {\n  console.log(\"message\", e.data);\n}, false);<\/code><\/pre>\n\n\n\n<p>Then, add the event listener for \u201c<span class=\"rnthl rntliteral\">temperature<\/span>\u201d.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>source.addEventListener('temperature', function(e) {<\/code><\/pre>\n\n\n\n<p>When a new temperature reading is available, the ESP8266 sends an event (\u201c<span class=\"rnthl rntliteral\">temperature<\/span>\u201d) to the client. The following lines handle what happens when the browser receives that event.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>console.log(\"temperature\", e.data);\ndocument.getElementById(\"temp\").innerHTML = e.data;<\/code><\/pre>\n\n\n\n<p>Basically, print the new readings on the browser console, and put the received data into the element with the corresponding id (&#8220;<span class=\"rnthl rntliteral\">temp<\/span>&#8220;) on the web page.<\/p>\n\n\n\n<p>A similar processor is done for humidity and pressure.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>source.addEventListener('humidity', function(e) {\n  console.log(\"humidity\", e.data);\n  document.getElementById(\"hum\").innerHTML = e.data;\n}, false);\n \nsource.addEventListener('pressure', function(e) {\n  console.log(\"pressure\", e.data);\n  document.getElementById(\"pres\").innerHTML = e.data;\n}, false);\n \nsource.addEventListener('gas', function(e) {\n  console.log(\"gas\", e.data);\n  document.getElementById(\"gas\").innerHTML = e.data;\n}, false);<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">setup()<\/h3>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, initialize the Serial Monitor, initialize Wi-Fi and the BME280 sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.begin(115200);\ninitWiFi();\ninitBME();<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Handle Requests<\/h4>\n\n\n\n<p>When you access the ESP8266 IP address on the root&nbsp;<span class=\"rnthl rntliteral\">\/<\/span> URL, send the text that is stored on the <span class=\"rnthl rntliteral\">index_html<\/span> variable to build the web page and pass the <span class=\"rnthl rntliteral\">processor<\/span> as argument, so that all placeholders are replaced with the latest sensor readings.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/\", HTTP_GET, &#091;](AsyncWebServerRequest *request){\n  request-&gt;send_P(200, \"text\/html\", index_html, processor);\n});<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Server Event Source<\/h4>\n\n\n\n<p>Set up the event source on the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Handle Web Server Events\nevents.onConnect(&#091;](AsyncEventSourceClient *client){\n  if(client-&gt;lastId()){\n    Serial.printf(\"Client reconnected! Last message ID that it got is: %u\\n\", client-&gt;lastId());\n  }\n  \/\/ send event with message \"hello!\", id current millis\n  \/\/ and set reconnect delay to 1 second\n  client-&gt;send(\"hello!\", NULL, millis(), 10000);\n});\nserver.addHandler(&amp;events);<\/code><\/pre>\n\n\n\n<p>Finally, start the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.begin();<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">loop()<\/h3>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">loop()<\/span>, get new sensor readings:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>getSensorReadings();<\/code><\/pre>\n\n\n\n<p>Print the new readings in the Serial Monitor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.printf(\"Temperature = %.2f \u00baC \\n\", temperature);\nSerial.printf(\"Humidity = %.2f % \\n\", humidity);\nSerial.printf(\"Pressure = %.2f hPa \\n\", pressure);\nSerial.println();<\/code><\/pre>\n\n\n\n<p>Finally, send events to the browser with the newest sensor readings to update the web page.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Send Events to the Web Server with the Sensor Readings\nevents.send(\"ping\",NULL,millis());\nevents.send(String(temperature).c_str(),\"temperature\",millis());\nevents.send(String(humidity).c_str(),\"humidity\",millis());\nevents.send(String(pressure).c_str(),\"pressure\",millis());<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"demonstration\">Demonstration<\/h2>\n\n\n\n<p>After inserting your network credentials on the <span class=\"rnthl rntliteral\">ssid<\/span> and <span class=\"rnthl rntliteral\">password<\/span> variables, you can upload the code to your board. Don&#8217;t forget to check if you have the right board and COM port selected.<\/p>\n\n\n\n<p>After uploading the code, open the Serial Monitor at a baud rate of 115200 and press the on-board EN\/RST button. The ESP IP address should be printed.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"669\" height=\"494\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/Server-Sent-Events-ESP32-Web-Server-Serial-Monitor-Sensor-Readings.png?resize=669%2C494&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU Web Server using Server Sent Events Serial Monitor Demonstration\" class=\"wp-image-99483\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/Server-Sent-Events-ESP32-Web-Server-Serial-Monitor-Sensor-Readings.png?w=669&amp;quality=100&amp;strip=all&amp;ssl=1 669w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/Server-Sent-Events-ESP32-Web-Server-Serial-Monitor-Sensor-Readings.png?resize=300%2C222&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 669px) 100vw, 669px\" \/><\/figure><\/div>\n\n\n<p>Open a browser on your local network and insert the ESP8266 IP address. You should get access to the web page to monitor the sensor readings.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"790\" height=\"441\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/BME28-Web-Server-with-Server-Sent-Events-Overview.png?resize=790%2C441&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"BME280 Web Server using Server-Sent Events SSE ESP8266 NodeMCU\" class=\"wp-image-99477\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/BME28-Web-Server-with-Server-Sent-Events-Overview.png?w=790&amp;quality=100&amp;strip=all&amp;ssl=1 790w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/BME28-Web-Server-with-Server-Sent-Events-Overview.png?resize=300%2C167&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/BME28-Web-Server-with-Server-Sent-Events-Overview.png?resize=768%2C429&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 790px) 100vw, 790px\" \/><\/figure><\/div>\n\n\n<p>The readings are updated automatically every 30 seconds.<\/p>\n\n\n\n<p>At the same time, you should get new sensor readings on the Serial Monitor as shown in the previous print screen. Additionally, you can check if the client is receiving the events. On your browser, open the console by pressing <strong>Ctrl<\/strong>+<strong>Shift<\/strong>+<strong>J<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"809\" height=\"559\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/Server-Sent-Events-Browser-Console-ESP2-Web-Server.png?resize=809%2C559&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Server-Sent Events Browser Console ESP8266 NodeMCU Web Server Demonstration\" class=\"wp-image-99484\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/Server-Sent-Events-Browser-Console-ESP2-Web-Server.png?w=809&amp;quality=100&amp;strip=all&amp;ssl=1 809w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/Server-Sent-Events-Browser-Console-ESP2-Web-Server.png?resize=300%2C207&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/Server-Sent-Events-Browser-Console-ESP2-Web-Server.png?resize=768%2C531&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 809px) 100vw, 809px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial you&#8217;ve learned how to use Server-Sent Events with the ESP8266. Server-Sent Events allow a web page (client) to get updates from a server. This can be used to automatically display new sensor readings on the web server page when they are available.<\/p>\n\n\n\n<p>We have a similar tutorial but using the BME680 environmental sensor. You can check the tutorial on the following link:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-bme680-web-server-arduino\/\">ESP8266 NodeMCU Web Server with BME680 &#8211; Weather Station (Arduino IDE)<\/a><\/li>\n<\/ul>\n\n\n\n<p>Instead of Server-Sent Events, you can also use the <a href=\"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-websocket-server-arduino\/\">WebSocket protocol<\/a> to keep the web page updated. Take a look at the following tutorial to learn how to set up a WebSocket server with the ESP8266:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span style=\"font-size: inherit; background-color: initial;\"><a href=\"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-websocket-server-arduino\/\">ESP8266 NodeMCU WebSocket Server: Control Outputs (Arduino IDE)<\/a><\/span><\/li>\n<\/ul>\n\n\n\n<p>Learn more about the ESP8266 with our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/home-automation-using-esp8266\/\"><span style=\"font-size: inherit; background-color: initial;\">Home Automation Using ESP8266<\/span><\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/micropython-programming-with-esp32-and-esp8266\/\">MicroPython Programming with ESP32 and ESP8266<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp8266\/\">More ESP8266 NodeMCU Projects and Guides\u2026<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to use Server-Sent Events (SSE) in an ESP8266 NodeMCU Web Server programmed with Arduino IDE. SSE allows the browser to receive automatic updates from a server &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP8266 NodeMCU Web Server using Server-Sent Events (Update Sensor Readings Automatically)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-web-server-sent-events-sse\/#more-99657\" aria-label=\"Read more about ESP8266 NodeMCU Web Server using Server-Sent Events (Update Sensor Readings Automatically)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":1,"featured_media":99651,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[265,214,246,300,240,264],"tags":[],"class_list":["post-99657","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp8266-project","category-esp8266","category-esp8266-arduino-ide","category-0-esp8266","category-esp8266-projects","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP8266-NodeMCU-Web-Server-Server-Sent-Events-SSE-Update-Sensor-Readings-Automatically-Arduino.jpg?fit=1280%2C720&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/99657","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=99657"}],"version-history":[{"count":2,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/99657\/revisions"}],"predecessor-version":[{"id":168068,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/99657\/revisions\/168068"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/99651"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=99657"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=99657"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=99657"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}