{"id":106154,"date":"2021-10-14T15:01:33","date_gmt":"2021-10-14T15:01:33","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=106154"},"modified":"2025-03-17T11:28:46","modified_gmt":"2025-03-17T11:28:46","slug":"stepper-motor-esp8266-websocket","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/stepper-motor-esp8266-websocket\/","title":{"rendered":"ESP8266 NodeMCU Web Server: Control Stepper Motor (WebSocket)"},"content":{"rendered":"\n<p>In this guide, you&#8217;ll learn how to create a web server with the ESP8266 NodeMCU board that displays a web page to control a stepper motor. The web page allows you to insert the number of steps and select clockwise or counterclockwise directions. Additionally, it also shows whether the motor is currently spinning or if it is stopped. The communication between the client and the server is achieved via WebSocket protocol. All clients are updated with the current motor state.<\/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\/2021\/08\/ESP8266-Stepper-Motor-Web-Server-Websocket.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU Web Server Control Stepper Motor WebSocket Arduino IDE\" class=\"wp-image-106155\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP8266-Stepper-Motor-Web-Server-Websocket.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP8266-Stepper-Motor-Web-Server-Websocket.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP8266-Stepper-Motor-Web-Server-Websocket.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP8266-Stepper-Motor-Web-Server-Websocket.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>To better understand how this project works, you can take a look at the following tutorials:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-stepper-motor-28byj-48-uln2003\/\">ESP8266 NodeMCU with Stepper Motor (28BYJ-48 and ULN2003 Motor Driver)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-websocket-server-arduino\/\">ESP8266 NodeMCU WebSocket Server: Control Outputs (Arduino IDE)<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Table of Contents<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"#prerequisites\">Prerequisites<\/a><\/li>\n\n\n\n<li><a href=\"#project-overview\">Project Overview<\/a><\/li>\n\n\n\n<li><a href=\"#organize-files\">Organizing your files:<\/a>\n<ol class=\"wp-block-list\">\n<li><a href=\"#html-file\">HTML File<\/a><\/li>\n\n\n\n<li><a href=\"#css-file\">CSS File<\/a><\/li>\n\n\n\n<li><a href=\"#javascript-file\">JavaScript File<\/a><\/li>\n\n\n\n<li><a href=\"#arduino-sketch\">Arduino Sketch<\/a><\/li>\n<\/ol>\n<\/li>\n\n\n\n<li><a href=\"#upload-code-files\">Upload Code and Files<\/a><\/li>\n\n\n\n<li><a href=\"#demonstration\">Demonstration<\/a><\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"prerequisites\">Prerequisites<\/h2>\n\n\n\n<p>Before proceeding with the tutorial, make sure you check 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 tutorial, you need the following parts:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/28byj-48-stepper-motor-uln2003\/\" target=\"_blank\" rel=\"noreferrer noopener\">28BYJ-48 Stepper Motor + ULN2003 Motor Driver<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/esp8266-esp-12e-nodemcu-wi-fi-development-board\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP8266<\/a>\u00a0(read\u00a0<a href=\"https:\/\/makeradvisor.com\/best-esp8266-wi-fi-development-board\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP8266 Development Boards<\/a>)<\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\">Jumper Wires<\/a><\/li>\n\n\n\n<li>5V Power Supply<\/li>\n<\/ul>\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 filesystem (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>There are different ways to control stepper motors with a microcontroller. To control the stepper motor with the ESP8266, we&#8217;ll use the <a href=\"https:\/\/www.airspayce.com\/mikem\/arduino\/AccelStepper\/\" target=\"_blank\" rel=\"noreferrer noopener\">AccelStepper <\/a>library. This library allows you to easily move the motor a defined number of steps, set its speed, acceleration, and much more. The library has great documentation explaining how to use its methods. You can check it <a href=\"https:\/\/www.airspayce.com\/mikem\/arduino\/AccelStepper\/classAccelStepper.html\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p>Follow the next steps to install the library in your Arduino IDE.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Go to <strong>Sketch<\/strong> > <strong>Include Library<\/strong> > <strong>Manage Libraries&#8230;<\/strong><\/li>\n\n\n\n<li>Search for &#8220;accelstepper&#8221;.<\/li>\n\n\n\n<li>Install the AccelStepper library by Mike McCauley. We&#8217;re using version 1.61.0.<\/li>\n<\/ol>\n\n\n\n<p>We&#8217;ll build the web server using the following libraries:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\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&nbsp;by 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<h3 class=\"wp-block-heading\">5) Schematic Diagram<\/h3>\n\n\n\n<p>The following schematic diagram shows the connections between the stepper motor and the ESP8266.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"1200\" height=\"646\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP8266-Stepper-Motor-Schematic-Diagram-Wiring.png?resize=1200%2C646&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 with Stepper Motor 28BYJ-48 and ULN2003A Schematic Diagram Wiring\" class=\"wp-image-106096\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP8266-Stepper-Motor-Schematic-Diagram-Wiring.png?w=1269&amp;quality=100&amp;strip=all&amp;ssl=1 1269w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP8266-Stepper-Motor-Schematic-Diagram-Wiring.png?resize=300%2C161&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP8266-Stepper-Motor-Schematic-Diagram-Wiring.png?resize=1024%2C551&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP8266-Stepper-Motor-Schematic-Diagram-Wiring.png?resize=768%2C413&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p id=\"block-bb12f0a8-4c76-4265-b3cd-21f5fd8080bb\"><strong>Note: <\/strong> You should power the ULN2003 motor driver using an external 5V power supply.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>Motor Driver<\/strong><\/td><td><strong>ESP8266<\/strong><\/td><\/tr><tr><td>IN1<\/td><td><span class=\"rnthl rntclblue\">GPIO 5<\/span><\/td><\/tr><tr><td>IN2<\/td><td><span class=\"rnthl rntcyellow\">GPIO 4<\/span><\/td><\/tr><tr><td>IN3<\/td><td><span class=\"rnthl rntclgreen\">GPIO 14<\/span><\/td><\/tr><tr><td>IN4<\/td><td><span class=\"rnthl rntcgray\">GPIO 12<\/span><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"project-overview\">Project Overview<\/h2>\n\n\n\n<p>The following image shows the web page you&#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=\"676\" height=\"588\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-ESP8266-Stepper-Motor-Websocket-web-server-animation.png?resize=676%2C588&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU Control Stepper Motor WebSocket Project overview\" class=\"wp-image-105635\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-ESP8266-Stepper-Motor-Websocket-web-server-animation.png?w=676&amp;quality=100&amp;strip=all&amp;ssl=1 676w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-ESP8266-Stepper-Motor-Websocket-web-server-animation.png?resize=300%2C261&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 676px) 100vw, 676px\" \/><\/figure><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>The web page shows a form where you can enter the number of steps you want the motor to move and select the direction: clockwise or counterclockwise.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>It also shows the motor state: <em>motor spinning<\/em> or <em>motor stopped<\/em>. Additionally, there&#8217;s a gear icon that spins as long as the motor is spinning. The gear spins clockwise or counterclockwise direction accordingly to the chosen direction.<\/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=\"750\" height=\"455\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Web-Server-Websockets-How-it-Works-01.png?resize=750%2C455&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 Stepper Motor Web Server Websocket How it Works\" class=\"wp-image-105637\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Web-Server-Websockets-How-it-Works-01.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Web-Server-Websockets-How-it-Works-01.png?resize=300%2C182&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>The server and the client communicate using WebSocket protocol.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>When you click on the <strong>GO!<\/strong> button, it calls a Javascript function that sends a message via WebSocket protocol with all the information: steps and direction (<strong>3<\/strong>). The message is in the following format:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>steps<strong>&amp;<\/strong>direction<\/code><\/pre>\n\n\n\n<p>So, if you submit 2000 steps and clockwise direction, it will send the following message:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>2000&amp;CW<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>At the same time, it will change the motor state on the web page, and the gear will start spinning in the proper direction (<strong>2<\/strong>).<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Then, the server receives the message (<strong>4<\/strong>) and spins the motor accordingly (<strong>5<\/strong>).<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>When the motor stops spinning (<strong>6<\/strong>), the ESP will send a message to the client(s), also via WebSocket protocol, informing that the motor has stopped (<strong>7<\/strong>). <\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The client(s) receive this request and update the motor state on the web page (<strong>8<\/strong>).<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"organize-files\">Organizing your Files<\/h2>\n\n\n\n<p>The files you want to upload to the ESP filesystem should be placed in a folder called <span class=\"rnthl rntliteral\">data<\/span> under the project folder. We\u2019ll move three files to that folder:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span class=\"rnthl rntliteral\">index.html<\/span> to build the web page;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">style.css<\/span> to style the web page;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">script.js<\/span> to handle websocket communication and start\/stop the gear animation.<\/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 <span class=\"rnthl rntliteral\">data<\/span> 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_Stepper_Motor_Websocket\/ESP8266_Stepper_Motor_Websocket.zip\" target=\"_blank\" rel=\"noreferrer noopener\">Download All the Arduino 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>Create a file called <span class=\"rnthl rntliteral\">index.html<\/span> with the following content:<\/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;Stepper Motor&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;stylesheet&quot; type=&quot;text\/css&quot; href=&quot;style.css&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; href=&quot;https:\/\/use.fontawesome.com\/releases\/v5.7.2\/css\/all.css&quot; integrity=&quot;sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr&quot; crossorigin=&quot;anonymous&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;Stepper Motor Control &lt;i class=&quot;fas fa-cogs&quot;&gt;&lt;\/i&gt;&lt;\/h1&gt;\r\n  &lt;\/div&gt;\r\n  &lt;div class=&quot;content&quot;&gt;\r\n        &lt;form&gt;\r\n          &lt;input type=&quot;radio&quot; id=&quot;CW&quot; name=&quot;direction&quot; value=&quot;CW&quot; checked&gt;\r\n          &lt;label for=&quot;CW&quot;&gt;Clockwise&lt;\/label&gt;\r\n          &lt;input type=&quot;radio&quot; id=&quot;CCW&quot; name=&quot;direction&quot; value=&quot;CCW&quot;&gt;\r\n          &lt;label for=&quot;CW&quot;&gt;Counterclockwise&lt;\/label&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;\r\n          &lt;label for=&quot;steps&quot;&gt;Number of steps:&lt;\/label&gt;\r\n          &lt;input type=&quot;number&quot; id=&quot;steps&quot; name=&quot;steps&quot;&gt;\r\n        &lt;\/form&gt;\r\n        &lt;button onclick=&quot;submitForm()&quot;&gt;GO!&lt;\/button&gt;\r\n        &lt;p&gt;Motor state: &lt;span id=&quot;motor-state&quot;&gt;Stopped&lt;\/span&gt;&lt;\/p&gt;\r\n        &lt;p&gt;&lt;i id=&quot;gear&quot; class=&quot;fas fa-cog&quot;&gt;&lt;\/i&gt; &lt;\/p&gt;\r\n\r\n  &lt;\/div&gt;\r\n&lt;\/body&gt;\r\n&lt;script src=&quot;script.js&quot;&gt;&lt;\/script&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_Stepper_Motor_Websocket\/data\/index.html\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>This HTML file is very similar to the one used in <strong><a href=\"https:\/\/randomnerdtutorials.com\/stepper-motor-esp32-web-server\/\">this tutorial<\/a><\/strong>. You can <em><a href=\"https:\/\/randomnerdtutorials.com\/stepper-motor-esp32-web-server\/#html-form\">click here<\/a><\/em> for a complete explanation of the HTML file.<\/p>\n\n\n\n<p>We&#8217;ve added ids to the HTML elements we want to manipulate using JavaScript\u2014the radio buttons and the input field:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>clockwise radio button: <span class=\"rnthl rntliteral\">id=&#8221;CW&#8221;<\/span><\/li>\n\n\n\n<li>counterclowise radio button: <span class=\"rnthl rntliteral\">id=&#8221;CCW&#8221;<\/span><\/li>\n\n\n\n<li>steps input field: <span class=\"rnthl rntliteral\">id=&#8221;steps&#8221;<\/span><\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;input type=\"radio\" id=\"CW\" name=\"direction\" value=\"CW\" checked&gt;\n&lt;label for=\"CW\"&gt;Clockwise&lt;\/label&gt;\n&lt;input type=\"radio\" id=\"CCW\" name=\"direction\" value=\"CCW\"&gt;\n&lt;label for=\"CW\"&gt;Counterclockwise&lt;\/label&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;\n&lt;label for=\"steps\"&gt;Number of steps:&lt;\/label&gt;\n&lt;input type=\"number\" id=\"steps\" name=\"steps\"&gt;<\/code><\/pre>\n\n\n\n<p>We want to send the form results to the server (ESP8266) via WebSocket protocol. So, we&#8217;ve added a button, that when clicked (<span class=\"rnthl rntliteral\">onclick<\/span> event) calls the <span class=\"rnthl rntliteral\">submitForm()<\/span> user-defined javascript function that sends the results to the server as you&#8217;ll see later in the <a href=\"#javascript-file\">JavaScript section<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;button onclick=\"submitForm()\"&gt;GO!&lt;\/button&gt;<\/code><\/pre>\n\n\n\n<p>Additionally, we also added a paragraph to display the motor state. We&#8217;ve added a <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;span&gt;<\/span><\/span> tag with the <span class=\"rnthl rntliteral\">motor-state<\/span> id so that we&#8217;re able to manipulate the text between the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;span&gt;<\/span><\/span> tags using Javascript.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;p&gt;Motor state: &lt;span id=\"motor-state\"&gt;Stopped&lt;\/span&gt;&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>Finally, there&#8217;s a paragraph displaying a gear with the <span class=\"rnthl rntliteral\">id=&#8221;gear&#8221;<\/span>. We need this id to make the gear move.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;p&gt;&lt;i id=\"gear\" class=\"fas fa-cog\"&gt;&lt;\/i&gt; &lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>Don&#8217;t forget that you need to reference the JavaScript file (<span class=\"rnthl rntliteral\">scrip.js<\/span>) in the HTML file as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;script src=\"script.js\"&gt;&lt;\/script&gt;<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"css-file\">CSS File<\/h2>\n\n\n\n<p>Create a file called <span class=\"rnthl rntliteral\">style.css<\/span> with the following content:<\/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}\r\n\r\nh1 {\r\n  font-size: 1.8rem;\r\n  color: white;\r\n}\r\n\r\np{\r\n  font-size: 20px;\r\n  text-align: center;\r\n}\r\n\r\n.topnav {\r\n  overflow: hidden;\r\n  background-color: #0A1128;\r\n  text-align: center;\r\n}\r\n\r\nbody {\r\n  margin: 0;\r\n}\r\n\r\n.content {\r\n  padding: 20px;\r\n  max-width: max-content;\r\n  margin: 0 auto;\r\n}\r\n\r\ninput[type=number], select {\r\n  width: 100%;\r\n  padding: 12px 20px;\r\n  margin: 8px 0;\r\n  display: inline-block;\r\n  border: 1px solid #ccc;\r\n  border-radius: 4px;\r\n  box-sizing: border-box;\r\n}\r\n\r\nform{\r\n  border-radius: 5px;\r\n  background-color: #f2f2f2;\r\n  padding: 20px;\r\n}\r\n\r\nbutton {\r\n  background-color: #034078;\r\n  border: none;\r\n  padding: 14px 20px;\r\n  text-align: center;\r\n  font-size: 20px;\r\n  border-radius: 4px;\r\n  transition-duration: 0.4s;\r\n  width: 100%;\r\n  color: white;\r\n  cursor: pointer;\r\n}\r\n\r\nbutton:hover {\r\n    background-color: #1282A2;\r\n}\r\n\r\ninput[type=&quot;radio&quot;] {\r\n  -webkit-appearance: none;\r\n  -moz-appearance: none;\r\n  appearance: none;\r\n  border-radius: 50%;\r\n  width: 16px;\r\n  height: 16px;\r\n  border: 2px solid #999;\r\n  transition: 0.2s all linear;\r\n  margin-right: 5px;\r\n  position: relative;\r\n  top: 4px;\r\n  }\r\n\r\ninput[type=&quot;radio&quot;]:checked{\r\n  border: 6px solid #1282A2;\r\n}\r\n\r\n#motor-state{\r\n  font-weight: bold;\r\n  color: red;\r\n}\r\n\r\n#gear{\r\n  font-size:100px;\r\n  color:#2d3031cb;\r\n}\r\n\r\n.spin {\r\n  -webkit-animation:spin 4s linear infinite;\r\n  -moz-animation:spin 4s linear infinite;\r\n  animation:spin 4s linear infinite;\r\n}\r\n\r\n.spin-back {\r\n  -webkit-animation:spin-back 4s linear infinite;\r\n  -moz-animation:spin-back 4s linear infinite;\r\n  animation:spin-back 4s linear infinite;\r\n}\r\n\r\n@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }\r\n@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }\r\n@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }\r\n\r\n@-moz-keyframes spin-back { 100% { -moz-transform: rotate(-360deg); } }\r\n@-webkit-keyframes spin-back { 100% { -webkit-transform: rotate(-360deg); } }\r\n@keyframes spin-back { 100% { -webkit-transform: rotate(-360deg); transform:rotate(-360deg); } }\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_Stepper_Motor_Websocket\/data\/style.css\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>We already covered how the CSS for the HTML form works. You can <em><a href=\"https:\/\/randomnerdtutorials.com\/stepper-motor-esp32-web-server\/#stepper-web-server-html-form-css\">click here<\/a><\/em> for a detailed explanation. Let&#8217;s take a look at the relevant parts for this tutorial.<\/p>\n\n\n\n<p>We format the motor state text font-weight (<span class=\"rnthl rntliteral\">bold<\/span>) and color (<span class=\"rnthl rntliteral\">red<\/span>). To refer to a specific id in CSS, use <span class=\"rnthl rntliteral\">#<\/span> followed by the id (<span class=\"rnthl rntliteral\">#motor-state<\/span>).<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>#motor-state{\n  font-weight: bold;\n  color: red;\n}<\/code><\/pre>\n\n\n\n<p>The following lines format the gear icon color and size\u2014remember that its id is <span class=\"rnthl rntliteral\">gear<\/span>, so we refer to it with <span class=\"rnthl rntliteral\">#gear<\/span>:<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>#gear{\n  font-size:100px;\n  color:#2d3031cb;\n}<\/code><\/pre>\n\n\n\n<p>Then, we format two classes <span class=\"rnthl rntliteral\">spin<\/span> and <span class=\"rnthl rntliteral\">spin-back<\/span> that are not attributed to any HTML element yet. We&#8217;ll attribute the <span class=\"rnthl rntliteral\">spin<\/span> and <span class=\"rnthl rntliteral\">spin-back<\/span> classes to the gear using JavaScript when the motor starts moving.<\/p>\n\n\n\n<p>These classes use the <span class=\"rnthl rntliteral\">animation<\/span> property to rotate the gear. To learn more about how the <span class=\"rnthl rntliteral\">animation<\/span> property works, we recommend taking a look at <a href=\"https:\/\/css-tricks.com\/almanac\/properties\/a\/animation\/\" target=\"_blank\" rel=\"noreferrer noopener\">this quick tutorial<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>.spin {\n  -webkit-animation:spin 4s linear infinite;\n  -moz-animation:spin 4s linear infinite;\n  animation:spin 4s linear infinite;\n}\n\n.spin-back {\n  -webkit-animation:spin-back 4s linear infinite;\n  -moz-animation:spin-back 4s linear infinite;\n  animation:spin-back 4s linear infinite;\n}\n\n@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }\n@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }\n@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }\n\n@-moz-keyframes spin-back { 100% { -moz-transform: rotate(-360deg); } }\n@-webkit-keyframes spin-back { 100% { -webkit-transform: rotate(-360deg); } }\n@keyframes spin-back { 100% { -webkit-transform: rotate(-360deg); transform:rotate(-360deg); } }<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"javascript-file\">JavaScript File<\/h2>\n\n\n\n<p>Create a file called <span class=\"rnthl rntliteral\">script.js<\/span> with the following content:<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-javascript\">var gateway = `ws:\/\/${window.location.hostname}\/ws`;\r\nvar websocket;\r\nwindow.addEventListener('load', onload);\r\nvar direction;\r\n\r\nfunction onload(event) {\r\n    initWebSocket();\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\nfunction onOpen(event) {\r\n    console.log('Connection opened');\r\n}\r\n\r\nfunction onClose(event) {\r\n    console.log('Connection closed');\r\n    document.getElementById(&quot;motor-state&quot;).innerHTML = &quot;motor stopped&quot;\r\n    setTimeout(initWebSocket, 2000);\r\n}\r\n\r\nfunction submitForm(){\r\n    const rbs = document.querySelectorAll('input[name=&quot;direction&quot;]');\r\n    direction;\r\n    for (const rb of rbs) {\r\n        if (rb.checked) {\r\n            direction = rb.value;\r\n            break;\r\n        }\r\n    }\r\n\r\n    document.getElementById(&quot;motor-state&quot;).innerHTML = &quot;motor spinning...&quot;;\r\n    document.getElementById(&quot;motor-state&quot;).style.color = &quot;blue&quot;;\r\n    if (direction==&quot;CW&quot;){\r\n        document.getElementById(&quot;gear&quot;).classList.add(&quot;spin&quot;);\r\n    }\r\n    else{\r\n        document.getElementById(&quot;gear&quot;).classList.add(&quot;spin-back&quot;);\r\n    }\r\n    \r\n    var steps = document.getElementById(&quot;steps&quot;).value;\r\n    websocket.send(steps+&quot;&amp;&quot;+direction);\r\n}\r\n\r\nfunction onMessage(event) {\r\n    console.log(event.data);\r\n    direction = event.data;\r\n    if (direction==&quot;stop&quot;){ \r\n      document.getElementById(&quot;motor-state&quot;).innerHTML = &quot;motor stopped&quot;\r\n      document.getElementById(&quot;motor-state&quot;).style.color = &quot;red&quot;;\r\n      document.getElementById(&quot;gear&quot;).classList.remove(&quot;spin&quot;, &quot;spin-back&quot;);\r\n    }\r\n    else if(direction==&quot;CW&quot; || direction==&quot;CCW&quot;){\r\n        document.getElementById(&quot;motor-state&quot;).innerHTML = &quot;motor spinning...&quot;;\r\n        document.getElementById(&quot;motor-state&quot;).style.color = &quot;blue&quot;;\r\n        if (direction==&quot;CW&quot;){\r\n            document.getElementById(&quot;gear&quot;).classList.add(&quot;spin&quot;);\r\n        }\r\n        else{\r\n            document.getElementById(&quot;gear&quot;).classList.add(&quot;spin-back&quot;);\r\n        }\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_Stepper_Motor_Websocket\/data\/script.js\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Let&#8217;s see how the JavaScript for this project works.<\/p>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">gateway<\/span> 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>Create another global variable called <span class=\"rnthl rntliteral\">direction<\/span> that will hold the motor&#8217;s current direction: clockwise, counterclowise or stopped.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>var direction;<\/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 that will be triggered 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>When the connection is opened, print a message in the console for debugging purposes.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function onOpen(event) {\n  console.log('Connection opened');\n}<\/code><\/pre>\n\n\n\n<p>If for some reason the web socket connection is closed, call the <span class=\"rnthl rntliteral\">initWebSocket()<\/span> function again after 2000 milliseconds (2 seconds).<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function onClose(event) {\n  console.log('Connection closed');\n  setTimeout(initWebSocket, 2000);\n}<\/code><\/pre>\n\n\n\n<p>Finally, we need to handle what happens when the form is submitted and when the client receives a new message (<span class=\"rnthl rntliteral\">onMessage<\/span> event). <\/p>\n\n\n\n<p>When the form is submitted, the <span class=\"rnthl rntliteral\">submitForm()<\/span> function is called:<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function submitForm(){<\/code><\/pre>\n\n\n\n<p>We start by getting which radio button is selected. We save the value of the selected radio button in the <span class=\"rnthl rntliteral\">direction<\/span> variable.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>const rbs = document.querySelectorAll('input&#091;name=\"direction\"]');\nvar direction;\nfor (const rb of rbs) {\n  if (rb.checked) {\n    direction = rb.value;\n    break;\n  }\n}<\/code><\/pre>\n\n\n\n<p>Then, we change the motor state text to <span class=\"rnthl rntliteral\">motor spinning&#8230;<\/span> and its color to <span class=\"rnthl rntliteral\">blue<\/span>. We refer to that HTML element by its id <span class=\"rnthl rntliteral\">motor-state<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>document.getElementById(\"motor-state\").innerHTML = \"motor spinning...\";\ndocument.getElementById(\"motor-state\").style.color = \"blue\";<\/code><\/pre>\n\n\n\n<p>Then, we check whether we&#8217;ve selected clockwise or counterclockwise direction to spin the gear in the right direction. To do that, we add the class <span class=\"rnthl rntliteral\">spin<\/span> or <span class=\"rnthl rntliteral\">spin-back<\/span> to the element with the <span class=\"rnthl rntliteral\">gear<\/span> id.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>if (direction==\"CW\"){\n  document.getElementById(\"gear\").classList.add(\"spin\");\n}\nelse{\n  document.getElementById(\"gear\").classList.add(\"spin-back\");\n}<\/code><\/pre>\n\n\n\n<p>We get the number of steps inserted and save it in the <span class=\"rnthl rntliteral\">steps<\/span> variable.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>var steps = document.getElementById(\"steps\").value;<\/code><\/pre>\n\n\n\n<p>Then, we finally send a message via WebSocket protocol to the server (ESP8266) with the number of steps and direction separated by a <span class=\"rnthl rntliteral\">&amp;<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>websocket.send(steps+\"&amp;\"+direction);<\/code><\/pre>\n\n\n\n<p>The server (your ESP board) will send a message when it is time to change the motor state. When that happens, we save the message in the <span class=\"rnthl rntliteral\">direction<\/span> variable.<\/p>\n\n\n\n<p>We check the content of the message and change the motor state and gear animation accordingly.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function onMessage(event) {\n  console.log(event.data);\n  direction = event.data;\n  if (direction==\"stop\"){ \n    document.getElementById(\"motor-state\").innerHTML = \"motor stopped\"\n    document.getElementById(\"motor-state\").style.color = \"red\";\n    document.getElementById(\"gear\").classList.remove(\"spin\", \"spin-back\");\n  }\n  else if(direction==\"CW\" || direction==\"CCW\"){\n    document.getElementById(\"motor-state\").innerHTML = \"motor spinning...\";\n    document.getElementById(\"motor-state\").style.color = \"blue\";\n    if (direction==\"CW\"){\n      document.getElementById(\"gear\").classList.add(\"spin\");\n    }\n    else{\n      document.getElementById(\"gear\").classList.add(\"spin-back\");\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"arduino-sketch\">Arduino Sketch<\/h2>\n\n\n\n<p>Before uploading, you can use the following link to:<\/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_Stepper_Motor_Websocket\/ESP8266_Stepper_Motor_Websocket.zip\" target=\"_blank\" rel=\"noreferrer noopener\">Download All the Arduino Project Files<\/a><\/strong><\/li>\n<\/ul>\n\n\n\n<p>Copy the following code to the Arduino IDE. Insert your network credentials and it will work straight away.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\r\n  Rui Santos\r\n  Complete project details at https:\/\/RandomNerdTutorials.com\/stepper-motor-esp8266-websocket\/\r\n  \r\n  Permission is hereby granted, free of charge, to any person obtaining a copy\r\n  of this software and associated documentation files.\r\n  \r\n  The above copyright notice and this permission notice shall be included in all\r\n  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;ESPAsyncWebServer.h&gt;\r\n#include &quot;LittleFS.h&quot;\r\n#include &lt;AccelStepper.h&gt;\r\n\r\n#define IN1 5\r\n#define IN2 4\r\n#define IN3 14\r\n#define IN4 12\r\nAccelStepper stepper(AccelStepper::HALF4WIRE, IN1, IN3, IN2, IN4);\r\n\r\nString message = &quot;&quot;;\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\/\/Variables to save values from HTML form\r\nString direction =&quot;STOP&quot;;\r\nString steps;\r\n\r\nbool notifyStop = false;\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 state) {\r\n  ws.textAll(state);\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    message = (char*)data;\r\n    steps = message.substring(0, message.indexOf(&quot;&amp;&quot;));\r\n    direction = message.substring(message.indexOf(&quot;&amp;&quot;)+1, message.length());\r\n    Serial.print(&quot;steps&quot;);\r\n    Serial.println(steps);\r\n    Serial.print(&quot;direction&quot;);\r\n    Serial.println(direction);\r\n    notifyClients(direction);\r\n    notifyStop = true;\r\n    if (direction == &quot;CW&quot;){\r\n      Serial.print(&quot;CW&quot;);\r\n      stepper.move(steps.toInt());\r\n    }\r\n    else{\r\n      Serial.print(&quot;CCW&quot;);\r\n      stepper.move(-steps.toInt());\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      \/\/Notify client of motor current state when it first connects\r\n      notifyClients(direction);\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 port for debugging purposes\r\n\r\n  Serial.begin(115200);\r\n  initWiFi();\r\n  initWebSocket();\r\n  initFS();\r\n  stepper.setMaxSpeed(1000);\r\n  stepper.setAcceleration(100);\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  server.begin();\r\n}\r\n\r\nvoid loop() {\r\n  if (stepper.distanceToGo() == 0 &amp;&amp; notifyStop == true){  \r\n    direction = &quot;stop&quot;;\r\n    notifyClients(direction);\r\n    notifyStop = false;\r\n  }\r\n  ws.cleanupClients();\r\n  stepper.run();\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_Stepper_Motor_Websocket\/ESP8266_Stepper_Motor_Websocket.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>The Arduino sketch is very similar to<a href=\"https:\/\/randomnerdtutorials.com\/stepper-motor-esp32-web-server\/\"> this tutorial<\/a>, but it handles the client-server communication using WebSocket protocol. Let&#8217;s see how it works or skip to the <a href=\"#demonstration\">demonstration section<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Include Libraries<\/h3>\n\n\n\n<p>First, include the required libraries. The <span class=\"rnthl rntliteral\">ESP8266WiFi<\/span>, <span class=\"rnthl rntliteral\">ESPAsyncTCP<\/span>, and <span class=\"rnthl rntliteral\">ESPAsyncWebServer<\/span> to create the web server, the <span class=\"rnthl rntliteral\">LittleFS<\/span> library to use the ESP8266 filesystem, and the <span class=\"rnthl rntliteral\">AccelStepper<\/span> library to control the stepper motor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;Arduino.h&gt;\n#include &lt;ESP8266WiFi.h&gt;\n#include &lt;ESPAsyncWebServer.h&gt;\n#include &lt;<span class=\"rnthl rntliteral\">ESPAsyncTCP<\/span>.h&gt;\n#include \"LittleFS.h\"\n#include &lt;AccelStepper.h&gt;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Stepper Motor Pins<\/h3>\n\n\n\n<p>Define the motor input pins. In this example, we&#8217;re connecting to GPIOs 5, 4, 14, and 12, but you can use any other suitable GPIOs.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define IN1 5\n#define IN2 4\n#define IN3 14\n#define IN4 12<\/code><\/pre>\n\n\n\n<p>Initialize an instance of the AccelStepper library called <span class=\"rnthl rntliteral\">stepper<\/span>. Pass as arguments: <span class=\"rnthl rntliteral\">AccelStepper::HALF4WIRE<\/span> to indicate we&#8217;re controlling the stepper motor with four wires, and the input pins. In the case of the 28BYJ-48 stepper motor, the order of the pins is <span class=\"rnthl rntliteral\">IN1<\/span>, <span class=\"rnthl rntliteral\">IN3<\/span>, <span class=\"rnthl rntliteral\">IN2<\/span>, <span class=\"rnthl rntliteral\">IN4<\/span>\u2014it might be different for your motor. <\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Stepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4);<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Network Credentials<\/h3>\n\n\n\n<p>Insert your network credentials in the following lines.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Replace with your network credentials\nconst char* ssid = \"REPLACE_WITH_YOUR_SSID\";\nconst char* password = \"REPLACE_WITH_YOUR_PASSWORD\";<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">AsyncWebServer and AsyncWebSocket<\/h3>\n\n\n\n<p>Create an <span class=\"rnthl rntliteral\">AsyncWebServer<\/span> object called <span class=\"rnthl rntliteral\">server<\/span> 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 <span class=\"rnthl rntliteral\">ESPAsyncWebServer<\/span> library includes a WebSocket plugin that makes it easy to handle WebSocket connections. Create an <span class=\"rnthl rntliteral\">AsyncWebSocket<\/span> object called <span class=\"rnthl rntliteral\">ws<\/span> to handle the connections on the <span class=\"rnthl rntliteral\">\/ws<\/span> path.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>AsyncWebSocket ws(\"\/ws\");<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Initializing Variables<\/h3>\n\n\n\n<p>The following variables will save the direction and number of steps received via WebSocket protocol. When the program first starts, the motor is stopped.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>String direction =\"stop\";\nString steps;<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">notifyStop<\/span> variable will be used to check whether the motor has reached its desired position and notify all clients that the motor is stopped.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>bool notifyStop = false;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">initFS()<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">initFS()<\/span> function initializes the ESP8266 filesystem (littleFS).<\/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<h3 class=\"wp-block-heading\">initWiFi()<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">initWiFi()<\/span> function initializes WiFi.<\/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<h3 class=\"wp-block-heading\">Handling WebSockets &#8211; Server<\/h3>\n\n\n\n<p>Previously, you&#8217;ve seen how to handle the WebSocket connection on the client side (browser). Now, let&#8217;s take a look on how to handle it on the server side.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Notify All Clients<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">notifyClients()<\/span> function notifies all clients with a message containing whatever you pass as a argument. In this case, we&#8217;ll want to notify all clients of the current motor state whenever there&#8217;s a change.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void notifyClients(String state) {\n  ws.textAll(state);\n}<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">AsyncWebSocket<\/span> class provides a <span class=\"rnthl rntliteral\">textAll()<\/span> method for sending the same message to all clients that are connected to the server at the same time.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Handle WebSocket Messages<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">handleWebSocketMessage()<\/span> function is a callback function that will run whenever we receive new data from the clients via WebSocket protocol.<\/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    message = (char*)data;\n    steps = message.substring(0, message.indexOf(\"&amp;\"));\n    direction = message.substring(message.indexOf(\"&amp;\")+1, message.length());\n    Serial.print(\"steps\");\n    Serial.println(steps);\n    Serial.print(\"direction\");\n    Serial.println(direction);\n    notifyClients(direction);\n    notifyStop = true;\n    if (direction == \"CW\"){\n      Serial.print(\"CW\");\n      stepper.move(steps.toInt());\n    }\n    else{\n      Serial.print(\"CCW\");\n      stepper.move(-steps.toInt());\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>We split the message to get the number of steps and direction. <\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>message = (char*)data;\nsteps = message.substring(0, message.indexOf(\"&amp;\"));\ndirection = message.substring(message.indexOf(\"&amp;\")+1, message.length());<\/code><\/pre>\n\n\n\n<p>Then, we notify all clients of the motor direction so that all clients change the motor state on the web interface.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>notifyClients(direction);<\/code><\/pre>\n\n\n\n<p>We set the <span class=\"rnthl rntliteral\">notifyStop<\/span> variable to <span class=\"rnthl rntliteral\">true<\/span> so that we&#8217;re able to notify that the motor has stopped later on.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>notifyStop = true;<\/code><\/pre>\n\n\n\n<p>Then, set the number of steps you want the motor to move depending on the direction (negative number of steps for counterclockwise direction and a positive number of steps for clockwise direction). For that, we use the <span class=\"rnthl rntliteral\">move()<\/span> function. The <span class=\"rnthl rntliteral\">move()<\/span> function doesn&#8217;t actually move the motor, it simply sets the new number of steps we want to move the motor. The motor will then go to the desired position one step at a time using the <span class=\"rnthl rntliteral\">run()<\/span> function in the <span class=\"rnthl rntliteral\">loop()<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (direction == \"CW\"){\n  Serial.print(\"CW\");\n  stepper.move(steps.toInt());\n}\nelse{\n  Serial.print(\"CCW\");\n  stepper.move(-steps.toInt());\n}<\/code><\/pre>\n\n\n\n<p><strong>Note: <\/strong> the <span class=\"rnthl rntliteral\">move()<\/span> function sets the target position relative to the current position. The <span class=\"rnthl rntliteral\">moveTo()<\/span> function sets the absolute target position (each position is defined by a predetermined number of steps). For more information <a href=\"https:\/\/www.airspayce.com\/mikem\/arduino\/AccelStepper\/classAccelStepper.html#a68942c66e78fb7f7b5f0cdade6eb7f06\" target=\"_blank\" rel=\"noreferrer noopener\">check the library documentation.<\/a><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Configure the WebSocket server<\/h4>\n\n\n\n<p>Now we need to configure an event listener to handle the different asynchronous steps of the WebSocket protocol. This event handler can be implemented by defining the <span class=\"rnthl rntliteral\">onEvent()<\/span> as follows:<\/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      \/\/Notify client of motor current state when it first connects\n      notifyClients(direction);\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<p>The <span class=\"rnthl rntliteral\">type<\/span> argument represents the event that occurs. It can take the following values:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span class=\"rnthl rntliteral\">WS_EVT_CONNECT<\/span> when a client has logged in;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">WS_EVT_DISCONNECT<\/span> when a client has logged out;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">WS_EVT_DATA<\/span> when a data packet is received from the client;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">WS_EVT_PONG<\/span> in response to a ping request;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">WS_EVT_ERROR<\/span> when an error is received from the client.<\/li>\n<\/ul>\n\n\n\n<p>There&#8217;s a section to notify any client of the current motor state when it first connects:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>case WS_EVT_CONNECT:\n  Serial.printf(\"WebSocket client #%u connected from %s\\n\", client-&gt;id(), client-&gt;remoteIP().toString().c_str());\n  \/\/Notify client of motor current state when it first connects\n  notifyClients(direction);\n  break;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Initialize WebSocket<\/h4>\n\n\n\n<p>Finally, 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<h3 class=\"wp-block-heading\">setup()<\/h3>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, initialize the Serial Monitor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.begin(115200);<\/code><\/pre>\n\n\n\n<p>Call the <span class=\"rnthl rntliteral\">initWiFi()<\/span> function to initialize WiFi.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>initWiFi();<\/code><\/pre>\n\n\n\n<p>Initialize websocket communication.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>initWebSocket();<\/code><\/pre>\n\n\n\n<p>Call the <span class=\"rnthl rntliteral\">initFS()<\/span> function to initialize the filesystem.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>initFS();<\/code><\/pre>\n\n\n\n<p>And set the stepper motor maximum speed and acceleration.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>stepper.setMaxSpeed(1000);\nstepper.setAcceleration(100);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Handle requests<\/h4>\n\n\n\n<p>Then, handle the web server. When you receive a request on the root (<span class=\"rnthl rntliteral\">\/<\/span>) URL\u2014this is when you access the ESP IP address\u2014 send the HTML text to build the web page:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/\", HTTP_GET, &#091;](AsyncWebServerRequest *request){\n  request-&gt;send(LittleFS, \"\/index.html\", \"text\/html\");\n});<\/code><\/pre>\n\n\n\n<p>When the HTML file loads on your browser, it will make a request for the CSS and JavaScript files. These are static files saved on the same directory (LittleFS). So, we can simply add the following line to serve files in a directory when requested by the root URL. It will serve the CSS and JavaScript files automatically.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.serveStatic(\"\/\", LittleFS, \"\/\");<\/code><\/pre>\n\n\n\n<p>Finally, start the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.begin();<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">loop()<\/h3>\n\n\n\n<p>Let&#8217;s take a look at the <span class=\"rnthl rntliteral\">loop()<\/span> section.<\/p>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">loop()<\/span> is where the motor moves one step at a time using the <span class=\"rnthl rntliteral\">run()<\/span> function. This function makes the motor move until it reaches its desired position (set by the <span class=\"rnthl rntliteral\">move()<\/span> function)).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>stepper.run();<\/code><\/pre>\n\n\n\n<p>Additionally, there&#8217;s an if statement to check if we need to notify the clients that the motor has stopped. The <span class=\"rnthl rntliteral\">distanceToGo()<\/span> function returns how many steps are left until we reach the desired position. So, when it returns <span class=\"rnthl rntliteral\">0<\/span>, it means the motor has stopped. We also check if the <span class=\"rnthl rntliteral\">notifyStop<\/span> variable is <span class=\"rnthl rntliteral\">true<\/span> (it means the motor was spinning previously).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (stepper.distanceToGo() == 0 &amp;&amp; notifyStop == true){  \n  direction = \"stop\";\n  notifyClients(direction);\n  notifyStop = false;\n}<\/code><\/pre>\n\n\n\n<p>When these conditions are met, we notify the clients the motor has stopped.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>direction = \"stop\";\nnotifyClients(direction);<\/code><\/pre>\n\n\n\n<p>Finally, set the <span class=\"rnthl rntliteral\">notifyStop<\/span> variable to <span class=\"rnthl rntliteral\">false<\/span>. It will only be <span class=\"rnthl rntliteral\">true<\/span> again if the board receives a request to move the motor.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"upload-code-files\">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\">\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 save 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\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"30\" height=\"30\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/05\/arduino-2-0-upload-button.png?resize=30%2C30&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Arduino 2.0 Upload Button\" class=\"wp-image-103678\"\/><\/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 web browser or multiple web browser windows on your local network and you&#8217;ll access the web page to control the motor. Submit the form to control the motor.<\/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=\"300\" height=\"609\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP32-Stepper-Motor-Web-Server-Websocketsl.jpg?resize=300%2C609&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU Stepper Motor Web Server Websocket Motor Spinning\" class=\"wp-image-105671\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP32-Stepper-Motor-Web-Server-Websocketsl.jpg?w=300&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP32-Stepper-Motor-Web-Server-Websocketsl.jpg?resize=148%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 148w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/figure><\/div>\n\n\n<p>The gear on the web page starts spinning in the right direction and the physical motor starts working.<\/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=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/28BYJ-48-connected-to-ULN2003-Motor-Driver-01-module.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"28BYJ-48 connected to ULN2003 Motor Driver 01 module\" class=\"wp-image-105430\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/28BYJ-48-connected-to-ULN2003-Motor-Driver-01-module.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/28BYJ-48-connected-to-ULN2003-Motor-Driver-01-module.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>When it stops, the gear on the web page and the motor state change accoridngly.<\/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=\"300\" height=\"608\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP32-Stepper-Motor-Web-Server-Websockets-motor-stopped.jpg?resize=300%2C608&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU Stepper Motor Web Server Websocket Motor Stopped\" class=\"wp-image-105672\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP32-Stepper-Motor-Web-Server-Websockets-motor-stopped.jpg?w=300&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP32-Stepper-Motor-Web-Server-Websockets-motor-stopped.jpg?resize=148%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 148w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/figure><\/div>\n\n\n<p>Notice that if you have multiple clients connect, all clients update the motor state almost instantaneously.<\/p>\n\n\n\n<p> Watch the video below for a live demonstration. <\/p>\n\n\n<div style=\"text-align:center\"><iframe src=\"https:\/\/player.vimeo.com\/video\/592192788?color=ff9933&title=1&byline=0&portrait=0\" width=\"720\" height=\"405\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen><\/iframe><\/div><\/br>\n\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 control a stepper motor using a web server built with the ESP8266. The web server provides a web page to control the stepper motor using a form whose results are sent to the ESP8266 via WebSocket protocol.<\/p>\n\n\n\n<p>If you want to learn more about HTML, CSS, JavaScript, and client-server communication protocols to build your ESP32 and ESP8266 web servers from scratch as we&#8217;ve done in this tutorial, make sure you take 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\/\">Build Web Servers with ESP32 and ESP8266<\/a><\/li>\n<\/ul>\n\n\n\n<p>Check the following resources to learn more about the ESP8266 board:<\/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\/projects-esp8266\/\">More ESP8266 Projects and Tutorials\u2026<\/a><\/li>\n<\/ul>\n\n\n\n<p>We hope you find this tutorial useful.<\/p>\n\n\n\n<p>Thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide, you&#8217;ll learn how to create a web server with the ESP8266 NodeMCU board that displays a web page to control a stepper motor. The web page allows &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP8266 NodeMCU Web Server: Control Stepper Motor (WebSocket)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/stepper-motor-esp8266-websocket\/#more-106154\" aria-label=\"Read more about ESP8266 NodeMCU Web Server: Control Stepper Motor (WebSocket)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":1,"featured_media":106155,"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,246,300,240],"tags":[],"class_list":["post-106154","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp8266","category-esp8266-arduino-ide","category-0-esp8266","category-esp8266-projects"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/08\/ESP8266-Stepper-Motor-Web-Server-Websocket.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\/106154","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\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=106154"}],"version-history":[{"count":13,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/106154\/revisions"}],"predecessor-version":[{"id":168058,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/106154\/revisions\/168058"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/106155"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=106154"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=106154"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=106154"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}