ESP32 WebSocket Server: Monitor DHT11 Sensor Data on a Webpage Using Websocket

In this tutorial, you’ll learn how to set up a ESP32 WebSocket Server and use it to send real-time sensor data (temperature and humidity from a DHT11 sensor) to a web client. By the end, you’ll have a solid foundation to build more advanced IoT applications.

What is a WebSocket?

WebSocket is a powerful communication protocol that enables real-time, bidirectional communication between a client (e.g., a web browser) and a server (e.g., an ESP32). Unlike HTTP, which requires constant polling, WebSocket allows the server to push updates to the client instantly. This makes it ideal for IoT projects like real-time sensor monitoring, home automation, and interactive dashboards.

Learn, how is a WebSocket different from HTTP?

What is web socket and how it is different from the HTTP? – GeeksforGeeks


What You’ll Learn

  • How to set up a ESP32 WebSocket server.
  • How to send real-time sensor data to a web client.
  • How to create a simple web interface to display the data.

Components Required

  • ESP32 Development Board
  • DHT11 Temperature and Humidity Sensor
  • Breadboard and Jumper Wires
  • Micro-USB Cable

Wiring Diagram

ESP32 Websocket server using dht11 wiring diagram
  1. Connect the VCC pin of the DHT11 to the VIN pin of the ESP32.
  2. Connect the GND pin of the DHT11 to the GND pin of the ESP32.
  3. Connect the Data pin of the DHT11 to GPIO 27 of the ESP32.

Setting Up the ESP32 WebSocket Server

1. Installing ESP32 boards in arduino IDE

Before starting, make sure you have the ESP32 boards installed in your Arduino IDE:

How To Install ESP32 And ESP8266 Boards In Arduino IDE (Step-by-Step Guide) – ArduinoYard

2. Install Required Libraries

Make sure you have the following libraries installed in your Arduino IDE:

In Arduino IDE, Go to Sketch > Include Library > Manage Libraries.

  • Search for DHT Sensor Library (for reading data from the DHT11).
DHT Library Installation in arduino IDE
  • Search for WebSockets (for WebSocket communication).
Websockets Library Installation in arduino IDE
  • Search for ESPAsyncWebServer (for handling HTTP and WebSocket requests).
ESPAsyncWebServer Installation in arduino IDE
  • Search for AsyncTCP and install it.
AsyncTCP library installation

3. WebSocket Server Code

Here’s the complete code to set up the ESP32 WebSocket server and integrate the DHT11 sensor:

//ESP32 WebSocket Server Example by ArduinoYard
#include <WiFi.h>
#include <WebSocketsServer.h>
#include <ESPAsyncWebServer.h>
#include <DHT.h>

// Replace with your network credentials
// Replace with your network credentials
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

// DHT11 setup
#define DHTPIN 27
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

// WebSocket and Web Server setup
WebSocketsServer webSocket = WebSocketsServer(81);
AsyncWebServer server(80);
// HTML and JavaScript for the web interface
const char* htmlPage = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
  <title>ESP32 WebSocket</title>
</head>
<body>
  <h1>Real-Time Sensor Data</h1>
  <p>Temperature: <span id="temperature">--</span> C</p>
  <p>Humidity: <span id="humidity">--</span> %</p>
  <script>
    const ws = new WebSocket('ws://' + window.location.hostname + ':81/');
    ws.onmessage = function(event) {
      const data = JSON.parse(event.data);
      document.getElementById('temperature').innerText = data.temperature;
      document.getElementById('humidity').innerText = data.humidity;
    };
  </script>
</body>
</html>
)rawliteral";
// Variables to store sensor data
float temperature = 0;
float humidity = 0;

// Function to read sensor data
void readSensorData() {
  temperature = dht.readTemperature();
  humidity = dht.readHumidity();
  if (isnan(temperature) || isnan(humidity)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  Serial.printf("Temperature: %.2f °C, Humidity: %.2f %%\n", temperature, humidity);
}

// WebSocket event handler
void onWebSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) {
  switch (type) {
    case WStype_DISCONNECTED:
      Serial.printf("[%u] Disconnected!\n", num);
      break;
    case WStype_CONNECTED:
      Serial.printf("[%u] Connected!\n", num);
      break;
    case WStype_TEXT:
      // Handle incoming text messages (if needed)
      break;
  }
}

void setup() {
  // Start Serial Monitor
  Serial.begin(9600);

  // Initialize DHT sensor
  dht.begin();

  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");
  Serial.println(WiFi.localIP());

  // Start WebSocket server
  webSocket.begin();
  webSocket.onEvent(onWebSocketEvent);

  // Serve HTML page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
    request->send(200, "text/html", htmlPage);
  });
  server.begin();
}

void loop() {
  webSocket.loop(); // Handle WebSocket events

  // Read sensor data
  readSensorData();

  // Send sensor data to all connected WebSocket clients
  String data = "{\"temperature\":" + String(temperature) + ",\"humidity\":" + String(humidity) + "}";
  webSocket.broadcastTXT(data);

  delay(2000); // Update data every 2 seconds
}


How It Works

  1. The ESP32 connects to Wi-Fi and starts a WebSocket server on port 81.
  2. The DHT11 sensor reads temperature and humidity data every 2 seconds.
  3. The WebSocket server sends the sensor data to the connected client (web browser) in JSON format.
  4. The web interface displays the real-time data without refreshing the page.

Testing the Web Interface

  • Upload the code to your ESP32.
  • Open the Serial Monitor to get the ESP32’s IP address.
  • Open a web browser and navigate to http://<ESP32_IP>.
  • You should see the temperature and humidity values updating in real-time after getting the connected message for WebSocket. It will take few seconds to connect.
Webpage results

Customization

This ESP32 WebSocket server and web interface can be customized for various IoT applications. Here are some ideas:

1. Adding More Sensors

Let’s say you want to add a light sensor (LDR) to measure light intensity.

Changes in the Code:

a. Modify readSensorData():
/ Add LDR pin
#define LDR_PIN 34

// Add light intensity variable
float lightIntensity = 0;

void readSensorData() {
  temperature = dht.readTemperature();
  humidity = dht.readHumidity();
  lightIntensity = analogRead(LDR_PIN); // Read light intensity
  if (isnan(temperature) || isnan(humidity)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  Serial.printf("Temperature: %.2f °C, Humidity: %.2f %%, Light: %.2f\n", temperature, humidity, lightIntensity);
}
b. Update WebSocket Data Format:
String data = "{\"temperature\":" + String(temperature) + 
              ",\"humidity\":" + String(humidity) + 
              ",\"light\":" + String(lightIntensity) + "}";
webSocket.broadcastTXT(data);
c. Update JavaScript to Display Light Intensity:
<p>Light Intensity: <span id="light">--</span></p>
<script>
  const ws = new WebSocket('ws://' + window.location.hostname + ':81/');
  ws.onmessage = function(event) {
    const data = JSON.parse(event.data);
    document.getElementById('temperature').innerText = data.temperature;
    document.getElementById('humidity').innerText = data.humidity;
    document.getElementById('light').innerText = data.light;
  };
</script>

2. Controlling ESP32 Outputs

Let’s add an LED that can be controlled from the web interface.

Changes in the Code:

a. Add LED Pin:
#define LED_PIN 2  // GPIO 2 for the LED
bool ledState = false; // Track LED state
b. Update onWebSocketEvent() to Handle Commands:
void onWebSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) {
  switch (type) {
    case WStype_DISCONNECTED:
      Serial.printf("[%u] Disconnected!\n", num);
      break;
    case WStype_CONNECTED:
      Serial.printf("[%u] Connected!\n", num);
      break;
    case WStype_TEXT:
      // Handle incoming commands
      String message = (char*)payload;
      if (message == "ON") {
        digitalWrite(LED_PIN, HIGH);
        ledState = true;
      } else if (message == "OFF") {
        digitalWrite(LED_PIN, LOW);
        ledState = false;
      }
      // Send updated LED state to the client
      String response = "{\"ledState\":" + String(ledState ? "true" : "false") + "}";
      webSocket.sendTXT(num, response);
      break;
  }
}
c. Add LED Control Buttons to the HTML:
<button onclick="sendCommand('ON')">Turn LED ON</button>
<button onclick="sendCommand('OFF')">Turn LED OFF</button>
<p>LED State: <span id="ledState">OFF</span></p>
<script>
  const ws = new WebSocket('ws://' + window.location.hostname + ':81/');
  ws.onmessage = function(event) {
    const data = JSON.parse(event.data);
    if (data.ledState !== undefined) {
      document.getElementById('ledState').innerText = data.ledState ? "ON" : "OFF";
    }
  };

  function sendCommand(command) {
    ws.send(command);
  }
</script>

3. Enhancing the Web Interface

Let’s use Bootstrap to improve the design of the web interface.

Changes in the HTML:

a. Include Bootstrap CSS:
<!-- wp:preformatted -->
<pre class="wp-block-preformatted"><!DOCTYPE html>
<html>
<head>
  <title>ESP32 WebSocket Server</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="container mt-5">
  <h1 class="text-center">Real-Time Sensor Data</h1>
  <div class="card mt-3">
    <div class="card-body">
      <p class="card-text">Temperature: <span id="temperature">--</span> °C</p>
      <p class="card-text">Humidity: <span id="humidity">--</span> %</p>
      <p class="card-text">Light Intensity: <span id="light">--</span></p>
    </div>
  </div>
  <div class="mt-3">
    <button class="btn btn-primary" onclick="sendCommand('ON')">Turn LED ON</button>
    <button class="btn btn-danger" onclick="sendCommand('OFF')">Turn LED OFF</button>
    <p class="mt-2">LED State: <span id="ledState">OFF</span></p>
  </div>
  <script>
    const ws = new WebSocket('ws://' + window.location.hostname + ':81/');
    ws.onmessage = function(event) {
      const data = JSON.parse(event.data);
      if (data.temperature !== undefined) {
        document.getElementById('temperature').innerText = data.temperature;
      }
      if (data.humidity !== undefined) {
        document.getElementById('humidity').innerText = data.humidity;
      }
      if (data.light !== undefined) {
        document.getElementById('light').innerText = data.light;
      }
      if (data.ledState !== undefined) {
        document.getElementById('ledState').innerText = data.ledState ? "ON" : "OFF";
      }
    };

    function sendCommand(command) {
      ws.send(command);
    }
  </script>
</body>
</html>

4. Adding Security

Let’s add basic user authentication to restrict access to the web interface.

Changes in the Code:

a. Add Username and Password:
const char* username = "admin";
const char* password = "password";
b. Update server.on() to Require Authentication:
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
  if (!request->authenticate(username, password)) {
    return request->requestAuthentication();
  }
  request->send(200, "text/html", htmlPage);
});
c. Update HTML to Prompt for Credentials:

When you access the web interface, the browser will prompt for a username and password.

Optional: SSL/TLS for Secure WebSocket (WSS)

To enable secure WebSocket communication (WSS), you’ll need to:

  1. Generate SSL/TLS certificates.
  2. Use the WiFiClientSecure library instead of WiFiClient.
  3. Update the WebSocket server to use the secure client.

This is more advanced and requires additional setup, such as using a certificate authority (CA) or self-signed certificates.


Conclusion

In this tutorial, you learned how to set up a ESP32 WebSocket server, use it to send real-time sensor data to a web client and how can we customize this code to improve it and use it for different applications. This is a powerful foundation for building IoT projects that require real-time communication.

Thank You!!!


IN CASE YOU HAVE MISSED PREVIOUS ESP32 WEBSERVER PARTS:

Part 1: Getting Started With The ESP32 Web Server: Hello World! – ArduinoYard

Part 2: ESP32 Webserver LED Control: Toggle An LED Using A Webpage – ArduinoYard

Part 3: ESP32 Webserver PWM Control: Control Brightness Of An LED Using A Webpage – ArduinoYard

Part 4: ESP32 Webserver Alarm System: Building An Alarm System Using A Webpage – ArduinoYard

Part 5: ESP32 OTA Firmware Update: Update The ESP32 Firmware Using A Local Webpage – ArduinoYard

Part 6: ESP32 WiFi Manager: Creating A Simple WiFi Manager With Static IP Support – ArduinoYard

Leave a Comment