{"id":130826,"date":"2023-07-20T13:20:39","date_gmt":"2023-07-20T13:20:39","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=130826"},"modified":"2025-03-17T11:04:48","modified_gmt":"2025-03-17T11:04:48","slug":"esp8266-nodemcu-websocket-server-sensor","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-websocket-server-sensor\/","title":{"rendered":"ESP8266 NodeMCU WebSocket Server: Display Sensor Readings"},"content":{"rendered":"\n<p>In this guide, you&#8217;ll learn how to create a WebSocket server with the ESP8266 NodeMCU board to display sensor readings on a web page. Whenever the ESP8266 has new readings available, the web page is updated automatically without the need to manually refresh it.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP8266-Websocket-Server-Sensor-Readings.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU WebSocket Server Display Sensor Readings Arduino IDE\" class=\"wp-image-130827\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP8266-Websocket-Server-Sensor-Readings.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP8266-Websocket-Server-Sensor-Readings.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP8266-Websocket-Server-Sensor-Readings.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP8266-Websocket-Server-Sensor-Readings.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclblue\">To learn more about building web servers with the ESP32 and ESP8266 from scratch, check our eBook:<a href=\"https:\/\/randomnerdtutorials.com\/build-web-servers-esp32-esp8266-ebook\/\" title=\"\"> Build Web Servers with the ESP32 and ESP8266<\/a>.<\/p>\n\n\n\n<p><strong>Table of Contents<\/strong><\/p>\n\n\n\n<p>Throughout this tutorial, we&#8217;ll cover the following main topics:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"#intro-websocket\" title=\"\">Introducing WebSocket Protocol<\/a><\/li>\n\n\n\n<li><a href=\"#prerequisites\" title=\"\">Install Required Libraries and Plugins<\/a><\/li>\n\n\n\n<li><a href=\"#web-server\" title=\"\">Building the Web Server Project: Display Sensor Readings<\/a>\n<ul class=\"wp-block-list\">\n<li><a href=\"#html-file\" title=\"\">Creating the HTML File<\/a><\/li>\n\n\n\n<li><a href=\"#css-file\" title=\"\">Creating the CSS File<\/a><\/li>\n\n\n\n<li><a href=\"#javascript-file\" title=\"Creating the JavaScript File\">Creating the JavaScript File<\/a><\/li>\n\n\n\n<li><a href=\"#esp8266-sketch\" title=\"\">Programming the ESP32 Board (Websocket server)<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p class=\"rntbox rntclgreen\">We have a similar tutorial for the ESP32 board: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-websocket-server-sensor\/\" title=\"\">ESP32 WebSocket Server: Display Sensor Readings<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"intro-websocket\">Introducing WebSocket Protocol<\/h2>\n\n\n\n<p>A WebSocket is a persistent connection between a client and a server that allows bidirectional communication between both parties using a TCP connection. This means you can send data from the client to the server and from the server to the client at any given time.&nbsp;<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"727\" height=\"785\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP3-ESP82662-WebSocket-Server-How-it-Works-f.png?resize=727%2C785&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 WebSocket Server How it Works\" class=\"wp-image-99447\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP3-ESP82662-WebSocket-Server-How-it-Works-f.png?w=727&amp;quality=100&amp;strip=all&amp;ssl=1 727w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP3-ESP82662-WebSocket-Server-How-it-Works-f.png?resize=278%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 278w\" sizes=\"(max-width: 727px) 100vw, 727px\" \/><\/figure><\/div>\n\n\n<p>The client establishes a WebSocket connection with the server through a process known as <em>WebSocket handshake<\/em>. The handshake starts with an HTTP request\/response, allowing servers to handle HTTP connections as well as WebSocket connections on the same port. Once the connection is established, the client and the server can send WebSocket data in full duplex mode.<\/p>\n\n\n\n<p>Using the WebSockets protocol, the server (ESP8266 board) can send information to the client or to all clients without being requested. This also allows us to send information to the web browser when a change occurs.<\/p>\n\n\n\n<p>This change can be something that happened on the web page (you clicked a button) or something that happened on the ESP8266 side like pressing a physical button on a circuit, or new sensor readings available.<\/p>\n\n\n\n<p class=\"rntbox rntclblue\">Learn how to control the ESP8266 outputs via WebSocket protocol: <a href=\"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-async-web-server-espasyncwebserver-library\/\" title=\"\">ESP8266 WebSocket Server: Control Outputs (Arduino IDE)<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Project Overview<\/h2>\n\n\n\n<p>Here&#8217;s the web page we&#8217;ll build for this project.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"787\" height=\"419\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP-Websocket-Server-Display-Sensor-Readings-Web-Browser-ESP32.png?resize=787%2C419&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 Websocket Server Sensor Readings\" class=\"wp-image-130719\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP-Websocket-Server-Display-Sensor-Readings-Web-Browser-ESP32.png?w=787&amp;quality=100&amp;strip=all&amp;ssl=1 787w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP-Websocket-Server-Display-Sensor-Readings-Web-Browser-ESP32.png?resize=300%2C160&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP-Websocket-Server-Display-Sensor-Readings-Web-Browser-ESP32.png?resize=768%2C409&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 787px) 100vw, 787px\" \/><\/figure><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>We&#8217;ll create a web page that displays temperature, humidity, and pressure.<\/li>\n\n\n\n<li>The web page displays the latest sensor readings when you open or refresh the web page.<\/li>\n\n\n\n<li>The sensor readings update automatically whenever there&#8217;s a new reading available on the ESP8266 without the need to refresh the webpage.<\/li>\n\n\n\n<li>The web server works perfectly on multiple clients (multiple web browser tabs on the same device or different devices).<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">How does it work?<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The ESP hosts a web server that displays a web page with three cards for the sensor readings.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>When you open the webpage, it sends a message (<span class=\"rnthl rntliteral\">getReadings<\/span>) to the ESP via WebSocket protocol. The server (ESP) receives that message. When that happens, it gets new readings from the sensors and sends them back to the client (web browser), also via web socket protocol. This way, whenever you open a new tab, it always shows the current and updated values.<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"286\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works-1.png?resize=1024%2C286&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 Websocket server how it works\" class=\"wp-image-130830\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works-1.png?resize=1024%2C286&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works-1.png?resize=300%2C84&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works-1.png?resize=768%2C214&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works-1.png?resize=1536%2C428&amp;quality=100&amp;strip=all&amp;ssl=1 1536w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works-1.png?resize=2048%2C571&amp;quality=100&amp;strip=all&amp;ssl=1 2048w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works-1.png?w=2400&amp;quality=100&amp;strip=all&amp;ssl=1 2400w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>Every 30 seconds, the ESP gets new readings and sends them to all connected clients (all web browser tabs opened) via WebSocket protocol. The client receives that message and displays the readings on the web page.<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"286\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works.png?resize=1024%2C286&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 Websocket server\" class=\"wp-image-130831\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works.png?resize=1024%2C286&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works.png?resize=300%2C84&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works.png?resize=768%2C214&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works.png?resize=1536%2C428&amp;quality=100&amp;strip=all&amp;ssl=1 1536w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works.png?resize=2048%2C571&amp;quality=100&amp;strip=all&amp;ssl=1 2048w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP8266-sensor-readings-how-it-works.png?w=2400&amp;quality=100&amp;strip=all&amp;ssl=1 2400w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"prerequisites\">Prerequisites<\/h2>\n\n\n\n<p>Before proceeding with this tutorial, make sure you check all the following prerequisites.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1) Parts Required<\/h3>\n\n\n\n<p>To follow this project you need:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/esp8266-esp-12e-nodemcu-wi-fi-development-board\/\" target=\"_blank\" rel=\"noopener\" title=\"\">ESP8266 Board<\/a> &#8211; read<a href=\"https:\/\/makeradvisor.com\/best-esp8266-wi-fi-development-board\/\" target=\"_blank\" rel=\"noopener\" title=\"\"> ESP8266 Boards Review and Comparison<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/bme280-sensor-module\/\" target=\"_blank\" rel=\"noreferrer noopener\">BME280 sensor module<\/a> &#8211; check the <a href=\"https:\/\/randomnerdtutorials.com\/esp32-bme280-arduino-ide-pressure-temperature-humidity\/\" title=\"\">BME280 getting started guide with the ESP32<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noreferrer noopener\">Breadboard<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noreferrer noopener\">Jumper wires<\/a><\/li>\n<\/ul>\n\n\n\n<p>For this example, we&#8217;ll use a BME280 sensor, but you can use any other sensor you&#8217;re familiar with.<\/p>\n\n\n<p>You can use the preceding links or go directly to <a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\">MakerAdvisor.com\/tools<\/a> to find all the parts for your projects at the best price!<\/p><p style=\"text-align:center;\"><a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2017\/10\/header-200.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\"><\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2) Arduino IDE and ESP8266 Boards Add-on<\/h3>\n\n\n\n<p>We\u2019ll program the ESP8266 using Arduino IDE. So, you must have the ESP8266 add-on installed. Follow the next tutorial if you haven\u2019t already:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-esp8266-nodemcu-arduino-ide-2-0\/\" title=\"\">Installing ESP8266 Board in Arduino IDE (Windows, Mac OS X, Linux)<\/a><\/li>\n<\/ul>\n\n\n\n<p>If you want to use VS Code with the PlatformIO extension, follow the next tutorial instead to learn how to program the ESP8266:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/vs-code-platformio-ide-esp32-esp8266-arduino\/\">Getting Started with VS Code and PlatformIO IDE for ESP32 and ESP8266 (Windows, Mac OS X, Linux Ubuntu)<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">3) Filesystem Uploader Plugin<\/h3>\n\n\n\n<p>To upload the HTML, CSS, and JavaScript files needed to build this project to the ESP8266 flash memory (LittleFS), we\u2019ll use a plugin for Arduino IDE:&nbsp;<strong>LittleFS Filesystem uploader<\/strong>. Follow the next tutorial to install the filesystem uploader plugin if you haven&#8217;t already:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/arduino-ide-2-install-esp8266-littlefs\/\" title=\"\">Install ESP8266 NodeMCU LittleFS Filesystem Uploader in Arduino IDE<\/a><\/li>\n<\/ul>\n\n\n\n<p>If you\u2019re using VS Code with the PlatformIO extension, read the following tutorial to learn how to upload files to the filesystem:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-vs-code-platformio-littlefs\/\">ESP8266 NodeMCU with VS Code and PlatformIO: Upload Files to Filesystem (LittleFS)<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4) Libraries<\/h3>\n\n\n\n<p>To build this project, you need to install the following libraries:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a style=\"font-size: inherit;\" href=\"https:\/\/github.com\/arduino-libraries\/Arduino_JSON\" target=\"_blank\" rel=\"noreferrer noopener\">Arduino_JSON library by Arduino<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/adafruit\/Adafruit_BME280_Library\" target=\"_blank\" rel=\"noopener\" title=\"\">Adafruit_BME280<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncWebServer\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncWebServer by ESP32Async<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncTCP\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncTCP\u00a0by ESP32Async<\/a><\/li>\n<\/ul>\n\n\n\n<p>You can install these libraries using the Arduino Library Manager. Go to&nbsp;<strong>Sketch&nbsp;<\/strong>&gt;&nbsp;<strong>Include Library<\/strong>&nbsp;&gt;&nbsp;<strong>Manage Libraries<\/strong>&nbsp;and search for the libraries&#8217; names.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Building the Circuit<\/h2>\n\n\n\n<p>To exemplify how to display sensor readings on a web server with the ESP8266, we&#8217;ll send sensor readings from a BME280 sensor to the browser. So, you need to wire a BME280 sensor to your ESP8266. You can also use any other sensor you&#8217;re familiar with.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic Diagram<\/h3>\n\n\n\n<p>We\u2019re going to use I2C communication with the BME280 sensor module. For that, wire the sensor to the default ESP8266&nbsp;SCL (<span class=\"rnthl rntcblue\">GPIO 5<\/span>)&nbsp;and&nbsp;SDA (<span class=\"rnthl rntcgreen\">GPIO 4<\/span>)&nbsp;pins, as shown in the following schematic diagram.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"675\" height=\"531\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/07\/ESP8266-NodeMCU-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit.png?resize=675%2C531&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU BME280 Sensor Temperature Humidity Pressure Wiring Diagram Circuit\" class=\"wp-image-98049\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/07\/ESP8266-NodeMCU-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit.png?w=675&amp;quality=100&amp;strip=all&amp;ssl=1 675w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/07\/ESP8266-NodeMCU-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit.png?resize=300%2C236&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 675px) 100vw, 675px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclblue\">Recommended reading: <a href=\"https:\/\/randomnerdtutorials.com\/esp8266-pinout-reference-gpios\/\" title=\"\">ESP8266 Pinout Reference: Which GPIO pins should you use?<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"web-server\">Organizing Your Files<\/h2>\n\n\n\n<p>To keep the project organized and make it easier to understand, we\u2019ll create four files to build the web server:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Arduino sketch: to get the sensor readings and handle the web server;<\/li>\n\n\n\n<li>index.html: to define the content of the web page to display the sensor readings;<\/li>\n\n\n\n<li>style.css: to style the web page;<\/li>\n\n\n\n<li>script.js: to program the behavior of the web page\u2014handle what happens when you open the web page and display the readings received via WebSocket protocol.<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"601\" height=\"358\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/05\/ESP8266-Organizing-Folders_organizing-files.png?resize=601%2C358&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 organizing your Files arduino sketch index html style css script js\" class=\"wp-image-104233\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/05\/ESP8266-Organizing-Folders_organizing-files.png?w=601&amp;quality=100&amp;strip=all&amp;ssl=1 601w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/05\/ESP8266-Organizing-Folders_organizing-files.png?resize=300%2C179&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 601px) 100vw, 601px\" \/><\/figure><\/div>\n\n\n<p>You should save the HTML, CSS, and JavaScript files inside a folder called&nbsp;<em><strong>data<\/strong>&nbsp;<\/em>inside the Arduino sketch folder, as shown in the previous diagram. We\u2019ll upload these files to the ESP8266 filesystem (LittleFS).<\/p>\n\n\n\n<p><strong>You can download all project files:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><a href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP8266\/ESP8266_Sensor_Readings_WebSocket\/ESP8266_Sensor_Readings_WebSocket.zip\" target=\"_blank\" rel=\"noopener\" title=\"\">Download all the project files<\/a><\/strong><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"html-file\">HTML File<\/h2>\n\n\n\n<p>Copy the following to the <span class=\"rnthl rntliteral\">index.html<\/span> file.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-html\">&lt;!DOCTYPE html&gt;\r\n&lt;html&gt;\r\n    &lt;head&gt;\r\n        &lt;title&gt;ESP IOT DASHBOARD&lt;\/title&gt;\r\n        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\r\n        &lt;link rel=&quot;icon&quot; type=&quot;image\/png&quot; href=&quot;favicon.png&quot;&gt;\r\n        &lt;link rel=&quot;stylesheet&quot; type=&quot;text\/css&quot; href=&quot;style.css&quot;&gt;\r\n    &lt;\/head&gt;\r\n    &lt;body&gt;\r\n        &lt;div class=&quot;topnav&quot;&gt;\r\n            &lt;h1&gt;SENSOR READINGS (WEBSOCKET)&lt;\/h1&gt;\r\n        &lt;\/div&gt;\r\n        &lt;div class=&quot;content&quot;&gt;\r\n            &lt;div class=&quot;card-grid&quot;&gt;\r\n                &lt;div class=&quot;card&quot;&gt;\r\n                    &lt;p class=&quot;card-title&quot;&gt; Temperature&lt;\/p&gt;\r\n                    &lt;p class=&quot;reading&quot;&gt;&lt;span id=&quot;temperature&quot;&gt;&lt;\/span&gt; &amp;deg;C&lt;\/p&gt;\r\n                &lt;\/div&gt;\r\n                &lt;div class=&quot;card&quot;&gt;\r\n                    &lt;p class=&quot;card-title&quot;&gt; Humidity&lt;\/p&gt;\r\n                    &lt;p class=&quot;reading&quot;&gt;&lt;span id=&quot;humidity&quot;&gt;&lt;\/span&gt; &amp;percnt;&lt;\/p&gt;\r\n                &lt;\/div&gt;\r\n                &lt;div class=&quot;card&quot;&gt;\r\n                    &lt;p class=&quot;card-title&quot;&gt; Pressure&lt;\/p&gt;\r\n                    &lt;p class=&quot;reading&quot;&gt;&lt;span id=&quot;pressure&quot;&gt;&lt;\/span&gt; hpa&lt;\/p&gt;\r\n                &lt;\/div&gt;\r\n            &lt;\/div&gt;\r\n        &lt;\/div&gt;\r\n        &lt;script src=&quot;script.js&quot;&gt;&lt;\/script&gt;\r\n    &lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP8266\/ESP8266_Sensor_Readings_WebSocket\/data\/index.html\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>We won&#8217;t go into much detail about the content of the HTML file. Just the relevant parts.<\/p>\n\n\n\n<p>The following lines display a card for the temperature.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;div class=\"card\"&gt;\n    &lt;p class=\"card-title\"&gt;&lt;i class=\"fas fa-thermometer-threequarters\" style=\"color:#059e8a;\"&gt;&lt;\/i&gt; Temperature&lt;\/p&gt;\n    &lt;p class=\"reading\"&gt;&lt;span id=\"temperature\"&gt;&lt;\/span&gt; &amp;deg;C&lt;\/p&gt;\n&lt;\/div&gt;<\/code><\/pre>\n\n\n\n<p>The temperature will show up in the following paragraph between the <span class=\"rnthl rntliteral\">&lt;span&gt;<\/span> tags. Notice that you need a unique id for that HTML tag so that later we know how to refer to this HTML element. In this case, the unique id is <span class=\"rnthl rntliteral\">temperature<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;span id=\"<strong>temperature<\/strong>\"&gt;&lt;\/span&gt;<\/code><\/pre>\n\n\n\n<p>We do a similar procedure for the humidity and pressure. The unique ids for the HTML element where we&#8217;ll display the humidity and pressure are <span class=\"rnthl rntliteral\">humidity<\/span> and <span class=\"rnthl rntliteral\">pressure<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;div class=\"card\"&gt;\n      &lt;p class=\"card-title\"&gt; Humidity&lt;\/p&gt;\n      &lt;p class=\"reading\"&gt;&lt;span id=\"<strong>humidity<\/strong>\"&gt;&lt;\/span&gt; &amp;percnt;&lt;\/p&gt;\n&lt;\/div&gt;\n&lt;div class=\"card\"&gt;\n    &lt;p class=\"card-title\"&gt; Pressure&lt;\/p&gt;\n    &lt;p class=\"reading\"&gt;&lt;span id=\"<strong>pressure<\/strong>\"&gt;&lt;\/span&gt; hpa&lt;\/p&gt;\n&lt;\/div&gt;<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"css-file\">CSS File<\/h2>\n\n\n\n<p>Copy the following to the <span class=\"rnthl rntliteral\">style.css<\/span> file. &nbsp;Feel free to change it to make the web page look as you wish. We won\u2019t explain how the CSS for this web page works because it is not relevant for this tutorial.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-css\">html {\r\n    font-family: Arial, Helvetica, sans-serif;\r\n    display: inline-block;\r\n    text-align: center;\r\n}\r\nh1 {\r\n    font-size: 1.8rem;\r\n    color: white;\r\n}\r\n.topnav {\r\n    overflow: hidden;\r\n    background-color: #0A1128;\r\n}\r\nbody {\r\n    margin: 0;\r\n}\r\n.content {\r\n    padding: 50px;\r\n}\r\n.card-grid {\r\n    max-width: 800px;\r\n    margin: 0 auto;\r\n    display: grid;\r\n    grid-gap: 2rem;\r\n    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\r\n}\r\n.card {\r\n    background-color: white;\r\n    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);\r\n}\r\n.card-title {\r\n    font-size: 1.2rem;\r\n    font-weight: bold;\r\n    color: #034078;\r\n}\r\n.reading {\r\n    font-size: 1.2rem;\r\n    color: #1282A2;\r\n}\r\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP8266\/ESP8266_Sensor_Readings_WebSocket\/data\/style.css\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"javascript-file\">JavaScript File<\/h2>\n\n\n\n<p>Copy the following to the <span class=\"rnthl rntliteral\">script.js<\/span> file.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-javascript\">\r\nvar gateway = `ws:\/\/${window.location.hostname}\/ws`;\r\nvar websocket;\r\n\/\/ Init web socket when the page loads\r\nwindow.addEventListener('load', onload);\r\n\r\nfunction onload(event) {\r\n    initWebSocket();\r\n}\r\n\r\nfunction getReadings(){\r\n    websocket.send(&quot;getReadings&quot;);\r\n}\r\n\r\nfunction initWebSocket() {\r\n    console.log('Trying to open a WebSocket connection\u2026');\r\n    websocket = new WebSocket(gateway);\r\n    websocket.onopen = onOpen;\r\n    websocket.onclose = onClose;\r\n    websocket.onmessage = onMessage;\r\n}\r\n\r\n\/\/ When websocket is established, call the getReadings() function\r\nfunction onOpen(event) {\r\n    console.log('Connection opened');\r\n    getReadings();\r\n}\r\n\r\nfunction onClose(event) {\r\n    console.log('Connection closed');\r\n    setTimeout(initWebSocket, 2000);\r\n}\r\n\r\n\/\/ Function that receives the message from the ESP32 with the readings\r\nfunction onMessage(event) {\r\n    console.log(event.data);\r\n    var myObj = JSON.parse(event.data);\r\n    var keys = Object.keys(myObj);\r\n\r\n    for (var i = 0; i &lt; keys.length; i++){\r\n        var key = keys[i];\r\n        document.getElementById(key).innerHTML = myObj[key];\r\n    }\r\n}<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP8266\/ESP8266_Sensor_Readings_WebSocket\/data\/script.js\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Here\u2019s a list of what this code does:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>initializes a WebSocket connection with the server;<\/li>\n\n\n\n<li>sends a message to the server to get the current sensor readings;<\/li>\n\n\n\n<li>uses the response to update the sensor readings on the web page;<\/li>\n\n\n\n<li>handles data exchange through the WebSocket protocol.<\/li>\n<\/ul>\n\n\n\n<p>Let\u2019s take a look at this JavaScript code to see how it works.<\/p>\n\n\n\n<p>The gateway is the entry point to the WebSocket interface. <span class=\"rnthl rntliteral\">window.location.hostname<\/span> gets the current page address (the web server IP address).<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>var gateway = ws:\/\/${window.location.hostname}\/ws;<\/code><\/pre>\n\n\n\n<p>Create a new global variable called <span class=\"rnthl rntliteral\">websocket<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>var websocket;<\/code><\/pre>\n\n\n\n<p>Add an event listener that will call the <span class=\"rnthl rntliteral\">onload<\/span> function when the web page loads.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>window.addEventListener('load', onload);<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">onload()<\/span> function calls the <span class=\"rnthl rntliteral\">initWebSocket()<\/span> function to initialize a WebSocket connection with the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function onload(event) {\n  initWebSocket();\n}<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">initWebSocket()<\/span> function initializes a WebSocket connection on the gateway defined earlier. We also assign several callback functions for when the WebSocket connection is opened, closed, or when a message is received. <\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function initWebSocket() {\n  console.log('Trying to open a WebSocket connection\u2026');\n  websocket = new WebSocket(gateway);\n  websocket.onopen = onOpen;\n  websocket.onclose = onClose;\n  websocket.onmessage = onMessage;\n}<\/code><\/pre>\n\n\n\n<p>Note that when the WebSocket connection is open, we&#8217;ll call the <span class=\"rnthl rntliteral\">getReadings<\/span> function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function onOpen(event) {\n  console.log('Connection opened');\n  getReadings();\n}<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">getReadings()<\/span> function sends a message to the server <span class=\"rnthl rntliteral\">getReadings<\/span> to get the current sensor readings. Then, we must handle what happens when we receive that message on the server side (ESP8266).<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function getReadings(){\n    websocket.send(\"getReadings\");\n}<\/code><\/pre>\n\n\n\n<p>We handle the messages received via WebSocket protocol on the <span class=\"rnthl rntliteral\">onMessage()<\/span> function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>\/\/ Function that receives the message from the ESP8266 with the readings\nfunction onMessage(event) {\n    console.log(event.data);\n    var myObj = JSON.parse(event.data);\n    var keys = Object.keys(myObj);\n\n    for (var i = 0; i &lt; keys.length; i++){\n        var key = keys&#091;i];\n        document.getElementById(key).innerHTML = myObj&#091;key];\n    }\n}<\/code><\/pre>\n\n\n\n<p>The server sends the readings in JSON format, for example:<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>{\n  temperature: 20;\n  humidity: 50;\n  pressure: 1023;\n}<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">onMessage()<\/span> function simply goes through all the key values (<span class=\"rnthl rntliteral\">temperature<\/span>, <span class=\"rnthl rntliteral\">humidity<\/span>, and <span class=\"rnthl rntliteral\">pressure<\/span>) and places them in the corresponding places on the HTML page. In this case, the keys have the same name as the ids we&#8217;ve defined on the HTML page. So, we can simply do something like this:<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>for (var i = 0; i &lt; keys.length; i++){\n    var key = keys&#091;i];\n    document.getElementById(key).innerHTML = myObj&#091;key];\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"esp8266-sketch\">Code for ESP8266 WebSocket Server (Sensor Readings)<\/h2>\n\n\n\n<p>Copy the following code to your Arduino IDE.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*********\r\n  Rui Santos\r\n  Complete instructions at https:\/\/RandomNerdTutorials.com\/esp8266-nodemcu-websocket-server-sensor\/\r\n  \r\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.\r\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r\n*********\/\r\n\r\n#include &lt;Arduino.h&gt;\r\n#include &lt;ESP8266WiFi.h&gt;\r\n#include &lt;ESPAsyncTCP.h&gt;\r\n#include &lt;ESPAsyncWebServer.h&gt;\r\n#include &quot;LittleFS.h&quot;\r\n#include &lt;Arduino_JSON.h&gt;\r\n#include &lt;Adafruit_BME280.h&gt;\r\n#include &lt;Adafruit_Sensor.h&gt;\r\n\r\n\/\/ Replace with your network credentials\r\nconst char* ssid = &quot;REPLACE_WITH_YOUR_SSID&quot;;\r\nconst char* password = &quot;REPLACE_WITH_YOUR_PASSWORD&quot;;\r\n\r\n\/\/ Create AsyncWebServer object on port 80\r\nAsyncWebServer server(80);\r\n\r\n\/\/ Create a WebSocket object\r\nAsyncWebSocket ws(&quot;\/ws&quot;);\r\n\r\n\/\/ Json Variable to Hold Sensor Readings\r\nJSONVar readings;\r\n\r\n\/\/ Timer variables\r\nunsigned long lastTime = 0;  \r\nunsigned long timerDelay = 30000;\r\n\r\n\/\/ Create a sensor object\r\nAdafruit_BME280 bme;         \/\/ BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL)\r\n\r\n\/\/ Init BME280\r\nvoid initBME(){\r\n  if (!bme.begin(0x76)) {\r\n    Serial.println(&quot;Could not find a valid BME280 sensor, check wiring!&quot;);\r\n    while (1);\r\n  }\r\n}\r\n\r\n\/\/ Get Sensor Readings and return JSON object\r\nString getSensorReadings(){\r\n  readings[&quot;temperature&quot;] = String(bme.readTemperature());\r\n  readings[&quot;humidity&quot;] =  String(bme.readHumidity());\r\n  readings[&quot;pressure&quot;] = String(bme.readPressure()\/100.0F);\r\n  String jsonString = JSON.stringify(readings);\r\n  return jsonString;\r\n}\r\n\r\n\/\/ Initialize LittleFS\r\nvoid initFS() {\r\n  if (!LittleFS.begin()) {\r\n    Serial.println(&quot;An error has occurred while mounting LittleFS&quot;);\r\n  }\r\n  else{\r\n   Serial.println(&quot;LittleFS mounted successfully&quot;);\r\n  }\r\n}\r\n\r\n\/\/ Initialize WiFi\r\nvoid initWiFi() {\r\n  WiFi.mode(WIFI_STA);\r\n  WiFi.begin(ssid, password);\r\n  Serial.print(&quot;Connecting to WiFi ..&quot;);\r\n  while (WiFi.status() != WL_CONNECTED) {\r\n    Serial.print('.');\r\n    delay(1000);\r\n  }\r\n  Serial.println(WiFi.localIP());\r\n}\r\n\r\nvoid notifyClients(String sensorReadings) {\r\n  ws.textAll(sensorReadings);\r\n}\r\n\r\nvoid handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {\r\n  AwsFrameInfo *info = (AwsFrameInfo*)arg;\r\n  if (info-&gt;final &amp;&amp; info-&gt;index == 0 &amp;&amp; info-&gt;len == len &amp;&amp; info-&gt;opcode == WS_TEXT) {\r\n    \/\/data[len] = 0;\r\n    \/\/String message = (char*)data;\r\n    \/\/ Check if the message is &quot;getReadings&quot;\r\n    \/\/if (strcmp((char*)data, &quot;getReadings&quot;) == 0) {\r\n      \/\/if it is, send current sensor readings\r\n      String sensorReadings = getSensorReadings();\r\n      Serial.print(sensorReadings);\r\n      notifyClients(sensorReadings);\r\n    \/\/}\r\n  }\r\n}\r\n\r\nvoid onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {\r\n  switch (type) {\r\n    case WS_EVT_CONNECT:\r\n      Serial.printf(&quot;WebSocket client #%u connected from %s\\n&quot;, client-&gt;id(), client-&gt;remoteIP().toString().c_str());\r\n      break;\r\n    case WS_EVT_DISCONNECT:\r\n      Serial.printf(&quot;WebSocket client #%u disconnected\\n&quot;, client-&gt;id());\r\n      break;\r\n    case WS_EVT_DATA:\r\n      handleWebSocketMessage(arg, data, len);\r\n      break;\r\n    case WS_EVT_PONG:\r\n    case WS_EVT_ERROR:\r\n      break;\r\n  }\r\n}\r\n\r\nvoid initWebSocket() {\r\n  ws.onEvent(onEvent);\r\n  server.addHandler(&amp;ws);\r\n}\r\n\r\nvoid setup() {\r\n  Serial.begin(115200);\r\n  initBME();\r\n  initWiFi();\r\n  initFS();\r\n  initWebSocket();\r\n\r\n  \/\/ Web Server Root URL\r\n  server.on(&quot;\/&quot;, HTTP_GET, [](AsyncWebServerRequest *request) {\r\n    request-&gt;send(LittleFS, &quot;\/index.html&quot;, &quot;text\/html&quot;);\r\n  });\r\n\r\n  server.serveStatic(&quot;\/&quot;, LittleFS, &quot;\/&quot;);\r\n\r\n  \/\/ Start server\r\n  server.begin();\r\n}\r\n\r\nvoid loop() {\r\n  if ((millis() - lastTime) &gt; timerDelay) {\r\n    String sensorReadings = getSensorReadings();\r\n    Serial.print(sensorReadings);\r\n    notifyClients(sensorReadings);\r\n\r\n  lastTime = millis();\r\n\r\n  }\r\n\r\n  ws.cleanupClients();\r\n}\r\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP8266\/ESP8266_Sensor_Readings_WebSocket\/ESP8266_Sensor_Readings_WebSocket.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How the Code Works<\/h3>\n\n\n\n<p>Continue reading to learn how the code works, or skip to the <a href=\"#demonstration\" title=\"\">demonstration <\/a>section.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Including Libraries<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">Adafruit_Sensor<\/span> and <span class=\"rnthl rntliteral\">Adafruit_BME280<\/span> libraries are needed to interface with the BME280 sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;Adafruit_BME280.h&gt;\n#include &lt;Adafruit_Sensor.h&gt;<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">ESP8266WiFi<\/span>, <span class=\"rnthl rntliteral\">ESPAsyncWebServer,<\/span> and <span class=\"rnthl rntliteral\">ESPAsyncTCP<\/span> libraries are used to create the web server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;ESP8266WiFi.h&gt;\n#include &lt;ESPAsyncTCP.h&gt;\n#include &lt;ESPAsyncWebServer.h&gt;<\/code><\/pre>\n\n\n\n<p>We&#8217;ll save the HTML, CSS, and JavaScript files on the ESP8266 filesystem, so we also need to include the <span class=\"rnthl rntliteral\">LittleFS.h<\/span> library.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include \"LittleFS.h\"<\/code><\/pre>\n\n\n\n<p>To create JSON objects, we&#8217;ll use the <span class=\"rnthl rntliteral\">Arduino_JSON<\/span> library.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;Arduino_JSON.h&gt;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Network Credentials<\/h4>\n\n\n\n<p>Insert your network credentials in the following variables, so that the ESP8266 can connect to your local network using Wi-Fi.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const char* ssid = \"REPLACE_WITH_YOUR_SSID\";\nconst char* password = \"REPLACE_WITH_YOUR_PASSWORD\";<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">AsyncWebServer and AsyncWebSocket<\/h4>\n\n\n\n<p>Create an <span class=\"rnthl rntliteral\">AsyncWebServer<\/span> object on port 80.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>AsyncWebServer server(80);<\/code><\/pre>\n\n\n\n<p>The following line creates a new websocket object on <span class=\"rnthl rntliteral\">\/ws<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Create a WebSocket object\nAsyncWebSocket ws(\"\/ws\");<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Timer Variables<\/h4>\n\n\n\n<p>The following variables are used to create timers in our code. In our case, we&#8217;ll send sensor readings to the client via WebSocket protocol every 30000 milliseconds (30 seconds). You can change the <span class=\"rnthl rntliteral\">timerDelay<\/span> variable to any other value that makes sense for your project.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Timer variables\nunsigned long lastTime = 0;\nunsigned long timerDelay = 30000;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Initializing the BME280 Sensor<\/h4>\n\n\n\n<p>The following line creates an <span class=\"rnthl rntliteral\">Adafruit_BME280<\/span> object to refer to the sensor called <span class=\"rnthl rntliteral\">bme<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Create a sensor object\nAdafruit_BME280 bme;<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">initBME()<\/span> function initializes the sensor. It will be called later in the <span class=\"rnthl rntliteral\">setup()<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Init BME280\nvoid initBME(){\n  if (!bme.begin(0x76)) {\n    Serial.println(\"Could not find a valid BME280 sensor, check wiring!\");\n    while (1);\n  }\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Getting Sensor Readings (JSON String)<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">getSensoreadings()<\/span> function creates a JSON string with the current sensor readings.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Get Sensor Readings and return JSON object\nString getSensorReadings(){\n  readings&#091;\"temperature\"] = String(bme.readTemperature());\n  readings&#091;\"humidity\"] = String(bme.readHumidity());\n  readings&#091;\"pressure\"] = String(bme.readPressure()\/100.0F);\n  String jsonString = JSON.stringify(readings);\n  return jsonString;\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Initializing the Filesystem<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">initFS()<\/span> function initializes LittleFS, the ESP8266 filesystem we&#8217;re using in this project to save the HTML, CSS, and Javascript files.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Initialize LittleFS\nvoid initFS() {\n  if (!LittleFS.begin()) {\n    Serial.println(\"An error has occurred while mounting LittleFS\");\n  }\n  else{\n    Serial.println(\"LittleFS mounted successfully\");\n  }\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Initializing Wi-Fi<\/h4>\n\n\n\n<p>The following function initializes Wi-Fi and connects to your network using the credentials you used previously. This function will be called later in the <span class=\"rnthl rntliteral\">setup()<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Initialize WiFi\nvoid initWiFi() {\n  WiFi.mode(WIFI_STA);\n  WiFi.begin(ssid, password);\n  Serial.print(\"Connecting to WiFi ..\");\n  while (WiFi.status() != WL_CONNECTED) {\n    Serial.print('.');\n    delay(1000);\n  }\n  Serial.println(WiFi.localIP());\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Notifying all Clients Via WebSocket<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">notifyClients()<\/span> function notifies all clients with the current sensor readings. Calling this function is what allows us to notify changes in all clients whenever we get new sensor readings (every 30 seconds).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void notifyClients(String sensorReadings) {\n  ws.textAll(sensorReadings);\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Handling WebSocket Messages<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">handleWebSocketMessage()<\/span>, as the name suggests, handles what happens when the server receives a message from the client via WebSocket protocol. We&#8217;ve seen in the JavaScript file, that the server can receive the <span class=\"rnthl rntliteral\">getReadings<\/span> message.<\/p>\n\n\n\n<p>When the ESP8266 receives the <span class=\"rnthl rntliteral\">getReadings<\/span> message, it sends the current sensor readings.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {\n  AwsFrameInfo *info = (AwsFrameInfo*)arg;\n  if (info-&gt;final &amp;&amp; info-&gt;index == 0 &amp;&amp; info-&gt;len == len &amp;&amp; info-&gt;opcode == WS_TEXT) {\n    data&#091;len] = 0;\n    String message = (char*)data;\n    \/\/ Check if the message is \"getReadings\"\n    if (strcmp((char*)data, \"getReadings\") == 0) {\n      \/\/ if it is, send current sensor readings\n      String sensorReadings = getSensorReadings();\n      Serial.print(sensorReadings);\n      notifyClients(sensorReadings);\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Handling WebSocket Events<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">onEvent()<\/span> function handles other WebSocket events.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {\n  switch (type) {\n    case WS_EVT_CONNECT:\n      Serial.printf(\"WebSocket client #%u connected from %s\\n\", client-&gt;id(), client-&gt;remoteIP().toString().c_str());\n      break;\n    case WS_EVT_DISCONNECT:\n      Serial.printf(\"WebSocket client #%u disconnected\\n\", client-&gt;id());\n      break;\n    case WS_EVT_DATA:\n      handleWebSocketMessage(arg, data, len);\n      break;\n    case WS_EVT_PONG:\n    case WS_EVT_ERROR:\n      break;\n  }\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Initializing WebSocket Protocol<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">initWebSocket()<\/span> function initializes the WebSocket protocol.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void initWebSocket() {\n  ws.onEvent(onEvent);\n  server.addHandler(&amp;ws);\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">setup()<\/h4>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, we initialize the Serial Monitor, the BME280 sensor, Wi-Fi, the filesystem, and the WebSocket protocol by calling the functions we&#8217;ve created previously.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.begin(115200);\ninitBME();\ninitWiFi();\ninitSPIFFS();\ninitWebSocket();<\/code><\/pre>\n\n\n\n<p>The following lines will serve the index.html and the other referenced static files saved on SPIFFS (style.css and script.js) when you access the web server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Web Server Root URL\nserver.on(\"\/\", HTTP_GET, &#091;](AsyncWebServerRequest *request) {\n  request-&gt;send(SPIFFS, \"\/index.html\", \"text\/html\");\n});\n\nserver.serveStatic(\"\/\", SPIFFS, \"\/\");<\/code><\/pre>\n\n\n\n<p>Finally, start the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Start server\nserver.begin();<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">loop()<\/h4>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">loop()<\/span>, we get and send new sensor readings every 30000 milliseconds (30 seconds).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void loop() {\n  if ((millis() - lastTime) &gt; timerDelay) {\n    String sensorReadings = getSensorReadings();\n    Serial.print(sensorReadings);\n    notifyClients(sensorReadings);\n\n    lastTime = millis();\n\n  }\n\n  ws.cleanupClients();\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Upload Code and Files<\/h2>\n\n\n\n<p>After inserting your network credentials, save the code. Go to&nbsp;<strong>Sketch<\/strong>&nbsp;&gt;&nbsp;<strong>Show Sketch Folder<\/strong>, and create a folder called&nbsp;<strong>data<\/strong>. <\/p>\n\n\n<div class=\"wp-block-image is-style-default\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"351\" height=\"271\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/arduino-ide-show-sketch-folder.png?resize=351%2C271&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Arduino IDE Open Sketch Folder to create data folder\" class=\"wp-image-158892\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/arduino-ide-show-sketch-folder.png?w=351&amp;quality=100&amp;strip=all&amp;ssl=1 351w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/arduino-ide-show-sketch-folder.png?resize=300%2C232&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 351px) 100vw, 351px\" \/><\/figure><\/div>\n\n\n<p>Inside that folder, you should place the HTML, CSS, and JavaScript files.<\/p>\n\n\n\n<p>Then, upload the code to your ESP8266 board. Make sure you have the right board and COM port selected. Also, make sure you\u2019ve added your network credentials.<\/p>\n\n\n<div class=\"wp-block-image is-style-default\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"32\" height=\"32\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/12\/upload-button-arduino-ide.png?resize=32%2C32&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Upload Arduino code\" class=\"wp-image-91745\"\/><\/figure><\/div>\n\n\n<p><strong>After uploading the code, you need to upload the files to the filesystem.<\/strong><\/p>\n\n\n\n<p>Press [<strong>Ctrl<\/strong>] + [<strong>Shift<\/strong>] + [<strong>P<\/strong>] on Windows or [<strong>\u2318<\/strong>] + [<strong>Shift<\/strong>] + [<strong>P<\/strong>] on MacOS to open the command palette. Search for the&nbsp;<strong>Upload LittleFS to Pico\/ESP8266\/ESP32<\/strong>&nbsp;command and click on it.<\/p>\n\n\n\n<p>If you don\u2019t have this option is because you didn\u2019t install the filesystem uploader plugin.&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/arduino-ide-2-install-esp8266-littlefs\/\">Check this tutorial<\/a>.<\/p>\n\n\n<div class=\"wp-block-image is-style-default\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"666\" height=\"344\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/06\/ESP8266-Upload-filesystem-image-esp8266.png?resize=666%2C344&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 Upload Filesystem Image\" class=\"wp-image-168043\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/06\/ESP8266-Upload-filesystem-image-esp8266.png?w=666&amp;quality=100&amp;strip=all&amp;ssl=1 666w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/06\/ESP8266-Upload-filesystem-image-esp8266.png?resize=300%2C155&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 666px) 100vw, 666px\" \/><\/figure><\/div>\n\n\n<p>When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200. Press the ESP8266 EN\/RST button, and it should print the ESP8266 IP address.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"demonstration\">Demonstration<\/h2>\n\n\n\n<p>Open a browser on your local network and paste the ESP8266 IP address. You should get access to the web server page that displays the sensor readings.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"787\" height=\"419\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP-Websocket-Server-Display-Sensor-Readings-Web-Browser-ESP32.png?resize=787%2C419&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 Websocket Server Sensor Readings\" class=\"wp-image-130719\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP-Websocket-Server-Display-Sensor-Readings-Web-Browser-ESP32.png?w=787&amp;quality=100&amp;strip=all&amp;ssl=1 787w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP-Websocket-Server-Display-Sensor-Readings-Web-Browser-ESP32.png?resize=300%2C160&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP-Websocket-Server-Display-Sensor-Readings-Web-Browser-ESP32.png?resize=768%2C409&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 787px) 100vw, 787px\" \/><\/figure><\/div>\n\n\n<p>The readings update automatically on the web page every 30 seconds.<\/p>\n\n\n\n<p>You can have multiple clients on different web browser tabs or devices and it will update automatically on all clients.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"360\" height=\"723\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/websocket-server-sensor-readings-ESP32-demonstration-1.png?resize=360%2C723&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU WebSocket Server Display Sensor Readings Arduino Demonstration\" class=\"wp-image-130724\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/websocket-server-sensor-readings-ESP32-demonstration-1.png?w=360&amp;quality=100&amp;strip=all&amp;ssl=1 360w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/websocket-server-sensor-readings-ESP32-demonstration-1.png?resize=149%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 149w\" sizes=\"(max-width: 360px) 100vw, 360px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial, you&#8217;ve learned how to build a websocket server with the ESP8266 that serves a web page to display sensor readings. The sensor readings update automatically on the web page without the need to manually refresh it.<\/p>\n\n\n\n<p>We hope you learned a lot from this tutorial. Let us know in the comments below if you successfully followed this tutorial and got the project working. <\/p>\n\n\n\n<p>To learn more about building web servers with the ESP8266, we really recommend taking a look at our eBook:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/build-web-servers-esp32-esp8266-ebook\/\"><strong>Build Web Servers with ESP32 and ESP8266 eBook<\/strong><\/a><\/li>\n<\/ul>\n\n\n\n<p>Learn more about the ESP8266 with our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/home-automation-using-esp8266\/\">Home Automation using ESP8266<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/build-web-servers-esp32-esp8266-ebook\/\">Build Web Servers with ESP32 and ESP8266<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/firebase-esp32-esp8266-ebook\/\">Firebase Web App with ESP32 and ESP8266<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp8266\/\">Free ESP8266 Projects and Tutorials<\/a><\/li>\n<\/ul>\n\n\n\n<p>Thank you for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide, you&#8217;ll learn how to create a WebSocket server with the ESP8266 NodeMCU board to display sensor readings on a web page. Whenever the ESP8266 has new readings &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP8266 NodeMCU WebSocket Server: Display Sensor Readings\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-websocket-server-sensor\/#more-130826\" aria-label=\"Read more about ESP8266 NodeMCU WebSocket Server: Display Sensor Readings\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":130827,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[214,265,246,240,300,264],"tags":[],"class_list":["post-130826","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp8266","category-esp8266-project","category-esp8266-arduino-ide","category-esp8266-projects","category-0-esp8266","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP8266-Websocket-Server-Sensor-Readings.jpg?fit=1280%2C720&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/130826","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=130826"}],"version-history":[{"count":8,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/130826\/revisions"}],"predecessor-version":[{"id":168052,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/130826\/revisions\/168052"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/130827"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=130826"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=130826"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=130826"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}