ESP32 Web Server using Server-Sent Events (Update Sensor Readings Automatically)

This tutorial shows how to use Server-Sent Events (SSE) in an ESP32 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 ESP32 sends it to the client and the web page can be updated automatically without the need to make additional requests.

ESP32 Web Server using Server-Sent Events (SSE) Update Sensor Readings Automatically Arduino

As an example, we’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:

We also have a similar Server-Sent Events guide for the ESP8266.

Introducing Server-Sent Events (SSE)

Server-Sent Events (SSE) allows the client to receive automatic updates from a server via HTTP connection.

ESP32 ESP8266 Server-Sent Events Web Server How it Works

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’t send any data to the server after the initial handshake.

This is useful to send updated sensor readings to the browser. Whenever a new reading is available, the ESP32 sends it to the client and the web page can be updated automatically without the need for further requests. 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.

Important: Server-Sent Events (SSE) are not supported on Internet Explorer.

Project Overview

Here’s the web page we’ll build for this project.

BME280 Web Server using Server-Sent Events (SSE) ESP32 Arduino
  • The ESP32 web server displays three cards with BME280 temperature, humidity and pressure readings;
  • The ESP32 gets new readings from the sensor every 30 seconds;
  • Whenever a new reading is available, the board (server) sends it to the client using server-sent events;
  • The client receives the data and updates the web page accordingly;
  • This allows the web page to be updated automatically whenever new readings are available.

How it Works?

The following diagram summarizes how Server-Sent Events work to update the web page.

ESP32 BME280 Web Server with Server Sent Events (SSE) How it Works
  1. The client initiates the SSE connection and the server uses the event source protocol on the /events URL to send updates to the client;
  2. The ESP32 gets new sensor readings;
  3. It sends the readings as events with the following names to the client: ‘temperature’, ‘humidity’ and ‘pressure’;
  4. The client has event listeners for the events sent by the server and receives the updated sensor readings on those events;
  5. It updates the web page with the newest readings.

Preparing Arduino IDE

We’ll program the ESP32 board using Arduino IDE, so make sure you have it installed in your Arduino IDE.

Installing Libraries – Async Web Server

To build the web server we’ll use the ESPAsyncWebServer library. This library needs the AsyncTCP library to work properly. Click the links below to download the libraries.

These libraries aren’t available to install through the Arduino Library Manager, so you need to copy the library files to the Arduino Installation Libraries folder. Alternatively, in your Arduino IDE, you can go to Sketch Include Library > Add .zip Library and select the libraries you’ve just downloaded.

Installing Libraries – BME280 Sensor

To get readings from the BME280 sensor module, we’ll use the Adafruit_BME280 library. You also need to install the Adafruit_Sensor library. Follow the next steps to install the libraries in your Arduino IDE:

1. Open your Arduino IDE and go to Sketch Include Library > Manage Libraries. The Library Manager should open.

2. Search for “adafruit bme280 ” on the Search box and install the library.

Installing BME280 library in Arduino IDE

To use the BME280 library, you also need to install the Adafruit Unified Sensor. Follow the next steps to install the library in your Arduino IDE:

3. Search for “Adafruit Unified Sensor“in the search box. Scroll all the way down to find the library and install it.

Installing Adafruit Unified Sensor Driver library

After installing the libraries, restart your Arduino IDE.

To learn more about the BME280 sensor, read our guide: ESP32 with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity).

Building the Circuit

To exemplify how to use server-sent events with the ESP32, we’ll send sensor readings from a BME280 sensor to the browser. So, you need to wire a BME280 sensor to your ESP32.

Parts Required

To complete this tutorial you need the following parts:

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

Schematic Diagram

We’re going to use I2C communication with the BME280 sensor module. For that, wire the sensor to the default ESP32 SCL (GPIO 22) and SDA (GPIO 21) pins, as shown in the following schematic diagram.

ESP32 Wiring to BME280 Schematic Diagram

Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?

Code for ESP32 Web Server using Server-Sent Events (SSE)

Copy the following code to your Arduino IDE.

/*********
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-web-server-sent-events-sse/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*********/

#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

// Create an Event Source on /events
AsyncEventSource events("/events");

// Timer variables
unsigned long lastTime = 0;  
unsigned long timerDelay = 30000;

// Create a sensor object
Adafruit_BME280 bme;         // BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL)

float temperature;
float humidity;
float pressure;

// Init BME280
void initBME(){
    if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
}

void getSensorReadings(){
  temperature = bme.readTemperature();
  // Convert temperature to Fahrenheit
  //temperature = 1.8 * bme.readTemperature() + 32;
  humidity = bme.readHumidity();
  pressure = bme.readPressure()/ 100.0F;
}

// Initialize WiFi
void initWiFi() {
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);
    Serial.print("Connecting to WiFi ..");
    while (WiFi.status() != WL_CONNECTED) {
        Serial.print('.');
        delay(1000);
    }
    Serial.println(WiFi.localIP());
}

String processor(const String& var){
  getSensorReadings();
  //Serial.println(var);
  if(var == "TEMPERATURE"){
    return String(temperature);
  }
  else if(var == "HUMIDITY"){
    return String(humidity);
  }
  else if(var == "PRESSURE"){
    return String(pressure);
  }
  return String();
}

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>ESP Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
  <link rel="icon" href="data:,">
  <style>
    html {font-family: Arial; display: inline-block; text-align: center;}
    p { font-size: 1.2rem;}
    body {  margin: 0;}
    .topnav { overflow: hidden; background-color: #50B8B4; color: white; font-size: 1rem; }
    .content { padding: 20px; }
    .card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }
    .cards { max-width: 800px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
    .reading { font-size: 1.4rem; }
  </style>
</head>
<body>
  <div class="topnav">
    <h1>BME280 WEB SERVER (SSE)</h1>
  </div>
  <div class="content">
    <div class="cards">
      <div class="card">
        <p><i class="fas fa-thermometer-half" style="color:#059e8a;"></i> TEMPERATURE</p><p><span class="reading"><span id="temp">%TEMPERATURE%</span> &deg;C</span></p>
      </div>
      <div class="card">
        <p><i class="fas fa-tint" style="color:#00add6;"></i> HUMIDITY</p><p><span class="reading"><span id="hum">%HUMIDITY%</span> &percnt;</span></p>
      </div>
      <div class="card">
        <p><i class="fas fa-angle-double-down" style="color:#e1e437;"></i> PRESSURE</p><p><span class="reading"><span id="pres">%PRESSURE%</span> hPa</span></p>
      </div>
    </div>
  </div>
<script>
if (!!window.EventSource) {
 var source = new EventSource('/events');
 
 source.addEventListener('open', function(e) {
  console.log("Events Connected");
 }, false);
 source.addEventListener('error', function(e) {
  if (e.target.readyState != EventSource.OPEN) {
    console.log("Events Disconnected");
  }
 }, false);
 
 source.addEventListener('message', function(e) {
  console.log("message", e.data);
 }, false);
 
 source.addEventListener('temperature', function(e) {
  console.log("temperature", e.data);
  document.getElementById("temp").innerHTML = e.data;
 }, false);
 
 source.addEventListener('humidity', function(e) {
  console.log("humidity", e.data);
  document.getElementById("hum").innerHTML = e.data;
 }, false);
 
 source.addEventListener('pressure', function(e) {
  console.log("pressure", e.data);
  document.getElementById("pres").innerHTML = e.data;
 }, false);
}
</script>
</body>
</html>)rawliteral";

void setup() {
  Serial.begin(115200);
  initWiFi();
  initBME();


  // Handle Web Server
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Handle Web Server Events
  events.onConnect([](AsyncEventSourceClient *client){
    if(client->lastId()){
      Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
    }
    // send event with message "hello!", id current millis
    // and set reconnect delay to 1 second
    client->send("hello!", NULL, millis(), 10000);
  });
  server.addHandler(&events);
  server.begin();
}

void loop() {
  if ((millis() - lastTime) > timerDelay) {
    getSensorReadings();
    Serial.printf("Temperature = %.2f ºC \n", temperature);
    Serial.printf("Humidity = %.2f \n", humidity);
    Serial.printf("Pressure = %.2f hPa \n", pressure);
    Serial.println();

    // Send Events to the Web Client with the Sensor Readings
    events.send("ping",NULL,millis());
    events.send(String(temperature).c_str(),"temperature",millis());
    events.send(String(humidity).c_str(),"humidity",millis());
    events.send(String(pressure).c_str(),"pressure",millis());
    
    lastTime = millis();
  }
}

View raw code

Insert your network credentials in the following variables and the code will work straight away.

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

How the Code Works

Continue reading to learn how the code works or skip to the Demonstration section.

Including Libraries

The Adafruit_Sensor and Adafruit_BME280 libraries are needed to interface with the BME280 sensor.

#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>

The WiFi, ESPAsyncWebServer and AsyncTCP libraries are used to create the web server.

#include <WiFi.h>
#include "ESPAsyncWebServer.h"

Network Credentials

Insert your network credentials in the following variables, so that the ESP32 can connect to your local network using Wi-Fi.

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

AsyncWebServer and AsyncEventSource

Create an AsyncWebServer object on port 80.

AsyncWebServer server(80);

The following line creates a new event source on /events.

AsyncEventSource events("/events");

Declaring Variables

The lastTime and the timerDelay variables will be used to update sensor readings every X number of seconds. As an example, we’ll get new sensor readings every 30 seconds (30000 milliseconds). You can change that delay time in the timerDelay variable.

unsigned long lastTime = 0;
unsigned long timerDelay = 30000;

Create an Adafruit_BME280 object called bme on the default ESP32 I2C pins.

Adafruit_BME280 bme;

The temperature, humidity and pressure float variables will be used to hold BME280 sensor readings.

float temperature;
float humidity;
float pressure;

Initialize BME280

The following function can be called to initialize the BME280 sensor.

void initBME(){
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
}

Get BME280 Readings

The getSensorReading() function gets temperature, humidity and pressure readings from the BME280 sensor and saves them on the temperature, humidity and pressure variables.

void getSensorReadings(){
  temperature = bme.readTemperature();
  // Convert temperature to Fahrenheit
  //temperature = 1.8 * bme.readTemperature() + 32;
  humidity = bme.readHumidity();
  pressure = bme.readPressure()/ 100.0F;
}

Initialize Wi-Fi

The following function sets the ESP32 as a Wi-Fi station and connects to your router using the ssid and password defined earlier.

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

Processor

The processor() 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.

String processor(const String& var){
  getSensorReadings();
  //Serial.println(var);
  if(var == "TEMPERATURE"){
    return String(temperature);
  }
  else if(var == "HUMIDITY"){
    return String(humidity);
  }
  else if(var == "PRESSURE"){
    return String(pressure);
  }
}

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’ve defined on the code).

Building the Web Page

The index_html variable contains all the HTML, CSS and JavaScript to build the web page.

Note: for the simplicity of this tutorial, we’re placing everything needed to build the web page on the index_html 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 ESP32 filesystem and reference them on the code.

Here’s the content index_html variable:

<!DOCTYPE HTML>
<html>
<head>
  <title>ESP Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
  <link rel="icon" href="data:,">
  <style>
    html {
      font-family: Arial; 
      display: inline-block; 
      text-align: center;
    }
    p { 
      font-size: 1.2rem;
    }
    body {  
      margin: 0;
    }
    .topnav { 
      overflow: hidden; 
      background-color: #50B8B4; 
      color: white; 
      font-size: 1rem; 
    }
    .content { 
      padding: 20px; 
    }
    .card { 
      background-color: white; 
      box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); 
    }
    .cards { 
      max-width: 800px; 
      margin: 0 auto; 
      display: grid; 
      grid-gap: 2rem; 
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
    .reading { 
      font-size: 1.4rem;  
    }
  </style>
</head>
<body>
  <div class="topnav">
    <h1>BME280 WEB SERVER (SSE)</h1>
  </div>
  <div class="content">
    <div class="cards">
      <div class="card">
        <p><i class="fas fa-thermometer-half" style="color:#059e8a;"></i> TEMPERATURE</p>
        <p><span class="reading"><span id="temp">%TEMPERATURE%</span> &deg;C</span></p>
      </div>
      <div class="card">
        <p><i class="fas fa-tint" style="color:#00add6;"></i> HUMIDITY</p>
        <p><span class="reading"><span id="hum">%HUMIDITY%</span> &percnt;</span></p>
      </div>
      <div class="card">
        <p><i class="fas fa-angle-double-down" style="color:#e1e437;"></i> PRESSURE</p><p><span class="reading"><span id="pres">%PRESSURE%</span> hPa</span></p>
      </div>
    </div>
  </div>
<script>
if (!!window.EventSource) {
  var source = new EventSource('/events');

  source.addEventListener('open', function(e) {
    console.log("Events Connected");
  }, false);

  source.addEventListener('error', function(e) {
    if (e.target.readyState != EventSource.OPEN) {
      console.log("Events Disconnected");
    }
  }, false);

  source.addEventListener('message', function(e) {
    console.log("message", e.data);
  }, false);

  source.addEventListener('temperature', function(e) {
    console.log("temperature", e.data);
    document.getElementById("temp").innerHTML = e.data;
  }, false);

  source.addEventListener('humidity', function(e) {
    console.log("humidity", e.data);
    document.getElementById("hum").innerHTML = e.data;
  }, false);

  source.addEventListener('pressure', function(e) {
    console.log("pressure", e.data);
    document.getElementById("pres").innerHTML = e.data;
  }, false);
}
</script>
</body>
</html>

We won’t go into detail on how the HTML and CSS works. We’ll just take a look at how to handle the events sent by the server.

CSS

Between the <style> </style> 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’t explain how the CSS for this web page works because it is not relevant for this tutorial.

<style>
  html {
    font-family: Arial; 
    display: inline-block; 
    text-align: center;
  }
  p { 
    font-size: 1.2rem;
  }
  body {  
    margin: 0;
  }
  .topnav { 
    overflow: hidden; 
    background-color: #50B8B4; 
    color: white; 
    font-size: 1rem; 
  }
  .content { 
    padding: 20px; 
  }
  .card { 
    background-color: white; 
    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); 
  }
  .cards { 
    max-width: 800px; 
    margin: 0 auto; 
    display: grid; 
    grid-gap: 2rem; 
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
  .reading { 
    font-size: 1.4rem;  
  }
</style>

HTML

Between the <body> </body> tags we add the web page content that is visible to the user.

<body>
  <div class="topnav">
    <h1>BME280 WEB SERVER (SSE)</h1>
  </div>
  <div class="content">
    <div class="cards">
      <div class="card">
        <p><i class="fas fa-thermometer-half" style="color:#059e8a;"></i> TEMPERATURE</p>
        <p><span class="reading"><span id="temp">%TEMPERATURE%</span> &deg;C</span></p>
      </div>
      <div class="card">
        <p><i class="fas fa-tint" style="color:#00add6;"></i> HUMIDITY</p>
        <p><span class="reading"><span id="hum">%HUMIDITY%</span> &percnt;</span></p>
      </div>
      <div class="card">
        <p><i class="fas fa-angle-double-down" style="color:#e1e437;"></i> PRESSURE</p><p><span class="reading"><span id="pres">%PRESSURE%</span> hPa</span></p>
      </div>
    </div>
  </div>

There’s a heading 1 with the content “BME280 WEB SERVER (SSE)”. That’s the text that shows up on the top bar. Feel free to modify that text.

<h1>BME280 WEB SERVER (SSE)</h1>

Then, we display the sensor readings in separated div tags. Let’s take a quick look at the paragraphs that displays the temperature:

<p><i class="fas fa-thermometer-half" style="color:#059e8a;"></i> TEMPERATURE</p>
<p><span class="reading"><span id="temp">%TEMPERATURE%</span> &deg;C</span></p>

The first paragraph simply displays the “TEMPERATURE” text. We define the color and also an icon.

On the second paragraph, you can see that the %TEMPERATURE% placeholder is surrounded by <span id=”temp”> </span> tags. The HTML id attribute is used to specify a unique id for an HTML element.

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’s what we’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 “temp” with the new reading.

A similar process is done to update the other readings.

JavaScript – EventSource

The JavaScript goes between the <script> </script> tags. It is responsible for initializing an EventSource connection with the server and handle the events received from the server.

<script>
if (!!window.EventSource) {
  var source = new EventSource('/events');
  source.addEventListener('open', function(e) {
    console.log("Events Connected");
  }, false);
  source.addEventListener('error', function(e) {
    if (e.target.readyState != EventSource.OPEN) {
      console.log("Events Disconnected");
    }
  }, false);

  source.addEventListener('message', function(e) {
    console.log("message", e.data);
  }, false);

  source.addEventListener('temperature', function(e) {
    console.log("temperature", e.data);
    document.getElementById("temp").innerHTML = e.data;
  }, false);

  source.addEventListener('humidity', function(e) {
    console.log("humidity", e.data);
    document.getElementById("hum").innerHTML = e.data;
  }, false);

  source.addEventListener('pressure', function(e) {
    console.log("pressure", e.data);
    document.getElementById("pres").innerHTML = e.data;
  }, false);
}
</script>

Let’s take a look at how this works.

Handle Events

Create a new EventSource object and specify the URL of the page sending the updates. In our case, it’s /events.

if (!!window.EventSource) {
  var source = new EventSource('/events');

Once you’ve instantiated an event source, you can start listening for messages from the server with addEventListener().

These are the default event listeners, as shown here in the AsyncWebServer documentation.

source.addEventListener('open', function(e) {
  console.log("Events Connected");
}, false);

source.addEventListener('error', function(e) {
  if (e.target.readyState != EventSource.OPEN) {
    console.log("Events Disconnected");
  }
}, false);

source.addEventListener('message', function(e) {
  console.log("message", e.data);
}, false);

Then, add the event listener for “temperature”.

source.addEventListener('temperature', function(e) {

When a new temperature reading is available, the ESP32 sends an event (“temperature”) to the client. The following lines handle what happens when the browser receives that event.

console.log("temperature", e.data);
document.getElementById("temp").innerHTML = e.data;

Basically, print the new readings on the browser console, and put the received data into the element with the corresponding id (“temp“) on the web page.

A similar processor is done for humidity and pressure.

source.addEventListener('humidity', function(e) {
  console.log("humidity", e.data);
  document.getElementById("hum").innerHTML = e.data;
}, false);
 
source.addEventListener('pressure', function(e) {
  console.log("pressure", e.data);
  document.getElementById("pres").innerHTML = e.data;
}, false);
 
source.addEventListener('gas', function(e) {
  console.log("gas", e.data);
  document.getElementById("gas").innerHTML = e.data;
}, false);

setup()

In the setup(), initialize the Serial Monitor, initialize Wi-Fi and the BME280 sensor.

Serial.begin(115200);
initWiFi();
initBME();

Handle Requests

When you access the ESP32 IP address on the root / URL, send the text that is stored on the index_html variable to build the web page and pass the processor as argument, so that all placeholders are replaced with the latest sensor readings.

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/html", index_html, processor);
});

Server Event Source

Set up the event source on the server.

// Handle Web Server Events
events.onConnect([](AsyncEventSourceClient *client){
  if(client->lastId()){
    Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
  }
  // send event with message "hello!", id current millis
  // and set reconnect delay to 1 second
  client->send("hello!", NULL, millis(), 10000);
});
server.addHandler(&events);

Finally, start the server.

server.begin();

loop()

In the loop(), get new sensor readings:

getSensorReadings();

Print the new readings in the Serial Monitor.

Serial.printf("Temperature = %.2f ºC \n", temperature);
Serial.printf("Humidity = %.2f % \n", humidity);
Serial.printf("Pressure = %.2f hPa \n", pressure);
Serial.println();

Finally, send events to the browser with the newest sensor readings to update the web page.

// Send Events to the Web Server with the Sensor Readings
events.send("ping",NULL,millis());
events.send(String(temperature).c_str(),"temperature",millis());
events.send(String(humidity).c_str(),"humidity",millis());
events.send(String(pressure).c_str(),"pressure",millis());

Demonstration

After inserting your network credentials on the ssid and password variables, you can upload the code to your board. Don’t forget to check if you have the right board and COM port selected.

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.

ESP32 Web Server using Server Sent Events Serial Monitor Demonstration

Open a browser on your local network and insert the ESP32 IP address. You should get access to the web page to monitor the sensor readings.

BME280 Web Server using Server-Sent Events ESP32

The readings are updated automatically every 30 seconds.

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 Ctrl+Shift+J.

Server-Sent Events Browser Console ESP2 Web Server Demonstration

Wrapping Up

In this tutorial you’ve learned how to use Server-Sent Events with the ESP32. 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.

We have a similar tutorial but using the BME680 environmental sensor. You can check the tutorial on the following link:

Instead of Server-Sent Events, you can also use the WebSocket protocol to keep the web page updated. Take a look at the following tutorial to learn how to set up a WebSocket server with the ESP32:

Learn more about the ESP32 with our resources:



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Enjoyed this project? Stay updated by subscribing our newsletter!

71 thoughts on “ESP32 Web Server using Server-Sent Events (Update Sensor Readings Automatically)”

  1. Excellent tutorial however I would like to know the advantages/disadvantages of Web Sent Events as opposed to using the Web Sockets protocol like you have described in a previous project.

    thanks and best regards,
    Carl

    Reply
    • Completely agree, great article and answers very neatly how I can introduce live behaviour to my ESP served pages easily.

      I am also interested in the pros and cons of SSE vs WS for this sort of application, as I’ve not used either yet.

      Reply
    • SSE has a messaging protocol so you can have a general UTF-8 message string, or labelled message like “temperature” with a UTF-8 string value (as in the software above). Typically json is used to format more complex data, so we could have used “TPH”:{“temperature”:25.2, “pressure”:1012, “humidity”:76.8} to send 3 readings in one message. With websockets, messages are a byte string and you have to come up with your own protocol.

      The SSE server implementation is simpler– it’s similar to a normal HTTP reply except you don’t give a length, then just keep the socket open to output a few more lines (with a flush) for each message. With websockets the client/server needs to implement a protocol to convert the http socket to separately managed websocket. But when changed to a websocket, the TCP connection doesn’t count against the limit per server. With libraries though, there might not be that much difference in top level software.

      Websockets are bidirectional, so the client can send messages to the server while receiving push data. You can see the difference in https://randomnerdtutorials.com/esp32-websocket-server-arduino/ which combines commands from the client with data (status) from the server. I believe browsers reissue a new request when the connection is broken, whereas websockets need to handle errors as you can see in the RNT tutorial above.

      Reply
    • Carl, did you receive a response to your question?

      I am looking at this project as some what of a beginner with WiFi but good with Arduino hacker. Does this Arduino sketch automaticaclly update the data posted to the Web page (with each iteration of the void loop()); or does the web page it self have to be manually refreshed to udate the current data vales?

      Reply
  2. Thanks for the tutorial– I didn’t know about SSE before and it’s a good comparison with the prior websocket implementation.

    I don’t understand how the float value gets converted into a %.2f (apparently) string when sending events. Seems like sprintf() should have been used instead of String().c_str(). Maybe the libraries return sensor readings with an int to 1/100 decimal value?

    But in engineering school we were taught to not show more precision than you have, so if the BME has +-1degC, +-3% RH, and +-1hPa, then seems like you want to display temperature and pressure with with %.1f, and humidity rounded to an int().

    Reply
  3. Great tutorial!
    but how would one send calibration offsets to fix small errors in the temperature/humidity and differentiate from 2 sensor boards?

    ie temperature measured by sensor 1 is 23.5 sensor 2 reads 23.00 when both in the same location – the actual temperature is 22.8 -” read from a calibrated thermometer.

    How does the SSE know which board is which if you had 2 sensors in a room?. Can we use the sensor boards mac address as an id or do we need to another method.

    Reply
    • Hi.
      You can send a JSON string with the two temperature values.
      Or you can create an event for each reading. For example “sensor1” and “sensor2” like in this tutorial. We have three events for each reading.
      Regards,
      Sara

      Reply
  4. Great write up. I took the liberty to adapt your code for an esp8266. Also tailored it a bit for my needs (added a reading, made a static connection) Maybe it is of use to someone
    gitlab.com/diy_bloke/esp8266webserversse

    Reply
  5. A few notes on my experience with this sketch:

    The BME280 board I received from Adafruit was part # P2652. This board has a few differences from the one you pictured. I’m not sure they still offer your style board. If the esp32 pin 21 is connected to SDI pin of the Adafruit board and SDO is connected to ground everything works fine. Don’t leave SDO floating! Connecting it to 3.3volt will change the boards address to 77h.

    Thanks.

    Reply
  6. My compile aborts with an error that I don’t understand:

    /Users/imac2019/Documents/Arduino/sketch_oct23a/sketch_oct23a.ino: In function ‘void loop()’:
    sketch_oct23a:180:51: error: unknown conversion type character 0xa in format [-Werror=format=]
    Serial.printf(“Humidity = %.2f % \n”, humidity);

    Arduino: 1.8.13 (Mac OS X), Board: “NodeMCU-32S, 80MHz, 921600”

    Presumably I’ve got something wrong in my IDE environment – any suggestions?
    Thanks.

    Reply
    • Hi.
      I’ve just tested the code for your specific board and it compiles fine.
      Are you try to run the code as it is or did you change anything?
      Regards,
      Sara

      Reply
    • It is croaking on the % at the end. character 0xa is the \n, and it sees %\n like %i %s %d, etc., and doesn’t recognize the ” \n”. To include a % inside a printf, use %%. [A space is a valid flag after a % meaning reserve a column for optional -, then it looks at the next character for type.]

      Use: Serial.printf(“Humidity = %.2f %%\n”, humidity);

      Reply
  7. Many thanks Sara. I’ve tried again, copying the code directly from ‘Raw Code’, as well as from where you say ‘copy the following code …’ and still get the same error result.
    Your other server examples still compile with no problems on my iMac. However, I have had some recent problems where some of my Arduino files located themselves onto my iCloud drive, and I have been trying to untangle them. I suspect I have upset something whilst doing that but it’s strange that all else works fine.

    Reply
  8. An update on my comment of 40 mins ago …

    I can get round the above compile error by changing:
    Serial.printf(“Humidity = %.2f % \n”, humidity);
    to:
    Serial.printf(“Humidity = %.2f %% \n”, humidity);
    But then I get another compile error;
    /Users/imac2019/Documents/Arduino/sketch_oct30a/sketch_oct30a.ino: In function ‘String processor(const String&)’:
    sketch_oct30a:79:1: error: control reaches end of non-void function [-Werror=return-type]
    }

    and I can get round that error by adding the line:
    return String(“Happy Christmas”);
    before the last curly bracket of the function:
    String processor(const String& var).

    Have to say I don’t fully understand what I am doing, but it compiles now. Am I the only one to have these hiccups?

    Many thanks for all these really useful web pages. I am trying to make a temperature sensor to put in my fridge and communicate to the fridge pump controller using WiFi or BLE but I am having problems with large amount of current needed by the ESP32 board. Have you done any tutorials on making the board go to sleep for a period of time between sending temperature readings?

    Reply
  9. I tried the “ESP32 Web Server using Server-Sent Events (SSE) program that gives me satisfaction. Nevertheless, I would like to do a local server version with “SoftAP”. A quick search for information seems to prove incompatibilities with this process. Do you think this is possible and how?

    Reply
  10. Hi Ruis, Hi Sara
    I downloaded the needed libraries and installed them as add zip-library
    then I tried to compile the code.
    But I get a lot of compiler-errors

    here some of them
    C:\Users\Stefan\Documents\Arduino\libraries\AsyncTCP-master\src\AsyncTCP.cpp:291:65: error: invalid conversion from ‘err_t ()(tcpip_api_call) {aka signed char ()(tcpip_api_call)}’ to ‘tcpip_api_call_fn {aka signed char ()(tcpip_api_call_data)}’ [-fpermissive]

    tcpip_api_call(_tcp_output_api, (struct tcpip_api_call*)&msg);

    ^

    C:\Users\Stefan\Documents\Arduino\libraries\AsyncTCP-master\src\AsyncTCP.cpp:291:65: error: cannot convert ‘tcpip_api_call‘ to ‘tcpip_api_call_data‘ for argument ‘2’ to ‘err_t tcpip_api_call(tcpip_api_call_fn, tcpip_api_call_data*)’

    C:\Users\Stefan\Documents\Arduino\libraries\AsyncTCP-master\src\AsyncTCP.cpp:259:12: note: class type ‘tcpip_api_call’ is incomplete

    struct tcpip_api_call call;

    ^

    C:\Users\Stefan\Documents\Arduino\libraries\AsyncTCP-master\src\AsyncTCP.cpp: In function ‘esp_err_t _tcp_write(tcp_pcb*, const char*, size_t, uint8_t)’:

    C:\Users\Stefan\Documents\Arduino\libraries\AsyncTCP-master\src\AsyncTCP.cpp:307:64: error: invalid conversion from ‘err_t ()(tcpip_api_call) {aka signed char ()(tcpip_api_call)}’ to ‘tcpip_api_call_fn {aka signed char ()(tcpip_api_call_data)}’ [-fpermissive]

    I guess this is caused by a invalid combination of libraries
    How can I setup up a second Arduino-IDE that works independent from the first?
    I guess it will be a big hassle to sort out all the installed libraries I have
    and i don’t want to install the Arduino-IDE new

    Just installing another Arduino-IDE does NOT work! It uses the same sketch and library-folders as the main IDE

    Reply
  11. finally found a solution. I had an older version of AsyncTCP installed.
    This caused the compiler-error-messages.
    So I deleted all asyncTCP-folders on my harddisk and installed them new

    Reply
  12. If instead of sending the read value, I want to send a string from the processor function, as I would, for example, if it is level 1, then the string receives a value and if not, it receives another, if I want to pass the string to the browser and have updated instantly, how would I do?

    Good night and thank you for the excellent work done by the whole team.

    Reply
    • Hi.
      You don’t need to use the processor.
      You can create an event for the string you want to send.
      Then, you need to modify the JavaScript code to read those events.
      It is a bit difficult to explain in a comment, but I hope this helps.
      Regards,
      Sara

      Reply
  13. Hi,
    I have used the exact same code and cannot get the SSE part to work.
    The initial values come through when the web page is first loaded or a refresh (F5) but after that I get no further updates on the browser.
    Ctl+Shift+J shows the initial data come through but no further communication.
    Placing a breakpoints in the js file for the initial load and for the SSE function causes the script to pause at the initial load (line 24) and stepping through shows the reading of the data from the JSON.
    The breakpoint in the SSE area (line 51) of the “source.addEventListener(‘new_readings’, function(e) ” shows that this never gets called.

    What am I missing?

    Thanks Neil.

    P.S.
    In a working scenario, what does http://mydevice/events/ display?

    Reply
      • Hi,
        Thank you for replying.
        I have not changed the code.

        I think the issue is that it is being blocked by our corporate firewall.
        Do you know what port it uses for the SSE?
        Thanks.

        Reply
  14. hi,
    I’ve tested your program on a esp32 wroom32 and works pretty nice. I have changed the sensor to BMP280 because that is what I had. No humidity but I don’t care. it’s about getting the script working and it did.
    Now my question: I have Domoticz as my home system where I would like to send the measurements to. I know how to do it with curl in other applications but don not know how to in this sketch.
    Can you tell me how a command looks like, (Domoticz uses indexes (number) to present data on a device.)
    thanks in advance.

    Reply
  15. Great tutorial. Extremely helpful and very inspiring.
    Would you kindly guide me on how to proceed with your guideline on how to separate HTML, CSS and JavaScript file to the ESP32 FileSystem ?

    “Note: for the simplicity of this tutorial, we’re placing everything needed to build the web page on the index_html 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 ESP32 filesystem and reference them on the code. “

    Reply
  16. Hi,
    What is the option to change the colour of the text or icon s depends of their value?
    As example if the temperature is below 18 degree the icon is in blue colour, between 18 and 28 is green and abouve 28 orange..etc?
    Thank you in advance

    Reply
  17. Hi,
    I have some existing code to which I want to add SSE updates, but events are not received in the browser.
    They don’t appear in the Chrome’s developper tool.

    In my HTML code, I added a 2nd event source and 2 handlers:
    if (!!window.EventSource) {
    var source = new EventSource(‘update’); /*If I change this, my other stuff doesn’t work */
    var source2 = new EventSource(‘/events’);
    }
    source2.addEventListener(‘console’, function(event) {
    console.log(“myevent”, event.data);
    }, false);
    source2.addEventListener(‘stop_button’, function(event) {
    document.getElementById(“stop_button”).checked = false;
    }, false);

    In the Arduino code, I added:
    AsyncEventSource events(“/events”);

    void guiStop()
    {
    events.send(“stop_button”,NULL,millis());
    }

    void webConsole(const char *str)
    {
    events.send(“console”,str,millis());
    }

    void InitWebServer()
    {
    /* other stuff */
    server.addHandler(&events);
    server.begin();
    }

    Reply
  18. I solved this by correcting the order of parameters in events:
    events.send(NULL,“stop_button”,millis());
    and
    events.send(str,“console”,millis());

    Now it works fine. I can send debugging messages on Chrome’s console.

    Can this work with the esp_http_server library?

    Reply
  19. Hi,
    how many (events.send) can I send in sequence?
    I mean, I have this situation:
    events.send(“ping”, NULL, millis());
    events.send(String(hostname).c_str(), “host”, millis());
    events.send(String(Ver).c_str(), “revision”, millis());
    events.send(String(scanner).c_str(), “fnames”, millis());
    events.send(String(ssid).c_str(), “fname”, millis());
    events.send(String(password).c_str(), “fpass”, millis());
    events.send(String(apmode).c_str(), “wifimode”, millis());
    events.send(String(sidebar).c_str(), “sidebar”, millis());

    the last one and even if I add another, it is not sent to the browser.
    why?
    is there a limit?

    Thank you for any answer

    Reply
  20. Hello
    I would like to ask if I use MIT APP inventor with ESP8266 AT command, is this method feasible? I can’t find relevant information about MIT APP inventor about SSE.

    Reply
  21. hi, i use your method for server sent web server but using my own sensor. my sensor is QMC5883L, i already done uploading to ESP32, but as soon as program start, my ESP crash.
    this the error ESP crash :
    assert failed: tcpip_api_call IDF/components/lwip/lwip/src/api/tcpip.c:497 (Invalid mbox)

    Backtrace:0x400833ad:0x3ffb25c00x40088339:0x3ffb25e0 0x4008d185:0x3ffb2600 0x400e517e:0x3ffb2730 0x400d28b5:0x3ffb2760 0x400d8dbe:0x3ffb27b0 0x400d1e4a:0x3ffb27d0 0x400db12e:0x3ffb2820

    ELF file SHA256: 0000000000000000

    Rebooting…

    could u help me to fix this error, i think this error from librabri AsyncTCP. please Help.

    Reply
    • Hi.
      What libraries are you using to read your sensor?
      Where are you reading the sensor in the code?
      Have you tried to read the sensor without the server code? Just to check that it’s working properly?
      Regards,
      Sara

      Reply
  22. Hello Rui and Sara.
    There is a typo error in the comment line just above the events.sent() funtions In the loop () function of the .ino file.
    It should say “// Send Events to the Web Client with the Sensor Readings” and not Web Server.
    The explanation text is the correct way around.

    void loop() {
    if ((millis() – lastTime) > timerDelay) {
    getSensorReadings();
    Serial.printf(“Temperature = %.2f ºC \n”, temperature);
    Serial.printf(“Humidity = %.2f \n”, humidity);
    Serial.printf(“Pressure = %.2f hPa \n”, pressure);
    Serial.println();

    // Send Events to the Web Server with the Sensor Readings
    events.send("ping",NULL,millis());
    events.send(String(temperature).c_str(),"temperature",millis());
    events.send(String(humidity).c_str(),"humidity",millis());
    events.send(String(pressure).c_str(),"pressure",millis());

    lastTime = millis();

    }
    }

    Reply
  23. Hi! I’ve been enjoying using your great explanatory tutorials and every one I’ve tried works perfectly. I know the answer may be difficult to convey, but what I am trying to accomplish is taking this tutorial using SSE and another of your tutorials to use SPIFFS to hold the CSS & HTML files. But the event.send doesn’t reach browser when I have put index.html in SPIFFS. All loads ok upon startup/refresh but not thereafter. Should I amend these lines?

    events.send(String(result1).c_str(),"result1",millis());
    events.send(String(result2).c_str(),"result2",millis());
    events.send(String(result3).c_str(),"result3",millis());

    where result* substitutes %RESULT1%, %RESULT2% etc.. or add something like;

    server.on(“/result1”, HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, String(result1).c_str(), “text/html”);

    I know this is leaning on your expertise but I don’t quite understand the syntax and workings of HTTP.

    Thank you for any guidance you can offer. I’ll keep changing bits and see if I can there eventually.

    Darren

    Reply
  24. Hello,

    I’m trying to use this example (ESP32 Web Server using Server-Sent Events (Update Sensor Readings Automatically)) with arduino 2.0. but some time my device report this error:

    Guru Meditation Error: Core 1 panic’ed (LoadProhibited). Exception was unhandled.
    Core 1 register dump:
    PC : 0x400d34fa PS : 0x00060230 A0 : 0x800d3592 A1 : 0x3ffb1ef0
    A2 : 0x3ffcb974 A3 : 0xe008b083 A4 : 0x00000029 A5 : 0x3ffd1784
    A6 : 0x0000000a A7 : 0x0d0a0d30 A8 : 0x800d3508 A9 : 0x3ffb1ed0
    A10 : 0x00000029 A11 : 0x00000029 A12 : 0x00000029 A13 : 0x00000029
    A14 : 0x00000000 A15 : 0x00000000 SAR : 0x0000000a EXCCAUSE: 0x0000001c
    EXCVADDR: 0xe008b083 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0xffffffff

    ELF file SHA256: 0000000000000000

    Backtrace: 0x400d34fa:0x3ffb1ef0 0x400d358f:0x3ffb1f10 0x400d35ab:0x3ffb1f30 0x400d3601:0x3ffb1f50 0x400d0d5d:0x3ffb1f80 0x400da2d9:0
    x3ffb1fb0 0x40089792:0x3ffb1fd0

    Rebooting…

    Does anyone have similar problem?

    Best Regards,
    Kriss

    Reply
      • Hi.
        Which version of the ESP32 installation are you using?
        Go to Tools > Board > Boards Manager, search for ESP32 and check your version.
        Regards,
        Sara

        Reply
    • I added delays between sending events to the browser with the latest sensor readings to refresh the web page:
      events.send(String(temperature).c_str(),”temperature”,millis());
      delay(20);
      events.send(String(humidity).c_str(),”humidity”,millis());
      delay(20);
      events.send(String(pressure).c_str(),”pressure”,millis());
      delay(20);

      This solved the problem.

      Reply
  25. Hello,
    This happens when I try to connect second clent.
    I’m not using “//#include <Adafruit_BME280.h //#include <Adafruit_Sensor.h>”.
    I’m just testing Async SSE with increment variables in loop() like this:

    void loop() {
    if ((millis() – lastTime) > timerDelay) {
    //getSensorReadings();
    temperature+=1.1;
    humidity+=1.2;
    pressure+=1.3;

    // Serial.printf("\r\n\nTemperature = %.2f oC\n", temperature);
    // Serial.printf("\r\nHumidity = %.2f \n", humidity);
    // Serial.printf("\r\nPressure = %.2f hPa\n", pressure);

    // Send Events to the Web Client with the Sensor Readings
    events.send("ping",NULL,millis());
    events.send(String(temperature).c_str(),"temperature",millis());
    events.send(String(humidity).c_str(),"humidity",millis());
    events.send(String(pressure).c_str(),"pressure",millis());

    lastTime = millis();

    }
    }

    Best Regards,
    Kriss

    Reply
    • I’m not sure what might be wrong…
      Try sending the same value in every loop and see if that changes anything.
      Regards,
      Sara

      Reply
  26. Hi,
    The problem is the same with fixed values!
    When connect more than one client get “Guru Meditation Error: Core 1 panic’ed (LoadProhibited). Exception”.
    May be something wrong in “AsyncTCP” lib? How can I find the problem?

    Best Regards,
    Kriss

    Reply
  27. Hi,

    it seems every tutorial on this topic uses this line for sending a “ping” event, which is nowhere handled in the rest of the code:
    events.send(“ping”,NULL,millis());
    Why did you include this? What effect does it have? I assume that this line had a purpose in another version of a similar example (maybe to keep the line alive), then the example was adapted by someone, and now this line would not be required, but erverybody keeps copying it in their tutorials. Could you please shed light on this?

    I’d like to add that I very much like your tutorials, they are well-structured and have helped me already several times!

    Thanks, best regards,
    Max

    Reply
    • Hi.
      You’re right.
      That line is not handled anywhere in the code.
      It basically was meant to check on the client side (on the web browser) that the server is alive. However, as you mentioned it is not handled anywhere on the Javascript. So, yes, you can remove it because we’re sending sensor readings at the same time as the ping event.
      If you were not sending sensor readings for a long period of time, it may be a good idea to send a ping event to maintain the client alive.

      Regards,
      Sara

      Reply
      • Hi Sara,
        perfect, thanks! (-:

        There’s another question I’d like to ask: Could you please explain what the “reconnect delay” is? And maybe there’s a typo in the code? (Is it actually 1 second or 10seconds (10000ms)?

        // Handle Web Server Events
        events.onConnect([](AsyncEventSourceClient *client){
        if(client->lastId()){
        Serial.printf(“Client reconnected! Last message ID that it got is: %u\n”, client->lastId());
        }
        // send event with message “hello!”, id current millis
        // and set reconnect delay to 1 second
        client->send(“hello!”, NULL, millis(), 10000);
        });

        Best regards,
        Max

        Reply
  28. Hello!
    This is a very nice tutorial, but I’m getting an error when I try to compile:
    C:\Users\cesar\OneDrive\Maker_ESP32\Examples\HTTP-Sensor\HTTP-Sensor.ino:64:45: error: array must be initialized with a brace-enclosed initializer
    const unsigned char* index_html[] PROGMEM = R”rawliteral(
    ^~~~~~~~~~~~~
    After this one, obviously, there’s an error for each new line since the C++ preprocessor thinks they are C++ statements.
    Any ideas?
    Thanks!

    Reply
  29. Hi!
    I had to tweak the code a little bit to use a DHT11 (I don’t have a BME), so I removed includes for <Adafruit_BME280.h> and <Adafruit_Sensor.h> and also any references to pressure in the code and in the HTML portion.
    I added the include for DHT and changed the initBME accordingly.
    The code compiles and uploads fine, I get the IP address after the ESP32 connects to Wi-Fi, but can’t get the web page working since the application keeps crashing:
    Connecting to WiFi …192.168.0.76
    Guru Meditation Error: Core 1 panic’ed (Interrupt wdt timeout on CPU1).

    Core 1 register dump:
    PC : 0x400db8ee PS : 0x00060335 A0 : 0x800db9d8 A1 : 0x3ffca3d0
    A2 : 0x00012ef1 A3 : 0x00000001 A4 : 0x3ffc3754 A5 : 0x00000001
    A6 : 0x00060b20 A7 : 0x00000001 A8 : 0x00027100 A9 : 0x00012ef2
    A10 : 0x00000001 A11 : 0x00000000 A12 : 0x01ca1683 A13 : 0x00000004
    A14 : 0x00000028 A15 : 0x003fffff SAR : 0x00000002 EXCCAUSE: 0x00000006
    EXCVADDR: 0x00000000 LBEG : 0x400857b5 LEND : 0x400857bd LCOUNT : 0x00000027

    Any ideas?

    Reply
  30. So, trying this code using Arduino 2.2.1, I added the two libraries, making sure any old versions were deleted. But when I try and compile I get these errors:

    c:\Users\Test\Documents\Arduino\libraries\ESP_Async_WebServer\src\AsyncWebSocket.cpp: In member function ‘IPAddress AsyncWebSocketClient::remoteIP()’:
    c:\Users\Test\Documents\Arduino\libraries\ESP_Async_WebServer\src\AsyncWebSocket.cpp:832:28: error: call of overloaded ‘IPAddress(unsigned int)’ is ambiguous
    return IPAddress(0U);
    ^
    In file included from C:\Users\test\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.10\cores\esp32/Arduino.h:180,
    from c:\Users\Test\Documents\Arduino\libraries\ESP_Async_WebServer\src\AsyncWebSocket.cpp:21:
    C:\Users\test\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.10\cores\esp32/IPAddress.h:51:5: note: candidate: ‘IPAddress::IPAddress(const uint8_t*)’
    IPAddress(const uint8_t *address);
    ^~~~~~~~~
    C:\Users\test\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.10\cores\esp32/IPAddress.h:50:5: note: candidate: ‘IPAddress::IPAddress(uint32_t)’
    IPAddress(uint32_t address);
    ^~~~~~~~~
    C:\Users\test\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.10\cores\esp32/IPAddress.h:29:7: note: candidate: ‘constexpr IPAddress::IPAddress(const IPAddress&)’
    class IPAddress: public Printable
    ^~~~~~~~~

    exit status 1

    Compilation error: exit status 1

    Any idea what I’m doing wrong or how to fix this?

    Reply
    • Hi.
      What are the ESP32 boards version you have installed?
      Go to Tools > Boards > Boards Manager, search for ESP32 and check if you need to update your ESP32 boards.
      Regards,
      Sara

      Reply
      • Hi Sara,

        I’m using an ESP32-C3. I found the problem. I needed to edit libraries\ESPAsyncWebServer-master\src\AsyncWebSocket.cpp and replace “return IPAddress(0U)” with “return IPAddress((uin32_t) 0u)”. Once I did that it compiled and ran perfectly.

        Thanks

        Reply
  31. Great demo !

    Finding that it works great but after maybe 50 or 100 messages I get an “ack timeout 4” and the event connection drops out for a while then eventually comes back, with data loss in between. Seems related to the number of messages, moreso than speed of sending. Anyone else seeing this?

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.