In this Project we will establish a Websocket connection between multiple ESP8266 and a local Node.JS server. The Node.JS server will be running on a PC, laptop or a on Raspberry Pi, while we use C/C++ code on the Arduino IDE for the ESP8266. Multiple clients (browser, ESP8266) can connect to this Node.Js Websocket server at the same time.
Each ESP8266 will read random ADC values and send these every 300 ms to the Node.Js server that will print them on the console and broadcast them to all other connected clients (similar to a group chat). The sender ESP8266 from which the particular ADC reading originates, will receive an edited message, which can be printed in a serial monitor.
About Websockets
The WebSocket protocol is an extension to the HTTP protocol, and allows to create real-time connections between web servers and a clients. Here, a client can be a web browser, smartphone app or, like in this project, an ESP8266.
While the HTTP protocol allows servers to send data only upon a client request, Websockets allow bi-directional communication between server and client. It enables web applications to efficiently exchange data in real-time without the overhead of conventional HTTP connections. Node.js is perfectly suited for writing WebSocket applications, and this tutorial explains how it all works.
The Overall Architecure
The websocket server is running on a laptop or a Raspberry Pi which is connected to a local network via a Wifi router. Also, the ESP8266 is connected to the same network via the Wifi router. It continously receives sensor data through its GPIO and sends it as a data stream to the Websocket server. By connecting to the Websocket server's IP address via browser, we are able to see a live stream of incoming sensor data sent from the ESP8266.
Similar to a chat server, our Websocket server will be a central server that will receive all massages, process them and send them to the other clients. In this example we have one single Websocket server, which the ESP8266 and our smartphone web browser is connected to.
The communication is bi-directional. So, the client not only receives messages. But rather we can also send a message from the client to the ESP8266, telling it to stop or start sending data, for example.

Image: Architecture for Websocket communication between ESP8266, NodeJs Server and a web browser running on a PC or smartphone
Note:
In a more advanced project there can be two Websockets servers (channels)- one for the front end communication between multiple clients (web browser, smartphone app) and server. And another Websocket server for the back end communication between multiple ESP8266's and the server.
By doing so, we could achieve a clean separation between, the micro-controller side and the web browser (client) side.
This could be useful when having many clients and sensors connected to the same server. With two separate channels, the Node.JS server application decides which commands are forwarded from the client channel to the ESP8266 channel and vice versa.
Materials Needed
For the sake of simplicity, this project is demonstrated in its most basic form in such that features and materials are kept at a minimum. Following materials are needed for this project:
- Raspberry Pi with Node.Js installed and Wifi capability
- NodeMCU ESP8266
- Wifi router
- Smartphone or PC with Web Browser and Wifi capability
Server-Side Code (Node.Js)
On the server-side (Raspberry Pi) install the latest version of Node of Node.Js (as of now: 10.8.0) with following command in the console.
$ curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt install -y nodejs
Continue with installing required components such as the Websocket package by following NPM commands.
npm install express
npm install body-parser
npm install --save ws
After that, copy and paste the code below into a text editor and save it as "websocket_example.js".
/**************************websocket_example.js*************************************************/ var bodyParser = require("body-parser"); const express = require('express'); //express framework to have a higher level of methods const app = express(); //assign app variable the express class/method var http = require('http'); var path = require("path"); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); const server = http.createServer(app);//create a server //***************this snippet gets the local ip of the node.js server. copy this ip to the client side code and add ':3000' ***** //****************exmpl. 192.168.56.1---> var sock =new WebSocket("ws://192.168.56.1:3000");************************************* require('dns').lookup(require('os').hostname(), function (err, add, fam) { console.log('addr: '+add); }) /**********************websocket setup**************************************************************************************/ //var expressWs = require('express-ws')(app,server); const WebSocket = require('ws'); const s = new WebSocket.Server({ server }); //when browser sends get request, send html file to browser // viewed at http://localhost:30000 app.get('/', function(req, res) { res.sendFile(path.join(__dirname + '/index.html')); }); //************************************************************************************************************************* //***************************ws chat server******************************************************************************** //app.ws('/echo', function(ws, req) { s.on('connection',function(ws,req){ /******* when server receives messsage from client trigger function with argument message *****/ ws.on('message',function(message){ console.log("Received: "+message); s.clients.forEach(function(client){ //broadcast incoming message to all clients (s.clients) if(client!=ws && client.readyState ){ //except to the same client (ws) that sent this message client.send("broadcast: " +message); } }); // ws.send("From Server only to sender: "+ message); //send to client where message is from }); ws.on('close', function(){ console.log("lost one client"); }); //ws.send("new client connected"); console.log("new client connected"); }); server.listen(3000);
 
&anbsp
ESP8266 Code
Include the Websocket library for the ESP8266 from here in your Arduino IDE. To do so, follow the link, click on "clone or download" -> download .ZIP-file. Then include the library in your Arduino IDE under: Sketch->Include Library->Add .ZIP library.
Now upload the code below to your ESP8266 device. Edit the "ssid" and "password" variable values according to your own router settings. Furthermore edit the "host" variable according to the ip address of your raspberry Pi in your wifi network.
Once the code is running, the Esp8266 will connect to your wifi router and try to establish a websocket connection to your Node.js server running on your Raspberry Pi. If connection can be established, the ESP8266 will send random ADC readings to the Websocket server in 300ms intervals. You can change the interval by changing the value for this variable in the code.
/*******************Esp8266_Websocket.ino****************************************/ #include <ESP8266WiFi.h> #include <WebSocketClient.h> boolean handshakeFailed=0; String data= ""; char path[] = "/"; //identifier of this device const char* ssid = "enter your wifi ssid here"; const char* password = "enter your wifi password here"; char* host = "192.168.0.23"; //replace this ip address with the ip address of your Node.Js server const int espport= 3000; WebSocketClient webSocketClient; unsigned long previousMillis = 0; unsigned long currentMillis; unsigned long interval=300; //interval for sending data to the websocket server in ms // Use WiFiClient class to create TCP connections WiFiClient client; void setup() { Serial.begin(115200); pinMode(readPin, INPUT); // Initialize the LED_BUILTIN pin as an output delay(10); // We start by connecting to a WiFi network Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); delay(1000); wsconnect(); // wifi_set_sleep_type(LIGHT_SLEEP_T); } void loop() { if (client.connected()) { currentMillis=millis(); webSocketClient.getData(data); if (data.length() > 0) { Serial.println(data); //*************send log data to server in certain interval************************************ //currentMillis=millis(); if (abs(currentMillis - previousMillis) >= interval) { previousMillis = currentMillis; data= (String) analogRead(A0); //read adc values, this will give random value, since no sensor is connected. //For this project we are pretending that these random values are sensor values webSocketClient.sendData(data);//send sensor data to websocket server } } else{ } delay(5); } } //********************************************************************************************************************* //***************function definitions********************************************************************************** void wsconnect(){ // Connect to the websocket server if (client.connect(host, espport)) { Serial.println("Connected"); } else { Serial.println("Connection failed."); delay(1000); if(handshakeFailed){ handshakeFailed=0; ESP.restart(); } handshakeFailed=1; } // Handshake with the server webSocketClient.path = path; webSocketClient.host = host; if (webSocketClient.handshake(client)) { Serial.println("Handshake successful"); } else { Serial.println("Handshake failed."); delay(4000); if(handshakeFailed){ handshakeFailed=0; ESP.restart(); } handshakeFailed=1; } }
Client-Side Code for Web Browser (HTML,CSS,Javascript)
Open your text editor and copy&paste the code below into your editor. Save the file as "index.html" and move it to the same folder that contains your Node.Js application on your Raspberry Pi. As soon as you run your node.js server code, it will output it's network ip in the console. Copy this ip and replace the websocket server address below.
Example: If IP address is 192.168.56.1, change the relevant line below to: var sock =new WebSocket("ws://192.168.56.1:3000");
index.html
<html lang="en"> <head> <meta charset="utf-8"/> <title>Websocket</title> </head> <body> <input style="width: 800px;height: 200px" type="text" placeholder="enter text here to send to server" id="eingabe" onkeypress="myFunction(event)"/> <button onclick="clearlog()">Clear Logs</button> <div style="overflow:scroll; width: 800px; height: 550px; border: solid; border-radius: 9px" id="display"></div> <script> //var sock =new WebSocket("ws://localhost:5001"); var sock =new WebSocket("ws://192.168.1.23:3000"); //replace this address with the one the node.js server prints out. keep port 3000 var display=document.getElementById("display") sock.onopen=function(event){ //alert("Socket connected succesfully!!!") setTimeout(function(){sock.send('connection succeeded');},1000); display.innerHTML+="connection succeeded <br />"; }; sock.onmessage=function(event){ console.log(event);//show received from server data in console of browser display.innerHTML+=event.data+"<br />"; //add incoming message from server to the log screen previous string + new string(message) } function myFunction(event) { //sock.send("Hello"); if(event.keyCode==13){ //when enter is pressed... var text=document.getElementById('eingabe').value; //assign value of the entered string to te text variable if(text!=""){ //if text is not an empty string //display.innerHTML+="From Client: "+text+"<br />"; //show the message from client in div sock.send(text); //send string to server display.innerHTML+="<strong>Me: </strong>" + text+"<br />"; //display input text in div (client side) document.getElementById('eingabe').value=""; //and clear the input field } else{ console.log("empty string not sent") } }} function clearlog(){ display.innerHTML=""; } </script> </body> </html>
Test the Setup
Now that the code for the ESP8266 is uploaded and the server-side code is ready, we can run the Node.Js server by navigating the console to the folder that contains the node.js application "websocket_example.js". We start it by entering following command in the console.
node websocket_example.js
You will see several status logs in the console. As soon as the ESP8266 is connected to a power source, it will try to establish a websocket connection with the node.js server and send its sensor data feed.
Now we can use our smartphone or PC browser and enter the ip address of the raspberry pi followed by the port number 3000 (e.g. 196.168.0.1:3000). The browser will load the .html file that we edited earlier. If everything is set up correctly, you will be able to see the sensor data feed from the ESP8266.
Wrap-Up
In this project we learned how to create a Websocket server that receives sensor data from an ESP8266 in real-time and forwards it to a Web browser (multiple connected Web browsers are also possible).
We used C-Code for the ESP8266, Javascript on the Node.js server-side code and HTML,CSS & Javascript for the client frontent. This is a very basic example to demonstrate the fundamentals of IOT. Further improvements and additional features of this project can be:
- Running the server on a public server or forwarding the local nodejs server to the world wide web, so that it can be accessed from outside
- SSL encryption
- Authentication with login name and password
- logging sensor data in a database and display data in charts to the front end user
- a dashboard from where user can send commands to the ESP8266 ( e.g. "Turn off lights")
- multiple Websocket channels to seperate client (front end) side from ESP8266 device side
- Webcam stream to the front end
- sleep modes of the ESP8266 to reduce power consumption
- multiple ESP8266 that can be addressed seperately
This list can be continued arbitrarily. However, adding functionalities will add complexity of the whole system, such that a well structured architecture and plan becomes necessary.
About the author
I just copy paste your code and change ssid passward as per your instrauction, but I am continuously getting these folling errors and I can’t find out how to solve it.
1 . ‘insigned’ does not name a type
2 . Esp8266_Websocket:22:17: error: no matching function for call to ‘WebSocketClient::WebSocketClient()’
WebSocketClient webSockClient;
Thanks in advance.
1.) Thanks for that hint. There was a typo in the code. We changed it from “insigned” to “unsigned”.
2.) Have you included the websocket library as explained in the article to the arduino IDE?
check it under following link: https://github.com/morrissinger/ESP8266-Websocket
That library contains all the functions necessary for the websocket communication
Hello,
It is still not working :(. I don’t use a Raspberry PI and I run the server on my laptop. I kept the port 3000. If I try to connect to the server by accessing http://localhost:3000/ from Chrome Browser, the chat web page is displayed. I can type a message and this is also shown (“Me:message”). However, the console window in which I run the *.js code shows nothing.
If I press “enter” without entering a text, the console window is not showing the message “empty string not sent”.
The Arduino code has still some bugs. For example:
unsigned int data= 0;
…..
webSocketClient.getData(data);
webSocketClient.sendData(data);
These two functions don’t work with unsigned int parameters:
bool getData(String& data, uint8_t *opcode = NULL);
void sendData(const char *str, uint8_t opcode = WS_OPCODE_TEXT);
void sendData(String str, uint8_t opcode = WS_OPCODE_TEXT);
Arduino will not compile until data is defined as String. I tried this:
data=String(analogRead(A0),DEC); //read adc values, this will give random value, since no sensor is connected. It compiles.
However, the ESP8266 client can’t connect and make a handshake with the server. It can only to connect to my WiFi Router Network (to which my laptop is also connected).
I have used the library from your link and the code from this page.
Could you please help me make this example to work?
It seems like you didn’t replace the ip address in your client-side .html code and esp8266 code with the correct ip address of your node.js websocket server.
To help you, I added a short snippet in the node.js code. So, when you run the node.js server, it will print the server ip address in the console. Copy this ip address and replace those in the esp8266 code (line 14, paste only ip address) and client-side html code (line 18, paste ip-address+port number). It should work then.
Hello,
Many thanks for your fast reply. Indeed I replaced the IP address with a wrong one. However, I managed to make it work until I read this.
There are still some typos in your ESP8266 code. You missed the void setup() closing bracket just before void loop().
The void loop() closing bracket is also missing before void wsconnect() definition.
With these changes, my ESP8266 can connect to the node.js server but it fails the handshake. I fixed this by changing:
char path[] = “”
to
char path[] = “/”
I found this “/” thing in this code:
https://github.com/morrissinger/ESP8266-Websocket/blob/master/examples/WebSocketClient_Demo/WebSocketClient_Demo.ino
Thank you again for sharing this example with us! It was really helpful!
Now I’m wondering if it is possible to have each sensor with its ESP8266 board and broadcast the data through the WiFi router (or through another ESP8266 connected to the WiFi router) to a webpage (or to the console).
You are welcome. Special thanks to you for pointing out the typos in my ESP8266 code. I edited it and removed obsolete lines.
To your question, you can have several ESP8266 with each having a sensor connected to the same websocket server. The most simple form would be something like a ‘group chat’: All devices are broadcasting and every client in that channel is able to read all messages. Also, each ESP8266 can be controlled (e.g. LED On/Off) with a special command that you define.
Furthermore, instead of displaying raw data from each device, you can plot the data using the canvasJS library. I will probably make a few more projects with Websockets and home automation.
Sorry for my bad english but i wonder how ”
multiple ESP8266 that can be addressed seperately”.
Thanks a lot! I manage to do all the task given in the procedure. Make me more understand about this architecture
I am getting constant updates on website and esp
Received: 8
Received: 8
Received: 8
it keeps sending each other 8 i don’t know why
Can someone help?
Can you do an example to control LED on/off with this esp8266 websocket client.
Hi, excellent post!
Node server running fine!
But I’ve some problems in the compile Arduino code process:
Error compiling for board OLIMEX ESP32-GATEWAY.
/Users/../Library/Arduino15/packages/esp32/hardware/esp32/1.0.4/tools/sdk/lib/libwpa_supplicant.a(md5-internal.o): In function `MD5Init’:
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/wpa_supplicant/src/crypto/md5-internal.c:93: multiple definition of `MD5Init’
libraries/ESP8266-Websocket/MD5.c.o:/Users/…../Documents/Arduino/libraries/ESP8266-Websocket/MD5.c:93: first defined here
/Users/…./Library/Arduino15/packages/esp32/hardware/esp32/1.0.4/tools/sdk/lib/libwpa_supplicant.a(md5-internal.o): In function `MD5Update’:
md5-internal.c:(.text.MD5Update+0x0): multiple definition of `MD5Update’
libraries/ESP8266-Websocket/MD5.c.o:MD5.c:(.text.MD5Update+0x0): first defined here
Multiple libraries were found for “WiFi.h”
Used: /Users/…/Library/Arduino15/packages/esp32/hardware/esp32/1.0.4/libraries/WiFi
Not used: /Applications/Arduino.app/Contents/Java/libraries/WiFi
Multiple libraries were found for “WebSocketClient.h”
Used: /Users/…../Documents/Arduino/libraries/ESP8266-Websocket
/Users/……/Library/Arduino15/packages/esp32/hardware/esp32/1.0.4/tools/sdk/lib/libwpa_supplicant.a(md5-internal.o): In function `MD5Final’:
md5-internal.c:(.text.MD5Final+0x0): multiple definition of `MD5Final’
libraries/ESP8266-Websocket/MD5.c.o:MD5.c:(.text.MD5Final+0x0): first defined here
collect2: error: ld returned 1 exit status
exit status 1
Error compiling for board OLIMEX ESP32-GATEWAY.
Do you know if this library works with board OLIMEX ESP32-GATEWAY?
Thanks
Hi, I have a little problem
In the wsconnect () function for some reason the client.connect returns a 0 and never makes the connection to my server, but it connects to my wifi cause it prints the assigned ip, could you help me?
Hey,
Thanks for the wonderful tutorial. I’m trying to work the exercise with a ESP-01 connecting to a Ubuntu server, connected to the same network. I tried to connect to the server with my laptop as a ws client. Works fine. But the ESP just doesn’t connect to the port. WiFi Connects 100/100 times. Not the port. I get a “Connection Failed. Handshake Failed.” and it restarts.
Any help would be greatly appreciated. Thanks!
This is what is happening:
12:04:47.550 -> Connecting to NETGEAR44
12:04:48.048 -> ……..
12:04:51.533 -> WiFi connected
12:04:51.533 -> IP address:
12:04:51.533 -> 192.168.1.11
12:04:53.525 -> Connection failed.
12:04:54.520 -> Handshake failed.
Can we send data using mqtt to nodejs server
Hi. Thanks for this tutorial. My problem is that when nodemcu wants to send data, the following error occurs
new client connected
events.js:292
throw er; // Unhandled ‘error’ event
^
RangeError: Invalid WebSocket frame: MASK must be set
at Receiver.getInfo (E:\My_code\IOT\node_modules\ws\lib\receiver.js:235:16)
at Receiver.startLoop (E:\My_code\IOT\node_modules\ws\lib\receiver.js:131:22)
at Receiver._write (E:\My_code\IOT\node_modules\ws\lib\receiver.js:78:10)
at writeOrBuffer (_stream_writable.js:352:12)
at Receiver.Writable.write (_stream_writable.js:303:10)
at Socket.socketOnData (E:\My_code\IOT\node_modules\ws\lib\websocket.js:872:35)
at Socket.emit (events.js:315:20)
at addChunk (_stream_readable.js:309:12)
at readableAddChunk (_stream_readable.js:284:9)
at Socket.Readable.push (_stream_readable.js:223:10)
Emitted ‘error’ event on WebSocket instance at:
at Receiver.receiverOnError (E:\My_code\IOT\node_modules\ws\lib\webs
at Receiver.emit (events.js:315:20)
at emitErrorNT (internal/streams/destroy.js:106:8)
at emitErrorCloseNT (internal/streams/destroy.js:74:3)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
[Symbol(status-code)]: 1002
}
E:\My_code\IOT>
hi
copied the same code, but this error
pleace help mi.
pleace help mi.
C:\Users\fn\Desktop\W\W.ino: In function ‘void loop()’:
W:48:33: error: no matching function for call to ‘WebSocketClient::getData(String&)’
webSocketClient.getData(data);
^
C:\Users\fn\Desktop\W\W.ino:48:33: note: candidate is:
In file included from C:\Users\fn\Desktop\W\W.ino:3:0:
C:\Users\fn\Documents\Arduino\libraries\arduino-websocket-client-master/WebSocketClient.h:88:12: note: String WebSocketClient::getData()
String getData();
^
C:\Users\fn\Documents\Arduino\libraries\arduino-websocket-client-master/WebSocketClient.h:88:12: note: candidate expects 0 arguments, 1 provided
Multiple libraries were found for “WebSocketClient.h”
Used: C:\Users\fn\Documents\Arduino\libraries\arduino-websocket-client-master
Not used: C:\Users\fn\Documents\Arduino\libraries\ESP8266-Websocket-master
Not used: C:\Users\fn\Documents\Arduino\libraries\ArduinoHttpClient
Not used: C:\Users\fn\Documents\Arduino\libraries\Arduino-Websocket-master
exit status 1
no matching function for call to ‘WebSocketClient::getData(String&)’