{"id":130716,"date":"2023-07-19T09:26:32","date_gmt":"2023-07-19T09:26:32","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=130716"},"modified":"2025-03-14T15:54:53","modified_gmt":"2025-03-14T15:54:53","slug":"esp32-websocket-server-sensor","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-websocket-server-sensor\/","title":{"rendered":"ESP32 WebSocket Server: Display Sensor Readings"},"content":{"rendered":"\n<p>In this guide, you&#8217;ll learn how to create a WebSocket server with the ESP32 to display sensor readings on a web page. Whenever the ESP32 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\/ESP32-Websocket-Server-Sensor-Readings.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 WebSocket Server Display Sensor Readings Arduino IDE\" class=\"wp-image-130726\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP32-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\/ESP32-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\/ESP32-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\/ESP32-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 from scratch, check out 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<\/a><\/li>\n\n\n\n<li><a href=\"#ESP32-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 ESP8266 board: <a href=\"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-websocket-server-sensor\/\" title=\"\">ESP8266 NodeMCU 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 (ESP32 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 ESP32 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 ESP32 outputs via WebSocket protocol: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-websocket-server-arduino\/\">ESP32 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=\"ESP32 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 ESP32 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-ESP32-sensor-readings-how-it-works-1.png?resize=1024%2C286&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Websocket server how it works\" class=\"wp-image-130730\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP32-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-ESP32-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-ESP32-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-ESP32-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-ESP32-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-ESP32-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-ESP32-sensor-readings-how-it-works.png?resize=1024%2C286&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Websocket server how it works\" class=\"wp-image-130731\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/Websocket-Server-ESP32-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-ESP32-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-ESP32-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-ESP32-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-ESP32-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-ESP32-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\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32 Board<\/a> &#8211; read <a href=\"https:\/\/makeradvisor.com\/esp32-development-boards-review-comparison\/\" target=\"_blank\" rel=\"noopener\" title=\"\">ESP32 Development 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 ESP32 Boards Add-on<\/h3>\n\n\n\n<p>We\u2019ll program the ESP32 using Arduino IDE. So, you must have the ESP32 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-esp32-arduino-ide-2-0\/\" title=\"\">Installing ESP32 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 ESP32:<\/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 ESP32 flash memory (LittleFS), we\u2019ll use a plugin for Arduino IDE:&nbsp;<strong>LittleFS<\/strong> <strong>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-esp32-littlefs\/\">Arduino IDE 2: Install ESP32 LittleFS Uploader (Upload Files to the Filesystem)<\/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\/esp32-vs-code-platformio-littlefs\/\">ESP32 with VS Code and PlatformIO: Upload Files to LittleFS Filesystem<\/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 version 0.1.0<\/a><span style=\"font-size: inherit;\">&nbsp;(Arduino Library Manager)<\/span><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/adafruit\/Adafruit_BME280_Library\" target=\"_blank\" rel=\"noopener\" title=\"\">Adafruit_BME280<\/a> (Arduino Library Manager)<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncWebServer\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncWebServer\u00a0<\/a>by ESP32Async<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/ESP32Async\/AsyncTCP\" target=\"_blank\" rel=\"noopener\" title=\"\">AsyncTCP<\/a> by ESP32Async<\/li>\n<\/ul>\n\n\n\n<p>You can install the first two 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 library name.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Building the Circuit<\/h2>\n\n\n\n<p>To demonstrate how to display sensor readings on a web server with the ESP32, we&#8217;ll send sensor readings from a BME280 sensor to the browser. You need to wire a BME280 sensor to your ESP32, but 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 ESP32&nbsp;SCL (<span class=\"rnthl rntcblue\">GPIO 22<\/span>)&nbsp;and&nbsp;SDA (<span class=\"rnthl rntcgreen\">GPIO 21<\/span>)&nbsp;pins, as shown in the following schematic diagram.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"675\" height=\"670\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit_f.png?resize=675%2C670&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Wiring to BME280 Schematic Diagram\" class=\"wp-image-99755\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit_f.png?w=675&amp;quality=100&amp;strip=all&amp;ssl=1 675w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit_f.png?resize=300%2C298&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit_f.png?resize=150%2C150&amp;quality=100&amp;strip=all&amp;ssl=1 150w\" sizes=\"(max-width: 675px) 100vw, 675px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclblue\">Recommended reading: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-pinout-reference-gpios\/\">ESP32 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\/2024\/06\/folder-structure.png?resize=601%2C358&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Organizing your Files arduino sketch index html style css script js\" class=\"wp-image-158891\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/folder-structure.png?w=601&amp;quality=100&amp;strip=all&amp;ssl=1 601w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/folder-structure.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 ESP32 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\/ESP32\/ESP32_Sensor_Readings_WebSocket\/ESP32_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;&lt;i class=&quot;fas fa-thermometer-threequarters&quot; style=&quot;color:#059e8a;&quot;&gt;&lt;\/i&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;<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/ESP32_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 elements 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}<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/ESP32_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\/ESP32\/ESP32_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 (ESP32).<\/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 ESP32 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=\"ESP32-sketch\">Code for ESP32 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 &amp; Sara Santos - Random Nerd Tutorials\r\n  Complete instructions at https:\/\/RandomNerdTutorials.com\/esp32-websocket-server-sensor\/\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#include &lt;Arduino.h&gt;\r\n#include &lt;WiFi.h&gt;\r\n#include &lt;AsyncTCP.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;\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 initLittleFS() {\r\n  if (!LittleFS.begin(true)) {\r\n    Serial.println(&quot;An error has occurred while mounting LittleFS&quot;);\r\n  }\r\n  Serial.println(&quot;LittleFS mounted successfully&quot;);\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  initLittleFS();\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    lastTime = millis();\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\/ESP32\/ESP32_Sensor_Readings_WebSocket\/ESP32_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\">WiFi<\/span>, <span class=\"rnthl rntliteral\">ESPAsyncWebServer<\/span> and <span class=\"rnthl rntliteral\">AsyncTCP<\/span> libraries are used to create the web server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;WiFi.h&gt;\n#include &lt;AsyncTCP.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 ESP32 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 \"<span class=\"rnthl rntliteral\">LittleFS<\/span>.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 ESP32 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\">init<span class=\"rnthl rntliteral\">LittleFS<\/span>()<\/span> function initializes <span class=\"rnthl rntliteral\">LittleFS<\/span>, the ESP32 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 <span class=\"rnthl rntliteral\">LittleFS<\/span>\nvoid init<span class=\"rnthl rntliteral\">LittleFS<\/span>() {\n  if (!<span class=\"rnthl rntliteral\">LittleFS<\/span>.begin(true)) {\n    Serial.println(\"An error has occurred while mounting <span class=\"rnthl rntliteral\">LittleFS<\/span>\");\n  }\n  Serial.println(\"<span class=\"rnthl rntliteral\">LittleFS<\/span>mounted successfully\");\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 ESP32 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();\ninit<span class=\"rnthl rntliteral\">LittleFS<\/span>();\ninitWebSocket();<\/code><\/pre>\n\n\n\n<p>The following lines will serve the index.html and the other referenced static files saved on <span class=\"rnthl rntliteral\">LittleFS<\/span> (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(<span class=\"rnthl rntliteral\">LittleFS<\/span>, \"\/index.html\", \"text\/html\");\n});\n\nserver.serveStatic(\"\/\", <span class=\"rnthl rntliteral\">LittleFS<\/span>, \"\/\");<\/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><em>data<\/em><\/strong>.<\/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=\"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><strong>Inside that folder, you should place the HTML, CSS, and JavaScript files.<\/strong><\/p>\n\n\n\n<p>Upload those files to the filesystem: 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.<a href=\"https:\/\/randomnerdtutorials.com\/arduino-ide-2-install-esp32-littlefs\/\">&nbsp;Check this tutorial<\/a>.<\/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=\"744\" height=\"401\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/upload-files-little-fs-esp32-arduino-ide.png?resize=744%2C401&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Sketch Data Upload LittleFS Arduino IDE\" class=\"wp-image-158893\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/upload-files-little-fs-esp32-arduino-ide.png?w=744&amp;quality=100&amp;strip=all&amp;ssl=1 744w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/upload-files-little-fs-esp32-arduino-ide.png?resize=300%2C162&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 744px) 100vw, 744px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntcred\"><strong>Important:&nbsp;<\/strong>make sure the Serial Monitor is closed before uploading to the filesystem. Otherwise, the upload will fail.<\/p>\n\n\n\n<p>Then, upload the code to your ESP32 board. Make sure you modified the code with your network credentials.<\/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=\"36\" height=\"39\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/05\/arduino-ide-2-upload-button.png?resize=36%2C39&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Arduino IDE 2 Upload Button\" class=\"wp-image-146269\"\/><\/figure><\/div>\n\n\n<p>When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200. Press the ESP32 EN\/RST button, and it should print the ESP32 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 ESP32 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=\"ESP32 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=\"ESP32 WebSocket Server Display Sensor Readings Arduino IDE 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 ESP32 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 ESP32, 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 ESP32 with our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 with Arduino IDE (eBook + video course)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32\/\">More ESP32 tutorials and projects\u2026<\/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 ESP32 to display sensor readings on a web page. Whenever the ESP32 has new readings available, the &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32 WebSocket Server: Display Sensor Readings\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-websocket-server-sensor\/#more-130716\" aria-label=\"Read more about ESP32 WebSocket Server: Display Sensor Readings\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":130726,"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":[281,276,277,299,264],"tags":[],"class_list":["post-130716","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32-project","category-esp32","category-esp32-arduino-ide","category-0-esp32","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2023\/04\/ESP32-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\/130716","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=130716"}],"version-history":[{"count":22,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/130716\/revisions"}],"predecessor-version":[{"id":167924,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/130716\/revisions\/167924"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/130726"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=130716"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=130716"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=130716"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}