Uploading sensor data to web servers is one of the core ideas for Internet of Things (IoT). Such data are often small-sized and are continuously updated over time. And while HTTP performs satisfactorily for simple applications, like how I showed in my NodeMCU web server tutorial, there is a need for a much better method when speed and data-size are critical factors. I’ve already shown how to use MQTT as a faster and lightweight alternative to HTTP. In this tutorial, I will demonstrate how to use NodeMCU ESP8266 WebSocket.
Introduction to WebSocket
WebSocket, like HTTP, is a communications protocol over TCP. The key differences between WebSocket and HTTP is that the former operates full-duplex, bi-directional and at single TCP connection.
Full-duplex means two objects communicating with each other can send and receive messages simultaneously, like when you’re talking over the telephone. In contrast, half-duplex is non-simultaneous messaging, like when you’re using a walkie-talkie. A full-duplex system is faster than a half-duplex system.
As a consequence of being full-duplex, WebSocket is also bidirectional. The client always initiates the communication in HTTP. The client or the server can initiate the communication in WebSocket.
Finally, WebSocket is established in a single TCP connection. The request-response pattern needs to be repeated for every HTTP request by the client.
NodeMCU WebSocket Library
A WebSocket library for NodeMCU using the Arduino IDE can be downloaded in this repository.
Extract the library to the Arduino libraries folder and then restart the IDE (if it was open when you were downloading the library).
The library has plenty of examples (File -> Examples ->WebSockets). I will create my own code here that is similar to the one on the NodeMCU web server tutorial via HTTP:
#include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <WebSocketsServer.h> #include <Hash.h> // Replace with your network credentials const char* ssid = "<YOUR WIFI SSID>"; const char* password = "<YOUR WIFI PASSWORD>"; WebSocketsServer webSocket = WebSocketsServer(81); ESP8266WebServer server(80); //instantiate server at port 80 (http port) String page = ""; int LEDPin = 13; void setup(void){ //the HTML of the web page page = "<h1>Simple NodeMCU Web Server</h1><p><a href=\"LEDOn\"><button>ON</button></a> <a href=\"LEDOff\"><button>OFF</button></a></p>"; //make the LED pin output and initially turned off pinMode(LEDPin, OUTPUT); digitalWrite(LEDPin, LOW); delay(1000); Serial.begin(115200); WiFi.begin(ssid, password); //begin WiFi connection Serial.println(""); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); server.on("/", [](){ server.send(200, "text/html", page); }); server.on("/LEDOn", [](){ server.send(200, "text/html", page); digitalWrite(LEDPin, HIGH); delay(1000); }); server.on("/LEDOff", [](){ server.send(200, "text/html", page); digitalWrite(LEDPin, LOW); delay(1000); }); server.begin(); webSocket.begin(); webSocket.onEvent(webSocketEvent); Serial.println("Web server started!"); } void loop(void){ webSocket.loop(); server.handleClient(); if (Serial.available() > 0){ char c[] = {(char)Serial.read()}; webSocket.broadcastTXT(c, sizeof(c)); } } void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length){ if (type == WStype_TEXT){ for(int i = 0; i < length; i++) Serial.print((char) payload[i]); Serial.println(); } }
Upload the code to your NodeMCU and, if successful, open Arduino’s serial monitor to see something like this:
Then go to your preferred web browser and type in the address of the NodeMCU (shown in the screenshot above) on the address bar. You should see something like this:
To see what this code does, wire a LED to D7 (which is GPIO #13) on your NodeMCU.
Then click the buttons on the web page. The LED should respond to the button press:
Explaining the Code
There are a few differences here with my code using HTTP. First is the declaration of the WebSocket object:
WebSocketsServer webSocket = WebSocketsServer(81);
The WebSocket server must be on a different port to HTTP (which is 80). Here it’s on port 81. Then we need to start the WebSocket connection using begin()
webSocket.begin(); webSocket.onEvent(webSocketEvent);
The onEvent() function calls the webSocketEvent() function when data is received via WebSocket. The webSocketEvent():
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length){ if (type == WStype_TEXT){ for(int i = 0; i < length; i++) Serial.print((char) payload[i]); Serial.println(); } }
This function simply prints the data via WebSocket to the serial port. Here, we are waiting for a text type response but there are other types of responses:
WStype_ERROR, WStype_DISCONNECTED, WStype_CONNECTED, WStype_TEXT, WStype_BIN, WStype_FRAGMENT_TEXT_START, WStype_FRAGMENT_BIN_START, WStype_FRAGMENT, WStype_FRAGMENT_FIN,
We also need to add a webSocket.loop() call on the loop() function to keep the connection alive.
Another advantage of using WebSocket is that you can send or receive data on the server without refreshing the page, like in the NodeMCU Ajax tutorial but easier. I will discuss this on my future tutorials.
I suggest you explore all the given examples on the library to learn more. Also, feel free to drop a comment if you want a solution for a problem you are experiencing on a project related to this topic. Have fun!
Hi,
Thank you so much for this tutorial.
I’m working on a project where I sould read data from DHT22 and send it to a web server via websocket and the web server will store the data to a Database. I can’t seem to find any pattern so if you can help me I will appreciate it.
Thanks.
Amazing tutorials. I am looking to set it up and have a magnetic door switch so it can sense when the door/window closes/opens. I would like it to have its current status (live) in a web page and also send it to a server its status. I would like to ask if you guide me, please.
Turning the LED on and off works fine but how do I send data from the NodeMCU to the client?
For instance, I want to send a double integer that contains 24 bits of data data from a 24 bit ADC every few milliseconds continuously. Can it be done?
Or even more simply: send A0 analog pin data as fast as the converter in the ESP8266 can produce a new byte
Hi Roland!
Thank you for this tutorial. It works now, but at the beginnig I had problems because the code did not compile. I am using Windows 8.1, Arduino 1.6.8 with the websocket library you added as a link. The error was:
exit status 1
‘webSocketEvent’ was not declared in this scope
After some research I found out that I must add to the init part of the code
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght);
Thank you so much for your amazing tutorial.
As you wrote “Another advantage of using WebSocket is that you can send or receive data on the server without refreshing the page, like in the NodeMCU Ajax tutorial but easier. I will discuss this on my future tutorials”. Would you please send me or post a tutorial about how to send and display an A0 analog pin data on the webpage together with the above buttons: on and off by using the webSocket without refreshing manually the webpage.
Thanks a lot!
Hello ,
That’s exactly what I would like to do to control a relay remotely : my huge difficulty lies on phone side.. I want to write small app with AppInventor 2 , but I do not know how to set it up to make the initial connection and switch to Websocket afterwards ( maybe I need a specific component on AI2 ..) , and this possibly is because I do ignore the very basics of websockets.
Any suggestion or… should I give up ?
Thank you so much ,
Fabio R.
Hi,
I found an extension for websocket for the app inventor: https://community.appybuilder.com/t/websocket-client-extension/1761?u=taifun
I haven’t tested that but I hope it helps you with your problem
Hi ,
Thank you for your kindness , I’ll give it a try and will ( eventually ) post a feedback if everything goes well .
My best regards ,
Fabio R. – Italy
Hello, Roland ,
I just went on with websockets , and I must thank you again for your hint on ai2 extension …
Now , I am facing ( again! ) with a problem when I try to exchange TXT messages between esp8266 and my AI2 app through websockets : all goes ok when I send a pre-established message ( or command ) , but all goes wrong if I try to send ( and decode ) a free TXT msg (like a file name on an SDCard )…
Would Async mode be easier ?
Thanks again
Fabio R.
hello i want to see my sensor values from anywhere in the world. So how do i send data to global website. Please help