Using the library ESP32 WebSocket Server to combine LED control and sensor visualization

Hey guys,

I would like to be able to control LEDs together with reading sensors data using the library ESP32 WebSocket Server.

I found these two excellent tutos from Random Nerd Tutorials:
ESP32 WebSocket Server: Display Sensor Readings | Random Nerd Tutorials

ESP32 WebSocket Server: Control Outputs (Arduino IDE) | Random Nerd Tutorials

I tried to use them to do that but the LED control part does't work. I would need help, especially in the onMessage function of the Javascript part.

The sensor part is:

// Function that receives the message from the ESP32 with the readings
function onMessage(event) {
    console.log(event.data);
    var myObj = JSON.parse(event.data);
    var keys = Object.keys(myObj);

    for (var i = 0; i < keys.length; i++){
        var key = keys[i];
        document.getElementById(key).innerHTML = myObj[key];
    }
}

and for the LED, it looks like this:

  function onMessage(event) {
    var state;
    if (event.data == "1"){
      state = "ON";
    }
    else{
      state = "OFF";
    }
    document.getElementById('state').innerHTML = state;
  }
  window.addEventListener('load', onLoad);
  function onLoad(event) {
    initWebSocket();
    initButton();
  }

  function initButton() {
    document.getElementById('button').addEventListener('click', toggle);
  }
  function toggle(){
    websocket.send('toggle');
  }

I'm not showing all the code for clarity. The rest is shown on the two links above.

Thanks in advance for your help.
Laurent

What do you mean exactly?

Do you receive the message sent via websocket on the serial monitor from the ESP side?
If you open the browser dev-tool, what output messages are printed in console?
Can you successfully connect to the WS server?

Thanks for your reply.
I can connect to the WS server since the temperature and humidity data are displayed and updated.
It's only the "ON" or "OFF" data that doesn't appear in the html card when I press the button, and of course, the LED doesn't turn ON.
You're right, I should put a few message in the console to see what's wrong exactly. Sorry, I can't answer to these questions now. I will do that when I get back home.

If from the two projects from randomnerd, you made a single project by putting the code together, then you need to post all your code here and not only a portion or the links to the original projects because those work without problems.

You probably made some small copy-paste errors.

Ok, you're right. I will send it later today.

Hey @cotestatnt , I hope you will be patient enough to read all the code. Thanks in advance !

By the way, I realize reading sensor data and pressing a button to light a LED is a different event, but I don't know where to put the code for the LED. I started with the code for the sensor readings, and then tried to add the code for the LED.

The result is that I see the sensor data but when I press the button "Toggle", it doesn't turn ON.

There it is ...

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "SPIFFS.h"
#include <Arduino_JSON.h>
#include <DHT.h>

// DHT22
#define gpioDHT 19
#define typeDHT DHT22
// Instanciation of the library DHT
DHT dht(gpioDHT, typeDHT);

// LED
bool ledState = 0;
const int ledPin = 2;

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

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Create a WebSocket object
AsyncWebSocket ws("/ws");

// Json Variable to Hold Sensor Readings
JSONVar readings;

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

// Get Sensor Readings and return JSON object
String getSensorReadings(){
  Serial.println("DHT22 value");
  Serial.println("===========");

  // Data readings
  float humidity;
  float temperatureInCelsius;
  do {
    humidity = dht.readHumidity();
    temperatureInCelsius = dht.readTemperature();
  } while (isnan(humidity) || isnan(temperatureInCelsius));

  // Measurement of the heat index
  float heatIndex = dht.computeHeatIndex(temperatureInCelsius, humidity, false); // false is for °C, true is for °F
  
  // Display the values
  Serial.print("Humidity = "); Serial.print(humidity); Serial.println(" %");
  Serial.print("Temperature = "); Serial.print(temperatureInCelsius); Serial.println(" °C");
//  Serial.print("Heat index = "); Serial.print(heatIndex); Serial.println(" °C");
  Serial.println();

  readings["temperature"] = String(temperatureInCelsius);
  readings["humidity"] =  String(humidity);
  String jsonString = JSON.stringify(readings);
  return jsonString;
}

// Initialize SPIFFS
void initSPIFFS() {
  if (!SPIFFS.begin(true)) {
    Serial.println("An error has occurred while mounting SPIFFS");
  }
  Serial.println("SPIFFS mounted successfully");
}

// 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());
}

void notifyClients(String sensorReadings) {
  ws.textAll(sensorReadings);
}

void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
  AwsFrameInfo *info = (AwsFrameInfo*)arg;
  if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
    //data[len] = 0;
    //String message = (char*)data;
    // Check if the message is "getReadings"
    //if (strcmp((char*)data, "getReadings") == 0) {
      //if it is, send current sensor readings
      String sensorReadings = getSensorReadings();
      Serial.print(sensorReadings);
      notifyClients(sensorReadings);
    //}
  }
}

void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_CONNECT:
      Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
      break;
    case WS_EVT_DISCONNECT:
      Serial.printf("WebSocket client #%u disconnected\n", client->id());
      break;
    case WS_EVT_DATA:
      handleWebSocketMessage(arg, data, len);
      break;
    case WS_EVT_PONG:
    case WS_EVT_ERROR:
      break;
  }
}

void initWebSocket() {
  ws.onEvent(onEvent);
  server.addHandler(&ws);
}

void setup() {
  Serial.begin(115200);
  initWiFi();
  initSPIFFS();
  initWebSocket();

  // Initialisation du DHT22;
  dht.begin();

  // LED
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  
  // Web Server Root URL
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(SPIFFS, "/index.html", "text/html");
  });

  server.serveStatic("/", SPIFFS, "/");

  // Start server
  server.begin();
}

void loop() {
  if ((millis() - lastTime) > timerDelay) {
    String sensorReadings = getSensorReadings();
    Serial.print(sensorReadings);
    notifyClients(sensorReadings);

  lastTime = millis();

  }

  ws.cleanupClients();
  digitalWrite(ledPin, ledState);
}

HTML

<!DOCTYPE html>
<html>
    <head>
        <title>ESP IOT DASHBOARD</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="icon" type="image/png" href="favicon.png">
        <link rel="stylesheet" type="text/css" href="style.css">
    </head>
    <body>
        <div class="topnav">
            <h1>SENSOR READINGS + LED ctl</h1>
        </div>
        <div class="content">
            <div class="card-grid">
                <div class="card">
                    <p class="card-title"><i class="fas fa-thermometer-threequarters" style="color:#059e8a;"></i> Temperature</p>
                    <p class="reading"><span id="temperature"></span> &deg;C</p>
                </div>
                <div class="card">
                    <p class="card-title"> Humidity</p>
                    <p class="reading"><span id="humidity"></span> &percnt;</p>
                </div>
                <div class="card">
                    <h2>GPIO 2</h2>
                    <p class="state">state: <span id="state">%STATE%</span></p>
                    <p><button id="button" class="button">Toggle</button></p>
                  </div>
            </div>
        </div>
        <script src="script.js"></script>
    </body>
</html>

Javascript


var gateway = `ws://${window.location.hostname}/ws`;
var websocket;
// Init web socket when the page loads
window.addEventListener('load', onload);

function onload(event) {
    initWebSocket();
}

function getReadings(){
    websocket.send("getReadings");
}

function initWebSocket() {
    console.log('Trying to open a WebSocket connection…');
    websocket = new WebSocket(gateway);
    websocket.onopen = onOpen;
    websocket.onclose = onClose;
    websocket.onmessage = onMessage;
}

// When websocket is established, call the getReadings() function
function onOpen(event) {
    console.log('Connection opened');
    getReadings();
}

function onClose(event) {
    console.log('Connection closed');
    setTimeout(initWebSocket, 2000);
}

// Function that receives the message from the ESP32 with the readings
function onMessage(event) {
    console.log(event.data);
    var myObj = JSON.parse(event.data);
    var keys = Object.keys(myObj);

    for (var i = 0; i < keys.length; i++){
        var key = keys[i];
        document.getElementById(key).innerHTML = myObj[key];
    }

    var state;
    if (event.data == "1"){
      state = "ON";
    }
    else{
      state = "OFF";
    }
    document.getElementById('state').innerHTML = state;


}

function onLoad(event) {
    initWebSocket();
    initButton();
}
function initButton() {
  document.getElementById('button').addEventListener('click', toggle);
}
function toggle(){
  websocket.send('toggle');
}

Actually, I found this
ESP32 WebSocket Server with DHT11 Sensor (youtube.com)
Working fine for me. I have the DHT22 and 3 LEDs.

Not the same library but doing the same job. Well, I think. By the way, do you see any advantages to use AsyncWebServer or WebSocketsServer?

Maybe this could be of some help: http://jurca.dyn.ts.si/

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.