ESP32 WebSocket Server: Find out how to Easily Make one Work and Create a WebSocket Server with this Complete Tutorial. Find out Exactly
How to get Instant, Fully Bi-Directional Communications Running
Easily.
ESP32 WebSocket Server: You're probably here because you tried to get your ESP32 to control
some relays and return a temperature reading to the browser. The problem
is that you have to refresh the page every time you want to see new
readings.
Uses Modern Web Technology not the older AJAX technology.
Use it for instantaneous bi-directional communications - no poll or refresh.
They have minimal overhead for data transfer i.e. they are efficient.
Designed for low latency i.e. they are designed to be fast.
Simultaneous update all attached Clients(browsers) are updated togther.
When you initially start using IOT control, you setup the ESP32 as a webserver
the problem is that a webserver only serves a page on request from the
browser (using the HTTP_GET command). So every time you want an update from the ESP32 you
have to click the browser reload button!
You can solve this problem using the newer WebSocket technology - there's an introduction in this link. Simply put a WebSocket allows you to establish bi-directional communication without refreshing the browser page.
Note: Websockets provide true bi-directional comms. without high overhead.
Note: Websockets are more difficult to use than just HTML.
This is exactly what you want for getting readings back from an ESP32.
You can also use WebSockets to go the other way and control LEDs or
relays on the ESP32.
The Webserver
You need a web server as this code reacts to browser requests and
responds by returning a web page i.e. it serves up web page to the
client (The ESP32 is the server).
The first thing you need to do is setup a webserver using an Arduino Library - in this case:
ESPAsyncWebServer Library
You use the asynchronous webserver
library because it is interrupt and event driven giving you better
performance. In the previous link you can find a discussion and comparison
of synchronous and asynchronous web servers.
Web Server example
First of all you need to serve HTML pages to the client (browser)
from the server (ESP32) using a standard library, in this case, the
ESPAsyncWebServer library. Program this example sketch into your ESP32:
Enter your router information into the code (password and ssid). Then
observe the IP address shown in the serial monitor of the Arduino IDE.
Type that IP address into the browser URL box.
For this example, when the browser requests a page from the ESP32 the following html text is returned...
<html><body><h1>Hello, world!</h1></body></html>
... so the text...
'Hello, world!'
...will be displayed in the browser window.
ESP32 Serves pages
So now the ESP32 can serve a page when it gets an HTTP_GET request from the browser.
The ESP32 code :
server.on("/",HTTP_GET,handleroot);
...starts the server, and when it receives an HTTP_GET for URL "/"
(or index) from the client, it then calls the handleroot function:
... which sends a the text/html item containing the HTML string
enclosed in quotes. The number 200 is an error number that in this case
says everything is fine.
Data From Client (Browser) to Server (ESP32)
Here is the very uninteresting Browser page. It is intentionally
uninteresting as it shows the fundamentals and does not include fancy
CSS styling - that makes the code longer.
Set up websockets on the Server (ESP32)
This allows the client (browser) to send data to the server (ESP32).
To enable websockets you can use the websocket code already inside
the ESPAsyncWebServer library; with the following code in addition to the
original asynchronous server:
This code starts monitoring for the websocket communication and calls
handleWebSocketEvent when an event triggers the webscocket.
In the handleWebSocketEvent function that you write you can react to websocket events such as:
WS_EVT_DISCONNECT WS_EVT_CONNECT WS_EVT_DATA
So your code, in the ESP, can react to received websocket events that
indicate either a new connection, a dis-connection or data reception.
Setup websockets on the client side
The next step is to create the html code that will send data to the
server (ESP32). So lets create a button in the browser, that toggles the
built in LED on an ESP32.
For this you need some JavaScript which is used to create the websocket functionality:
In this case we'll just create a button that sends a toggle command to the ESP32.
For this operation the following HTML and JavaScript is required:
<!DOCTYPEhtml>
<html>
<head>
</head>
<body>
<h1>ESP32 Websocket Example - Client to Server</h1>
<buttononclick='toggleLED()'>Toggle LED</button>
<brclear="all">
<script>
var webSocket;
connectWebSocket();
function connectWebSocket() {
webSocket = new WebSocket('ws://' + window.location.hostname + '/ws');
webSocket.onopen = function(event) {
console.log('WebSocket connected');
};
webSocket.onerror = function(event) {
console.error('WebSocket error:', event);
};
}
function toggleLED() {
webSocket.send('toggle');
}
</script>
</body>
</html>
Here the toggleLED() function sends the data string 'toggle' over the
connected websocket when the button, labelled 'Toggle LED', in the HTML
page is pressed.
In the ESP32 code, the handleWebSocketEvent() function will detect the WS_EVT_DATA event updating the LED state.
The following ESP32 code will update ring 'toggthe LED on receipt of a data payload from the webSocket matching the stle'.
voidhandleWebSocketEvent(AsyncWebSocket*server,AsyncWebSocketClient*client,AwsEventTypetype,void*arg,uint8_t*data,size_tlen){
switch(type){
caseWS_EVT_DISCONNECT:
Serial.printf("[u] Disconnected!\n",client->id());
break;
caseWS_EVT_CONNECT:
{
IPAddressip=client->remoteIP();
Serial.printf("[u] Connected from %d.%d.%d.%d",client->id(),ip[0],ip[1],ip[2],ip[3]);
}
break;
caseWS_EVT_DATA:
{
AwsFrameInfo*info=(AwsFrameInfo*)arg;
if(info->final&&info->index==0&&info->len==len&&info->opcode==WS_TEXT){
data[len]='\0';
Stringpayload=String((char*)data);
Serial.printf("[u] Received: %s\n",client->id(),payload.c_str());
if(payload=="toggle"){
ledState=!ledState;
// digitalWrite(LED_PIN, ledState);
digitalWrite(LED_PIN,!ledState);// For AI thinker LED control is inverted (pin33)
}
}
}
break;
}
}
Example 1 code Download
You can download the first example code here - change the file extension to .ino and label the whole lot as :
websockets_CtoS_toggle_led.ino
Save the file in a directory labelled
websockets_simple_CLI_TO_SER_button_toggle_led the same a any other
Arduino code. Don't forget to enter your own SSID and router password. Program your ESP32 - an example of programming for the AI thinker board is shown here, for different boards just select your board from the drop down list..
As usual copy the IP address shown in the monitor and paste that into your browser address bar.
This is a no-frills program so observe the serial monitor output to get
the status of the link. You should see something along these lines:
Connecting to WiFi...
Connecting to WiFi...
Connecting to WiFi...
Connected to WiFi
IP Address: 192.168.0.62
Client to Server WebSockets with ESPAsyncWebServer.h
[1] Connected from 192.168.0.51
[1] Received: toggle
[1] Received: toggle
[1] Received: toggle
[1] Received: toggle
The ESP32 connects to the WiFi and returns its IP address. When you type
the IP address into the address bar you get the message similar to:
[1] Connected from 192.168.0.51
... and when you hit the button on the web page the websocket sends data from the browser to the ESP32 to control the LED:
[1] Received: toggle
ESP32 WebSocket Server: Multiple WebSockets
The concept of having multiple open websockets gives a very different
slant to how you control an ESP32 compared to just using GET and POST protocols
with traditional HTML (really just point to point control). If you alter data from one Client connection through a websocket,
all the other client connections should get updated.
Warning: You can have more than one active WebSocket!
You see that '[1]' in the above serial output - that indicates that
websocket 1 is active. Open another browser page (even open a different
browser), type in the same IP address (the 1st one). Then the serial
output will be something like:
[2] Connected from 192.168.0.51
[2] Received: toggle
[2] Received: toggle
The '[1]' has become a '[2]' showing that the second websocket is now
active and a toggle signal was received from websocket 2. You can toggle
the LED from any browser window that has a connected websocket.
For this simple code controlling the LED on the ESP32 from either instance does work. But consider this:
What if you reported the state of the LED in the HTML page?
Toggling the LED in one browser window would update that window, but not
the other one. In fact when your ESP32 code toggles the LED it should also
output a broadcast websocket message to all websockets. The broadcast message says "this
is the new value of the LED".
In this way all browser pages can be kept
in step.
Note: WebSockets are designed for multiple instances - you have to code for that.
ESP32 WebSocket Server: Multi Broadcast LED status
Lets update the code to show the state of the LED in each browser instance.
Here's the screen shot of the browser:
There are two problems:
On websocket connection, the browser does not know the current LED state.
Other instances of the websocket (in different browser pages) need LED state updates.
So how do you code this action?
LED status
HTML to show websocket LED status
First lets add an LED status message to the current HTML code:
<p>LED Status: <span id='ledStatus'></span></p>
This gives a place holder for the LED status message that will be
updated by the javascript on receipt of a websocket LED status message.
Javascript to show websocket LED status
Now add in the Javascript that reacts to a websocket message:
When the Browser/Javascript recives a properly formatted JSON string
it will display the received message data value in the element that has id='ledStatus'.
In this case the messages are either LED ON, and LED OFF
{
"label": "ledStatus",
"value": "LED ON"
}
Alternatively for OFF we have:
{
"label": "ledStatus",
"value": "LED OFF"
}
It may seem like a lot of trouble to use JSON formatted strings, but
when there is lots of data you can access the information in a scalable
way.
ESP32 code to broadcast LED status
in the handleWebSocket code we had for the WS_EVT_DATA case statement:
caseWS_EVT_DATA:
{
...
if(payload=="toggle"){
ledState=!ledState;
// digitalWrite(LED_PIN, ledState);
digitalWrite(LED_PIN,!ledState);// For AI thinker LED control is inverted (pin33)
}
}
Now all you do is add in code that generates a JSON formatted string
(in one line), that depends on the ledState variable and broadcast that
to all sockets:
caseWS_EVT_DATA:
{
...
if(payload=="toggle"){
ledState=!ledState;
// digitalWrite(LED_PIN, ledState);
digitalWrite(LED_PIN,!ledState);// For AI thinker LED control is inverted (pin33)
StringledUpdate="{\"label\":\"ledStatus\",\"value\":\""+String(ledState?"LED ON":"LED OFF")+"\"}";
webSocket.textAll(ledUpdate);
}
}
Here the JSON string value is changed depending on the ledState to
either "LED ON" or "LED OFF" and is then sent as a broadcast message to
all connected websockets.
So, whenever the server (ESP32) receives a websocket 'toggle' (LED)
message, as a data event, the ESP32 will broadcast the value to all
connected websockets.
ESP32 WebSocket Server: A few Extras
Initialise Browser on websocket connect
The LED status information (sent to the browser) is not automatically
updated on a websocket browser connect event so you have to code it
into the ESP32 code. This is separate to the when the clicking the
button.
Just to complete this part, set up the initialisation of the LED
state using the WS_EVT_CNCT, again in the handleWebSocket function:
caseWS_EVT_CONNECT:
{
IPAddressip=client->remoteIP();
Serial.printf("[u] Connected from %d.%d.%d.%d\n",client->id(),ip[0],ip[1],ip[2],ip[3]);
}
break;
Adding in the initialisation code:
caseWS_EVT_CONNECT:
{
IPAddressip=client->remoteIP();
Serial.printf("[u] Connected from %d.%d.%d.%d\n",client->id(),ip[0],ip[1],ip[2],ip[3]);
// Initialise the browser entry box with the current LED state.
// Create a JSON message containing the LED status
StringledStatusUpdate="{\"label\":\"ledStatus\",\"value\":\""+String(ledState?"LED ON":"LED OFF")+"\"}";
// Send the LED status to the client
client->text(ledStatusUpdate);
}
The only difference between this code and the previous is that the
specific newly connected websocket is updated (it's not a broadcast
command).
Reconnect when connection lost
Another useful thing to add to the Javascript code is an automatic
re-connection operation so that if the WiFi is lost for some reason the
code will try and re-connect the websocket. It means you don't have to
refresh the browser, it's all automatic.
You can do this by adding the following code:
webSocket.onclose = function(event) {
console.log('WebSocket disconnected');
var messageElement = document.getElementById('message');
Also, add into the body html, an 'id' for the status message.
<p><span id='message'></span></p>
Example 2 code Download
You can download the second example code here - change the file extension to .ino and label the whole lot as :
websockets_CtoS_toggle_led_stat_upd.ino
Test Example 2
To test out this functionality, use your mobile as a hotspot (or
another ESP32), get the new IP address (it will be different). Reprogram
the ESP32 with your hotspot name and password.
Set your PC to use the hotspot. Use the IP address in the browser. Turn
off the hotspot. Turn it on again, and you'll see the re-connection
message as coded above.
ESP32 WebSocket Server: Test LED Status Update
To test the code open two browser pages and type in the original IP
address into both. When you click the toggle LED button in one, the
message will be updated in both.
Click one toggle button to turn on the LED. Close the second browser
page. Open a new browser page as before, observe the LED status message -
it should be LED ON - indicating that the initialisation code is
operating correctly.
Data From Server (ESP32) to Client (Browser)
This allows the server (ESP32) to send data to the client (browser).
In this example, we'll send an update every second and every second, a
count value will be increased and transmitted through a websocket.
This page shows you exactly how to implement an Ardino WebSocket
Server, showing you the programming methods to allow bi-directional
communication.
First a Webserver is example presented, followed by a Client to
Server (ESP32) example. This is expanded from a simple HTML button to
more complex status update, which also explains the need for multi-socket
broadcast operations. The final example completes the communication
path by adding data from Server to Client (Browser).
For the Client to Server (ESP32) programming you need some Javascript
and HTML While for the Server to Client (Browser) you need an Arduino
WebSocket library.
Written by John Main who has a degree in Electronic Engineering.
Note: Parts of this page were written using chatgpt
as a research assistant.
Unlock the secrets of Arduino scrolling displays! This beginner-friendly guide shows you how to create real-time, dynamic graphics using an SSD1306 OLED, perfect for tracking sensor data and building…
How to get accurate DHT22 digital humidity sensor readings with an Arduino. Did you know it also measures temperature as Well? Find out why, in this page...
A PIR sensor lets your Arduino sense movement without contact. This tutorial covers PIR sensor basics, connecting one to an Arduino board and coding a motion detector.
Arduino Hall Effect Sensor: Add magnetic sensing superpowers to your Arduino projects with an easy-to-use hall effect sensor. With full code and layout...
Comments
Have your say about what you just read! Leave me a comment in the box below.
Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.