{"id":105501,"date":"2021-10-06T16:52:12","date_gmt":"2021-10-06T16:52:12","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=105501"},"modified":"2025-03-14T16:13:03","modified_gmt":"2025-03-14T16:13:03","slug":"stepper-motor-esp32-web-server","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/stepper-motor-esp32-web-server\/","title":{"rendered":"ESP32 Web Server: Control Stepper Motor (HTML Form)"},"content":{"rendered":"\n<p>In this tutorial, you&#8217;ll learn how to create a web server with the ESP32 to control a stepper motor remotely. The web server displays a web page with an HTML form that allows you to select the direction and number of steps you want the motor to move.<\/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\/07\/Control-Stepper-Motor-ESP32-Web-Server-HTML-Forml.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Control Stepper Motor with ESP32 Web Server HTML Form Arduino IDE\" class=\"wp-image-105615\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/Control-Stepper-Motor-ESP32-Web-Server-HTML-Forml.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/Control-Stepper-Motor-ESP32-Web-Server-HTML-Forml.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/Control-Stepper-Motor-ESP32-Web-Server-HTML-Forml.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/Control-Stepper-Motor-ESP32-Web-Server-HTML-Forml.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<h2 class=\"wp-block-heading\">Table of Contents<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"#stepper-web-server-html-form\">Control Stepper Motor with HTML Form (minimal setup)<\/a><\/li>\n\n\n\n<li><a href=\"#stepper-web-server-html-form-css\">Control Stepper Motor with HTML Form + CSS (using LittleFS)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/stepper-motor-esp32-websocket\/\">Control Stepper Motor with WebSockets (HTML, CSS, JavaScript)<\/a><\/li>\n<\/ol>\n\n\n\n<p>In the picture below, you can see the three web server projects we&#8217;ll build (number 3 is in <a href=\"https:\/\/randomnerdtutorials.com\/stepper-motor-esp32-websocket\/\">this post<\/a>). <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"471\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/stepper-web-server-all-web-server-projects.jpg?resize=750%2C471&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Control Stepper Motor with ESP32 Web Server HTML Form Arduino IDE\" class=\"wp-image-105599\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/stepper-web-server-all-web-server-projects.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/stepper-web-server-all-web-server-projects.jpg?resize=300%2C188&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>This is a didactic tutorial where you&#8217;ll learn more about creating web pages and interaction between the ESP32 and the client. We&#8217;ll show you how to create the web page step-by-step with HTML and send the form results to the ESP32 via HTTP POST to control the stepper motor.<\/p>\n\n\n\n<p>Later, you&#8217;ll add some CSS to style the web page to improve its look.<\/p>\n\n\n\n<p>Finally, we&#8217;ll show you how to use Websockets for bidirectional communication between the server and the client. This will allow us to know on the web interface whether the motor is spinning or stopped. This section will add some JavaScript to handle WebSocket communication and add some cool animations to the web page.<\/p>\n\n\n\n<p>The following articles might be useful to understand the concepts covered throughout this tutorial:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-stepper-motor-28byj-48-uln2003\/\">ESP32 with Stepper Motor (28BYJ-48 and ULN2003 Motor Driver)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-input-data-html-form\/\">Input Data on HTML Form ESP32\/ESP8266 Web Server using Arduino IDE<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-websocket-server-arduino\/\">ESP32 WebSocket Server: Control Outputs (Arduino IDE)<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">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\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32&nbsp;<\/a>(read&nbsp;<a href=\"https:\/\/makeradvisor.com\/esp32-development-boards-review-comparison\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP32 Development Boards<\/a>)<\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/28byj-48-stepper-motor-uln2003\/\" target=\"_blank\" rel=\"noreferrer noopener\">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 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 filesystem (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 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 these libraries in the Arduino Library Manager. Open the Library Manager by clicking the Library icon at the left sidebar.<\/p>\n\n\n\n<p>Search for <span class=\"rnthl rntliteral\">ESPAsyncWebServer<\/span> and install the <strong>ESPAsyncWebServer by ESP32Async<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"666\" height=\"586\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-ESPAsyncWebServer-Library-ArduinoIDE-2-f.png?resize=666%2C586&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Installing ESPAsyncWebServer ESP32 Arduino IDE\" class=\"wp-image-167890\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-ESPAsyncWebServer-Library-ArduinoIDE-2-f.png?w=666&amp;quality=100&amp;strip=all&amp;ssl=1 666w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-ESPAsyncWebServer-Library-ArduinoIDE-2-f.png?resize=300%2C264&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 666px) 100vw, 666px\" \/><\/figure><\/div>\n\n\n<p>Then, install the AsyncTCP library. Search for <span class=\"rnthl rntliteral\">AsyncTCP<\/span> and install the <strong>AsyncTCP by ESP32Async<\/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=\"722\" height=\"586\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-AsyncTCP-Library-ArduinoIDE.png?resize=722%2C586&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Installing AsyncTCP ESP32 Arduino IDE\" class=\"wp-image-167886\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-AsyncTCP-Library-ArduinoIDE.png?w=722&amp;quality=100&amp;strip=all&amp;ssl=1 722w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-AsyncTCP-Library-ArduinoIDE.png?resize=300%2C243&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 722px) 100vw, 722px\" \/><\/figure><\/div>\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 ESP32.<\/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=\"1200\" height=\"631\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Schematic-Diagram-Wiring_bb.png?resize=1200%2C631&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 with Stepper Motor 28BYJ-48 and ULN2003A Schematic Diagram Wiring\" class=\"wp-image-105354\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Schematic-Diagram-Wiring_bb.png?w=1296&amp;quality=100&amp;strip=all&amp;ssl=1 1296w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Schematic-Diagram-Wiring_bb.png?resize=300%2C158&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Schematic-Diagram-Wiring_bb.png?resize=1024%2C538&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Schematic-Diagram-Wiring_bb.png?resize=768%2C404&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntcred\"><strong>Note: <\/strong> You should power the 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>ESP32<\/strong><\/td><\/tr><tr><td>IN1<\/td><td><span class=\"rnthl rntcblue\">GPIO 19<\/span><\/td><\/tr><tr><td>IN2<\/td><td><span class=\"rnthl rntcyellow\">GPIO 18<\/span><\/td><\/tr><tr><td>IN3<\/td><td><span class=\"rnthl rntcgreen\">GPIO 5<\/span><\/td><\/tr><tr><td>IN4<\/td><td><span class=\"rnthl rntcgray\">GPIO 17<\/span><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"stepper-web-server-html-form\">1. Control Stepper Motor with HTML Form<\/h2>\n\n\n\n<p>In this section, you&#8217;ll learn how to create a simple HTML form to control the stepper 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=\"640\" height=\"351\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-ESP8266-Stepper-motor-web-server-HTML-form-simple.png?resize=640%2C351&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 Stepper Motor Control Web Server HTML Form\" class=\"wp-image-105512\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-ESP8266-Stepper-motor-web-server-HTML-form-simple.png?w=640&amp;quality=100&amp;strip=all&amp;ssl=1 640w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-ESP8266-Stepper-motor-web-server-HTML-form-simple.png?resize=300%2C165&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/figure><\/div>\n\n\n<p>Here&#8217;s how it works:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>On the web page, you can select whether you want the motor to turn <strong>Clockwise <\/strong>or <strong>Counterclockwise<\/strong>. Those are <em>radio buttons<\/em>. Radio buttons are usually displayed as small circles, which are filled or highlighted when selected. You can only select one radio button in a given group at a time. <\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>There is an input field of type <em>number <\/em>where the user can enter a number\u2014in this case, the number of steps.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Finally, a button called <span class=\"rnthl rntliteral\">GO!<\/span> of type <em>submit <\/em>sends the data to the server via an HTTP POST request.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"html-form\">HTML Form and Input Fields<\/h3>\n\n\n\n<p>In this section, we&#8217;ll take a look at the HTML to build the form.<\/p>\n\n\n\n<p>In HTML, the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;form&gt;<\/span><\/span> tag is used to create an HTML form to collect user input. The user input is then sent to the server (ESP32 or ESP8266) for processing. Based on the values collected on the form, your ESP board may perform different actions\u2014in this case, spin the motor a determined number of steps.<\/p>\n\n\n\n<p>Here&#8217;s the HTML we&#8217;ll use for this project.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n  &lt;title&gt;Stepper Motor&lt;\/title&gt;\n  &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;h1&gt;Stepper Motor Control&lt;\/h1&gt;\n    &lt;form action=\"\/\" method=\"POST\"&gt;\n\n      &lt;input type=\"radio\" name=\"direction\" value=\"CW\" checked&gt;\n      &lt;label for=\"CW\"&gt;Clockwise&lt;\/label&gt;\n\n      &lt;input type=\"radio\" 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\n      &lt;label for=\"steps\"&gt;Number of steps:&lt;\/label&gt;\n      &lt;input type=\"number\" name=\"steps\"&gt;\n\n      &lt;input type=\"submit\" value=\"GO!\"&gt;\n\n    &lt;\/form&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/code><\/pre>\n\n\n\n<p>An HTML form contains different form elements. All form elements are enclosed inside the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;form&gt;<\/span><\/span> tag. It contains controls <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;input&gt;<\/span><\/span> (radio buttons and number input field) and labels for those controls (<span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;label&gt;<\/span><\/span>).<\/p>\n\n\n\n<p>Additionally, the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;form&gt;<\/span><\/span> tag must include the <span class=\"rnthl rntliteral\">action<\/span> attribute that specifies what you want to do when the form is submitted. In our case, we want to send that data to the server (ESP32\/ESP8266) when the user clicks the <strong>submit<\/strong> button. The <span class=\"rnthl rntliteral\">method<\/span> attribute specifies the HTTP method (GET or POST) used when submitting the form data.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;form action=\"\/\" method=\"POST\"&gt;<\/code><\/pre>\n\n\n\n<p>POST is used to send data to a server to create\/update a resource. The data sent to the server with POST is stored in the body of the HTTP request.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Radio Buttons<\/h4>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"249\" height=\"48\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/html-radio-bottons-stepper-motor-control.png?resize=249%2C48&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"HTML Radio Buttons Control Stepper Motor Web Server ESP32 ESP8266\" class=\"wp-image-105601\"\/><\/figure><\/div>\n\n\n<p>A radio button is defined as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;input type=\"radio\"&gt;<\/code><\/pre>\n\n\n\n<p>For our project, we need two radio buttons, and only one can be selected at a time. So, we can create a group of radio buttons. To do that, the radio buttons must share the same name (the value of the <span class=\"rnthl rntliteral\">name<\/span> attribute\u2014in this case <span class=\"rnthl rntliteral\">direction<\/span>).<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;input type=\"radio\" name=\"direction\"&gt;<\/code><\/pre>\n\n\n\n<p>Finally, we also need the <span class=\"rnthl rntliteral\">value<\/span> attribute that specifies a unique value for each radio button. This value is not visible to the user, but it is sent to the server when you click on the submit button to identify which button was selected.<\/p>\n\n\n\n<p>In our example, we created one radio button with the value <span class=\"rnthl rntliteral\">CW<\/span> (to select clockwise) and another <span class=\"rnthl rntliteral\">CCW<\/span> (to select counterclockwise).<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;input type=\"radio\" name=\"direction\" value=\"CW\"&gt;<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;input type=\"radio\" name=\"direction\" value=\"CCW\"&gt;<\/code><\/pre>\n\n\n\n<p>Finally, if you want one radio button to be selected by default, you can add the keyword <span class=\"rnthl rntliteral\">checked<\/span>. In our example, the clockwise direction is selected by default.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;input type=\"radio\" name=\"direction\" value=\"CW\" checked&gt;<\/code><\/pre>\n\n\n\n<p>So, this is how the radio buttons and corresponding labels look like:<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;input type=\"radio\" name=\"direction\" value=\"CW\" checked&gt;\n&lt;label for=\"CW\"&gt;Clockwise&lt;\/label&gt;\n\n&lt;input type=\"radio\" name=\"direction\" value=\"CCW\"&gt;\n&lt;label for=\"CW\"&gt;Counterclockwise&lt;\/label&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Input Field<\/h4>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"364\" height=\"33\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/Number-Input-Field-HTML-Form-Control-Stepper-Motor.png?resize=364%2C33&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Number Input Field HTML Form Stepper Motor Web Server ESP32 ESP8266\" class=\"wp-image-105602\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/Number-Input-Field-HTML-Form-Control-Stepper-Motor.png?w=364&amp;quality=100&amp;strip=all&amp;ssl=1 364w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/Number-Input-Field-HTML-Form-Control-Stepper-Motor.png?resize=300%2C27&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 364px) 100vw, 364px\" \/><\/figure><\/div>\n\n\n<p>Finally, we also need an input field where the user enters the number of steps\u2014an input field of type <span class=\"rnthl rntliteral\">number<\/span>. The <span class=\"rnthl rntliteral\">name<\/span> attribute allows us to determine in which input field the user entered the data.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;input type=\"number\" name=\"steps\"&gt;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Submit Button<\/h4>\n\n\n\n<p>To complete the form, we need a submit button. A submit button is an input of type <span class=\"rnthl rntliteral\">submit<\/span>. When you click this button, the form&#8217;s data is sent to the server (the ESP32 or ESP8266 boards). The <span class=\"rnthl rntliteral\">value<\/span> attribute specifies the text to display on the button.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;input type=\"submit\" value=\"GO!\"&gt;<\/code><\/pre>\n\n\n\n<p>For example, if you select the clockwise direction and enter 2000 steps, the client will make the following request to the ESP:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>POST \/\nHost: localhost\n<strong>direction<\/strong>=CW&amp;<strong>steps<\/strong>=2000<\/code><\/pre>\n\n\n\n<p>The ESP receives this request and can get the direction and number of steps from the body of the request.<\/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=\"869\" height=\"363\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-ESP8266-Web-Server-Control-Stepper-HTML-Form-How-it-Works.png?resize=869%2C363&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 Web-Server Control Stepper HTML Form How it Works\" class=\"wp-image-105606\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-ESP8266-Web-Server-Control-Stepper-HTML-Form-How-it-Works.png?w=869&amp;quality=100&amp;strip=all&amp;ssl=1 869w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-ESP8266-Web-Server-Control-Stepper-HTML-Form-How-it-Works.png?resize=300%2C125&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-ESP8266-Web-Server-Control-Stepper-HTML-Form-How-it-Works.png?resize=768%2C321&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 869px) 100vw, 869px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<p>Now that you know how to create the HTML form, let&#8217;s go through the Arduino code.<\/p>\n\n\n\n<p>The HTML text can be saved on an HTML file saved on the <a href=\"https:\/\/randomnerdtutorials.com\/arduino-ide-2-install-esp32-littlefs\/\" title=\"\">ESP32 filesystem (LittleFS)<\/a> or it can be saved in a variable in your Arduino sketch.<\/p>\n\n\n\n<p>Because the HTML text for this example is relatively simple and we don&#8217;t have CSS or JavaScript files, we&#8217;ll save the HTML text as a variable (<span class=\"rnthl rntliteral\">index_html<\/span>).<\/p>\n\n\n\n<p>Here&#8217;s the code to build the web server (insert your network credentials and the code will work straight away).<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  Complete project details at https:\/\/RandomNerdTutorials.com\/stepper-motor-esp32-web-server\/\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\/\n#include &lt;Arduino.h&gt;\n#include &lt;WiFi.h&gt;\n#include &lt;AsyncTCP.h&gt;\n#include &lt;ESPAsyncWebServer.h&gt;\n#include &lt;Stepper.h&gt;\n\n\/\/ Stepper Motor Settings\nconst int stepsPerRevolution = 2048;  \/\/ change this to fit the number of steps per revolution\n#define IN1 19\n#define IN2 18\n#define IN3 5\n#define IN4 17\nStepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4);\n\n\/\/ Replace with your network credentials\nconst char* ssid = &quot;REPLACE_WITH_YOUR_SSID&quot;;\nconst char* password = &quot;REPLACE_WITH_YOUR_PASSWORD&quot;;\n\n\/\/ Create AsyncWebServer object on port 80\nAsyncWebServer server(80);\n\n\/\/ Search for parameters in HTTP POST request\nconst char* PARAM_INPUT_1 = &quot;direction&quot;;\nconst char* PARAM_INPUT_2 = &quot;steps&quot;;\n\n\/\/ Variables to save values from HTML form\nString direction;\nString steps;\n\n\/\/ Variable to detect whether a new request occurred\nbool newRequest = false;\n\n\/\/ HTML to build the web page\nconst char index_html[] PROGMEM = R&quot;rawliteral(\n&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n  &lt;title&gt;Stepper Motor&lt;\/title&gt;\n  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;h1&gt;Stepper Motor Control&lt;\/h1&gt;\n    &lt;form action=&quot;\/&quot; method=&quot;POST&quot;&gt;\n      &lt;input type=&quot;radio&quot; name=&quot;direction&quot; value=&quot;CW&quot; checked&gt;\n      &lt;label for=&quot;CW&quot;&gt;Clockwise&lt;\/label&gt;\n      &lt;input type=&quot;radio&quot; name=&quot;direction&quot; value=&quot;CCW&quot;&gt;\n      &lt;label for=&quot;CW&quot;&gt;Counterclockwise&lt;\/label&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;\n      &lt;label for=&quot;steps&quot;&gt;Number of steps:&lt;\/label&gt;\n      &lt;input type=&quot;number&quot; name=&quot;steps&quot;&gt;\n      &lt;input type=&quot;submit&quot; value=&quot;GO!&quot;&gt;\n    &lt;\/form&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n)rawliteral&quot;;\n\n\/\/ Initialize WiFi\nvoid initWiFi() {\n  WiFi.mode(WIFI_STA);\n  WiFi.begin(ssid, password);\n  Serial.print(&quot;Connecting to WiFi ..&quot;);\n  while (WiFi.status() != WL_CONNECTED) {\n    Serial.print('.');\n    delay(1000);\n  }\n  Serial.println(WiFi.localIP());\n}\n\n\nvoid setup() {\n  Serial.begin(115200);\n\n  initWiFi();\n\n  myStepper.setSpeed(5);\n\n  \/\/ Web Server Root URL\n  server.on(&quot;\/&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\n    request-&gt;send(200, &quot;text\/html&quot;, index_html);\n  });\n  \n  \/\/ Handle request (form)\n  server.on(&quot;\/&quot;, HTTP_POST, [](AsyncWebServerRequest *request) {\n    int params = request-&gt;params();\n    for(int i=0;i&lt;params;i++){\n      const AsyncWebParameter* p = request-&gt;getParam(i);\n      if(p-&gt;isPost()){\n        \/\/ HTTP POST input1 value (direction)\n        if (p-&gt;name() == PARAM_INPUT_1) {\n          direction = p-&gt;value().c_str();\n          Serial.print(&quot;Direction set to: &quot;);\n          Serial.println(direction);\n        }\n        \/\/ HTTP POST input2 value (steps)\n        if (p-&gt;name() == PARAM_INPUT_2) {\n          steps = p-&gt;value().c_str();\n          Serial.print(&quot;Number of steps set to: &quot;);\n          Serial.println(steps);\n        }\n      }\n    }\n    request-&gt;send(200, &quot;text\/html&quot;, index_html);\n    newRequest = true;\n  });\n\n  server.begin();\n}\n\nvoid loop() {\n  \/\/ Check if there was a new request and move the stepper accordingly\n  if (newRequest){\n    if (direction == &quot;CW&quot;){\n      \/\/ Spin the stepper clockwise direction\n      myStepper.step(steps.toInt());\n    }\n    else{\n      \/\/ Spin the stepper counterclockwise direction\n      myStepper.step(-steps.toInt());\n    }\n    newRequest = false;\n  }\n}\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_Stepper_Motor_Web_Server.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=\"#demonstration1\">demonstration section<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Include Libraries<\/h4>\n\n\n\n<p>First, include the required libraries. The <span class=\"rnthl rntliteral\">WiFi<\/span>, <span class=\"rnthl rntliteral\">AsyncTCP<\/span>, and <span class=\"rnthl rntliteral\">ESPAsyncWebServer<\/span> to create the web server and the <span class=\"rnthl rntliteral\">Stepper<\/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;WiFi.h&gt;\n#include &lt;AsyncTCP.h&gt;\n#include &lt;ESPAsyncWebServer.h&gt;\n#include &lt;Stepper.h&gt;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Stepper Motor Pins and Steps per Revolution<\/h4>\n\n\n\n<p>Define the steps per revolution of your stepper motor\u2014in our case, it&#8217;s 2048:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const int stepsPerRevolution = 2048;  \/\/ change this to fit the number of steps per revolution<\/code><\/pre>\n\n\n\n<p>Define the motor input pins. In this example, we&#8217;re connecting to GPIOs 19, 18, 5, and 17, but you can use any other suitable GPIOs.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define IN1 19\n#define IN2 18\n#define IN3 5\n#define IN4 17<\/code><\/pre>\n\n\n\n<p>Initialize an instance of the stepper library called <span class=\"rnthl rntliteral\">myStepper<\/span>. Pass as arguments the steps per revolution 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<h4 class=\"wp-block-heading\">Network Credentials<\/h4>\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<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<h4 class=\"wp-block-heading\">Initializing Variables<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">PARAM_INPUT_1<\/span> and <span class=\"rnthl rntliteral\">PARAM_INPUT_2<\/span> variables will be used to search for parameters in the HTTP POST request. Remember that it contains the <span class=\"rnthl rntliteral\">direction<\/span> and number of <span class=\"rnthl rntliteral\">steps<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Search for parameters in HTTP POST request\nconst char* PARAM_INPUT_1 = \"direction\";\nconst char* PARAM_INPUT_2 = \"steps\";<\/code><\/pre>\n\n\n\n<p>The following variables will save the direction and number of steps.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>String direction;\nString steps;<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">newRequest<\/span> variable will be used to check whether a new request occurred. Then, in the <span class=\"rnthl rntliteral\">loop()<\/span>, we&#8217;ll spin the motor when a new request is received\u2014when the <span class=\"rnthl rntliteral\">newRequest<\/span> variable is <span class=\"rnthl rntliteral\">true<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>bool newRequest = false;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">HTML Form<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">index_html<\/span> variable saves the HTML text to build the web page\u2014we&#8217;ve seen previously how the HTML to build the web page with the form works.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ HTML to build the web page\nconst char index_html&#091;] PROGMEM = R\"rawliteral(\n&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n  &lt;title&gt;Stepper Motor&lt;\/title&gt;\n  &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;h1&gt;Stepper Motor Control&lt;\/h1&gt;\n    &lt;form action=\"\/\" method=\"POST\"&gt;\n      &lt;input type=\"radio\" name=\"direction\" value=\"CW\" checked&gt;\n      &lt;label for=\"CW\"&gt;Clockwise&lt;\/label&gt;\n      &lt;input type=\"radio\" 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\" name=\"steps\"&gt;\n      &lt;input type=\"submit\" value=\"GO!\"&gt;\n    &lt;\/form&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n)rawliteral\";<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">initWiFi()<\/h4>\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<p>In this example, the ESP is set as a Wi-Fi station (it connects to your router). If you don&#8217;t have a router nearby, you can set your board as an Access Point. You can read the next tutorial to learn how to set the board as an access point:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-access-point-ap-web-server\/\">How to Set an ESP32 Access Point (AP) for Web Server<\/a><\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">setup()<\/h4>\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>And set the stepper motor speed in rpm.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>myStepper.setSpeed(5);<\/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 happens when you access the ESP IP address\u2014send 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(200, \"text\/html\", index_html);\n});<\/code><\/pre>\n\n\n\n<p>Then, you need to handle what happens when the ESP receives a POST request with the form details.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/\", HTTP_POST, &#091;](AsyncWebServerRequest *request) {<\/code><\/pre>\n\n\n\n<p>First, we search for parameters in the HTTP POST request:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>int params = request-&gt;params();\nfor(int i=0;i&lt;params;i++){\n  AsyncWebParameter* p = request-&gt;getParam(i);\n  if(p-&gt;isPost()){<\/code><\/pre>\n\n\n\n<p>If one of the parameters is equal to <span class=\"rnthl rntliteral\">PARAM_INPUT_1<\/span>, we know its value contains the direction of the motor. If that\u2019s the case, we get the value of that parameter and save it in the <span class=\"rnthl rntliteral\">direction<\/span> variable.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (p-&gt;name() == PARAM_INPUT_1) {\n  direction = p-&gt;value().c_str();\n  Serial.print(\"Direction set to: \");\n  Serial.println(direction);\n}<\/code><\/pre>\n\n\n\n<p>We follow a similar procedure for <span class=\"rnthl rntliteral\">PARAM_INPUT_2<\/span>, but we save the value in the <span class=\"rnthl rntliteral\">steps<\/span> variable.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (p-&gt;name() == PARAM_INPUT_2) {\n  steps = p-&gt;value().c_str();\n  Serial.print(\"Number of steps set to: \");\n  Serial.println(steps);\n}<\/code><\/pre>\n\n\n\n<p>Finally, we respond with the content of the HTML page\u2014it will reload the page.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>request-&gt;send(200, \"text\/html\", index_html);<\/code><\/pre>\n\n\n\n<p>After this, we set the <span class=\"rnthl rntliteral\">newRequest<\/span> variable to <span class=\"rnthl rntliteral\">true<\/span>, so that it spins the motor in the <span class=\"rnthl rntliteral\">loop()<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>newRequest = true;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">loop()<\/h4>\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>If the <span class=\"rnthl rntliteral\">newRequest<\/span> variable is <span class=\"rnthl rntliteral\">true<\/span>, we&#8217;ll check what&#8217;s the spinning direction: <span class=\"rnthl rntliteral\">CW<\/span> or <span class=\"rnthl rntliteral\">CCW<\/span>. If it is <span class=\"rnthl rntliteral\">CW<\/span>, we move the motor the number of steps saved in the <span class=\"rnthl rntliteral\">steps<\/span> variable using the <span class=\"rnthl rntliteral\">step()<\/span> method on the <span class=\"rnthl rntliteral\">myStepper<\/span> object.<\/p>\n\n\n\n<p>To move the motor counterclockwise, we just need to pass the number of steps but with a minus <span class=\"rnthl rntliteral\">&#8211;<\/span> sign.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (direction == \"CW\"){\n  \/\/ Spin the stepper clockwise direction\n  myStepper.step(steps.toInt());\n}\nelse{\n  \/\/ Spin the stepper counterclockwise direction\n  myStepper.step(-steps.toInt());\n}<\/code><\/pre>\n\n\n\n<p>After spinning the motor, set the <span class=\"rnthl rntliteral\">newRequest<\/span> variable to <span class=\"rnthl rntliteral\">false<\/span>, so that it can detect new requests again.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>newRequest = false;<\/code><\/pre>\n\n\n\n<p class=\"rntbox rntclgray\"><strong>Note: <\/strong> because the <span class=\"rnthl rntliteral\">Stepper.h<\/span> is not an asynchronous library, it won&#8217;t do anything else until the motor has stopped spinning. So, if you try to make new requests while the motor is spinning, it will not work. We&#8217;ll build an example using WebSocket protocol that will allow us to know on the web interface whether the motor is spinning or not\u2014<a href=\"https:\/\/randomnerdtutorials.com\/stepper-motor-esp32-websocket\/\">you can check that tutorial here<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"demonstration1\">Demonstration<\/h3>\n\n\n\n<p>After inserting your network credentials, you can upload the code to your board.<\/p>\n\n\n\n<p>After uploading, open the Serial Monitor at a baud rate of 115200 and press the on-board RESET button. The ESP IP address will be displayed.<\/p>\n\n\n\n<p>Open a browser on your local network and insert the ESP IP address. You&#8217;ll get access to the HTML form to control the stepper motor.<\/p>\n\n\n<div class=\"wp-block-image is-resized\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"370\" height=\"750\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Web-Server-HTML-Form-No-CSS.jpg?resize=370%2C750&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 Control Stepper Motor Web Server HTML Form no CSS Simple\" class=\"wp-image-105553\" style=\"width:322px;height:auto\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Web-Server-HTML-Form-No-CSS.jpg?w=370&amp;quality=100&amp;strip=all&amp;ssl=1 370w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Web-Server-HTML-Form-No-CSS.jpg?resize=148%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 148w\" sizes=\"(max-width: 370px) 100vw, 370px\" \/><\/figure><\/div>\n\n\n<p>Select the direction and enter a determined number of steps. Then, press GO!. The stepper motor will start spinning. <\/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>At the same time, you can see the values of the <span class=\"rnthl rntliteral\">direction<\/span> and <span class=\"rnthl rntliteral\">steps<\/span> variables on the Serial Monitor.<\/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=\"601\" height=\"445\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-ESP8266-Stepper-motor-web-server-serial-monitor.png?resize=601%2C445&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"28BYJ-48 connected to ULN2003 Motor Driver 01 module Arduino IDE demonstration\" class=\"wp-image-105540\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-ESP8266-Stepper-motor-web-server-serial-monitor.png?w=601&amp;quality=100&amp;strip=all&amp;ssl=1 601w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-ESP8266-Stepper-motor-web-server-serial-monitor.png?resize=300%2C222&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 601px) 100vw, 601px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"stepper-web-server-html-form-css\">2. Styling the Form with CSS<\/h2>\n\n\n\n<p>In the previous section, we&#8217;ve created a plain form without any formatting. By adding some CSS to your project, your HTML page will look much better.<\/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=\"615\" height=\"448\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/Stepper-Motor-HTML-Form-web-server-CSS.png?resize=615%2C448&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 Stepper Motor Web Server HTML Form with CSS\" class=\"wp-image-105607\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/Stepper-Motor-HTML-Form-web-server-CSS.png?w=615&amp;quality=100&amp;strip=all&amp;ssl=1 615w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/Stepper-Motor-HTML-Form-web-server-CSS.png?resize=300%2C219&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 615px) 100vw, 615px\" \/><\/figure><\/div>\n\n\n<p>When your HTML also includes CSS, it is easier to work if you have separated HTML and CSS files (apart from the Arduino sketch file). So, instead of writing HTML and CSS in the Arduino sketch, we\u2019ll create separated HTML and CSS files. <\/p>\n\n\n\n<p>These files will then be uploaded to the ESP32 filesystem (LittleFS) using the <a href=\"https:\/\/randomnerdtutorials.com\/arduino-ide-2-install-esp32-littlefs\/\" title=\"\"><strong>LittleFS<\/strong> <strong>Filesystem uploader<\/strong> plugin<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Organizing Your Files<\/h3>\n\n\n\n<p>The files you want to upload to the ESP filesystem should be placed in a folder called <strong><em>data <\/em><\/strong>under the project folder.&nbsp;We\u2019ll move two 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<\/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\/07\/ESP32-Stepper-web-server-file-structure-SPIFFS.png?resize=601%2C358&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Stepper Motor Web Server Folder Structure SPIFFS\" class=\"wp-image-105560\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-web-server-file-structure-SPIFFS.png?w=601&amp;quality=100&amp;strip=all&amp;ssl=1 601w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-web-server-file-structure-SPIFFS.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_Stepper_Motor_WS_Styled\/ESP32_Stepper_Motor_WS_Styled.zip\" target=\"_blank\" rel=\"noreferrer noopener\">Download All the Arduino Project Files<\/a><\/strong><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Page Overview<\/h3>\n\n\n\n<p>To better understand how styling the web page works, let&#8217;s take a closer look at the web page we&#8217;ll build.<\/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=\"869\" height=\"404\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP-Web-Server-Style-HTML-Form.png?resize=869%2C404&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP Web Server Style HTML Form\" class=\"wp-image-105611\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP-Web-Server-Style-HTML-Form.png?w=869&amp;quality=100&amp;strip=all&amp;ssl=1 869w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP-Web-Server-Style-HTML-Form.png?resize=300%2C139&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP-Web-Server-Style-HTML-Form.png?resize=768%2C357&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 869px) 100vw, 869px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">HTML File<\/h3>\n\n\n\n<p>We need to make some modifications to the HTML file to make it easier to format using CSS. Create a file called <span class=\"rnthl rntliteral\">index.html<\/span> and copy the following into that 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;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 action=&quot;\/&quot; method=&quot;POST&quot;&gt;\r\n      &lt;input type=&quot;radio&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; 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; name=&quot;steps&quot;&gt;\r\n      &lt;input type=&quot;submit&quot; value=&quot;GO!&quot;&gt;\r\n    &lt;\/form&gt;\r\n  &lt;\/div&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/ESP32_Stepper_Motor_WS_Styled\/data\/index.html\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>To use a CSS file to style the HTML page, you need to reference the style sheet in your HTML document. So you need to add the following between the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;head&gt;<\/span><\/span> tags of your document:<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;link rel=\"stylesheet\" type=\"text\/css\" href=\"stylesheet.css\"&gt;<\/code><\/pre>\n\n\n\n<p>This <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;link&gt;<\/span><\/span> tag tells the HTML file that you\u2019re using an external style sheet to format how the page looks. The <span class=\"rnthl rntliteral\">rel<\/span> attribute specifies the nature of the external file. In this case, it is a style sheet\u2014the CSS file\u2014that will be used to alter the page&#8217;s appearance. <\/p>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">type<\/span> attribute is set to <span class=\"rnthl rntliteral\">&#8220;text\/css&#8221;<\/span> to indicate that you\u2019re using a CSS file for the styles. The <span class=\"rnthl rntliteral\">href<\/span> attribute indicates the file location; since the file is in the same folder as the HTML file, you just need to reference the filename. Otherwise, you need to reference its file path. <\/p>\n\n\n\n<p>Now you have your style sheet connected to your HTML document.<\/p>\n\n\n\n<p>To use the fontawesome icons in the web page like the cogs, we need to add the following line.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.5.1\/css\/all.min.css\"&gt;<\/code><\/pre>\n\n\n\n<p>We created a <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;div&gt;<\/span><\/span> tag with the class <span class=\"rnthl rntliteral\">topnav<\/span> to make it easier to format the first heading.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;div class=\"topnav\"&gt;\n  &lt;h1&gt;Stepper Motor Control &lt;i class=\"fas fa-cogs\"&gt;&lt;\/i&gt;&lt;\/h1&gt;\n&lt;\/div&gt;<\/code><\/pre>\n\n\n\n<p>Then, we include the form inside a <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;div&gt;<\/span><\/span> tag with the class <span class=\"rnthl rntliteral\">content<\/span>. This will make it easier to format the area occupied by the form.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;div class=\"content\"&gt;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">CSS File<\/h3>\n\n\n\n<p>Create a file called <span class=\"rnthl rntliteral\">style.css<\/span> with the following content to format the form.<\/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\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\nform{\r\n  border-radius: 5px;\r\n  background-color: #f2f2f2;\r\n  padding: 20px;\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\ninput[type=submit] {\r\n  -webkit-appearance: none;\r\n  -moz-appearance: none;\r\n  appearance: none;\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\ninput[type=submit]: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}<\/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_Stepper_Motor_WS_Styled\/data\/style.css\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">html<\/span> selector includes the styles that apply to the whole HTML page. In this case, we&#8217;re setting the font.<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>html {\n  font-family: Arial, Helvetica, sans-serif;\n}<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">h1<\/span> selector includes the styles for heading 1. In our case, the heading 1 includes the text &#8220;<span class=\"rnthl rntliteral\">Stepper Motor Control&#8221;<\/span>. This sets the text font size and color.<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>h1 {\n  font-size: 1.8rem;\n  color: white;\n}<\/code><\/pre>\n\n\n\n<p>To select the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;div&gt;<\/span><\/span> with the <span class=\"rnthl rntliteral\">topnav<\/span> class, use a dot (<span class=\"rnthl rntliteral\">.<\/span>) before the class name, like this:<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>.topnav {<\/code><\/pre>\n\n\n\n<p>Set the <span class=\"rnthl rntliteral\">.topnav<\/span> background color using the <span class=\"rnthl rntliteral\">background-color<\/span> property. You can choose any background color. We\u2019re using <span class=\"rnthl rntliteral\">#0A1128<\/span>. The text is aligned at the center. Additionally, set the <span class=\"rnthl rntliteral\">overflow<\/span> property to <span class=\"rnthl rntliteral\">hidden<\/span> like this:<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>.topnav {\n  overflow: hidden;\n  background-color: #0A1128;\n  text-align: center;\n}<\/code><\/pre>\n\n\n\n<p>It&#8217;s a bit difficult to explain what the <span class=\"rnthl rntliteral\">overflow<\/span> property does. The best way to understand it is to render your web page with and without that property to spot the differences.<\/p>\n\n\n\n<p>The margin of the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;body&gt;<\/span><\/span>\u2014the container that includes the whole HTML page\u2014is set to <span class=\"rnthl rntliteral\">0<\/span> so that it occupies all the browser window space.<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>body {\n  margin: 0;\n}<\/code><\/pre>\n\n\n\n<p>The following lines style the <span class=\"rnthl rntliteral\">content<\/span> div (that contains the form): padding and margin. Additionally, set its <span class=\"rnthl rntliteral\">max-width<\/span> to the maximum width of its content (the form itself).<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>.content {\n  padding: 20px;\n  max-width: max-content;\n  margin: 0 auto;\n}<\/code><\/pre>\n\n\n\n<p>The form is a container with round borders (<span class=\"rnthl rntliteral\">border-radius<\/span> property) and light gray background color (<span class=\"rnthl rntliteral\">background-color<\/span> property). We also add some <span class=\"rnthl rntliteral\">padding<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>form{\n  border-radius: 5px;\n  background-color: #f2f2f2;\n  padding: 20px;\n}<\/code><\/pre>\n\n\n\n<p>Then, we need to style each individual element of the form. To select the input number, we use the <span class=\"rnthl rntliteral\">input[type=number]<\/span> selector.<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>input&#091;type=number], select {\n  width: 100%;\n  padding: 12px 20px;\n  margin: 8px 0;\n  display: inline-block;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n  box-sizing: border-box;\n}<\/code><\/pre>\n\n\n\n<p><strong>Note: <\/strong> the <span class=\"rnthl rntliteral\">[attribute=value]<\/span> selector selects elements with the specified <span class=\"rnthl rntliteral\">attribute<\/span> and <span class=\"rnthl rntliteral\">value<\/span>. In this case, we&#8217;re selecting the input elements of type <span class=\"rnthl rntliteral\">number<\/span>.<\/p>\n\n\n\n<p>To style the submit button, use the <span class=\"rnthl rntliteral\">input[type=submit]<\/span> selector.<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>input&#091;type=submit] {\n  -webkit-appearance: none;\n  -moz-appearance: none;\n  appearance: none;\n  background-color: #034078;\n  border: none;\n  padding: 14px 20px;\n  text-align: center;\n  font-size: 20px;\n  border-radius: 4px;\n  transition-duration: 0.4s;\n  width: 100%;\n  color: white;\n  cursor: pointer;\n}<\/code><\/pre>\n\n\n\n<p>To make the button change color when you hover your mouse over it, you can use the <span class=\"rnthl rntliteral\">:hover<\/span> selector.<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>input&#091;type=submit]:hover {\n  background-color: #1282A2;\n}<\/code><\/pre>\n\n\n\n<p>Finally, to select the radio buttons, use the <span class=\"rnthl rntliteral\">input[type=&#8221;radio&#8221;]<\/span> selector.<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>input&#091;type=\"radio\"] {\n  -webkit-appearance: none;\n  -moz-appearance: none;\n  appearance: none;\n  border-radius: 50%;\n  width: 16px;\n  height: 16px;\n  border: 2px solid #999;\n  transition: 0.2s all linear;\n  margin-right: 5px;\n  position: relative;\n  top: 4px;\n }<\/code><\/pre>\n\n\n\n<p>To style the selected radio button, you can use the <span class=\"rnthl rntliteral\">:checked<\/span> selector.<\/p>\n\n\n\n<pre class=\"wp-block-code language-css\"><code>input&#091;type=\"radio\"]:checked{\n  border: 6px solid #1282A2;\n}<\/code><\/pre>\n\n\n\n<p>The form elements were styled based on an example provided by the W3Schools website. If you want to better understand how it works, <a href=\"https:\/\/www.w3schools.com\/css\/css_form.asp\" target=\"_blank\" rel=\"noreferrer noopener\">you can check it here<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Arduino Sketch<\/h3>\n\n\n\n<p>In this project, the HTML and CSS files are saved in the ESP32 filesystem (LittleFS). So, we need to make some modifications to the sketch.<\/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 project details at https:\/\/RandomNerdTutorials.com\/stepper-motor-esp32-web-server\/\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;Stepper.h&gt;\r\n\r\nconst int stepsPerRevolution = 2048;  \/\/ change this to fit the number of steps per revolution\r\n#define IN1 19\r\n#define IN2 18\r\n#define IN3 5\r\n#define IN4 17\r\nStepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4);\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\/\/ Search for parameter in HTTP POST request\r\nconst char* PARAM_INPUT_1 = &quot;direction&quot;;\r\nconst char* PARAM_INPUT_2 = &quot;steps&quot;;\r\n\r\n\/\/Variables to save values from HTML form\r\nString direction;\r\nString steps;\r\n\r\nbool newRequest = false;\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  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 setup() {\r\n  \/\/ Serial port for debugging purposes\r\n  Serial.begin(115200);\r\n  initWiFi();\r\n  initLittleFS();\r\n  myStepper.setSpeed(5);\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.on(&quot;\/&quot;, HTTP_POST, [](AsyncWebServerRequest *request) {\r\n    int params = request-&gt;params();\r\n    for(int i=0;i&lt;params;i++){\r\n      const AsyncWebParameter* p = request-&gt;getParam(i);\r\n      if(p-&gt;isPost()){\r\n        \/\/ HTTP POST input1 value\r\n        if (p-&gt;name() == PARAM_INPUT_1) {\r\n          direction = p-&gt;value().c_str();\r\n          Serial.print(&quot;Direction set to: &quot;);\r\n          Serial.println(direction);\r\n        }\r\n        \/\/ HTTP POST input2 value\r\n        if (p-&gt;name() == PARAM_INPUT_2) {\r\n          steps = p-&gt;value().c_str();\r\n          Serial.print(&quot;Number of steps set to: &quot;);\r\n          Serial.println(steps);\r\n          \/\/ Write file to save value\r\n        }\r\n        newRequest = true;\r\n        \/\/Serial.printf(&quot;POST[%s]: %s\\n&quot;, p-&gt;name().c_str(), p-&gt;value().c_str());\r\n      }\r\n    }\r\n    request-&gt;send(LittleFS, &quot;\/index.html&quot;, &quot;text\/html&quot;);\r\n  });\r\n\r\n  server.begin();\r\n}\r\n\r\nvoid loop() {\r\n  if (newRequest){\r\n    if (direction == &quot;CW&quot;){\r\n      myStepper.step(steps.toInt());\r\n      Serial.print(&quot;CW&quot;);\r\n    }\r\n    else{\r\n      myStepper.step(-steps.toInt());\r\n    }\r\n    newRequest = false;\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\/ESP32\/ESP32_Stepper_Motor_WS_Styled\/ESP32_Stepper_Motor_WS_Styled.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Let&#8217;s take a look at the modifications you need to make.<\/p>\n\n\n\n<p>First, you need to include the <span class=\"rnthl rntliteral\">LittleFS.h<\/span> library.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include \"LittleFS.h\"<\/code><\/pre>\n\n\n\n<p>Then, you need to initialize LittleFS. We created a function called <span class=\"rnthl rntliteral\">initLittleFS()<\/span> to do that.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void initLittleFS() {\n  if (!LittleFS.begin(true)) {\n    Serial.println(\"An error has occurred while mounting LittleFS\");\n  }\n  else {\n  Serial.println(\"LittleFSmounted successfully\");\n  }\n}<\/code><\/pre>\n\n\n\n<p>Then, you need to call that function in the <span class=\"rnthl rntliteral\">setup()<\/span> before initializing the web server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>initLittleFS();<\/code><\/pre>\n\n\n\n<p>Then, to handle requests, you need to indicate that your HTML file is saved in LittleFS, as follows:<\/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 file. This is a static file saved on the same directory (LittleFS). So, we can simply add the following line to serve static files in a directory when requested by the root URL. It will serve the CSS file automatically.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.serveStatic(\"\/\", LittleFS, \"\/\");<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Upload Code and Files<\/h3>\n\n\n\n<p>Before uploading, you can use the following link to:<\/p>\n\n\n\n<p><li><strong><a href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/ESP32_Stepper_Motor_WS_Styled\/ESP32_Stepper_Motor_WS_Styled.zip\" target=\"_blank\" rel=\"noreferrer noopener\">Download All the Arduino Project Files<\/a><\/strong><\/li><\/p>\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><strong>Inside that folder, you should save the HTML and CSS files.<\/strong><\/p>\n\n\n\n<p>Then, upload the code to your ESP32 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-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>After uploading the code, you need to upload the files. In the Arduino IDE, 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&#8217;t have this option is because you didn&#8217;t install the filesystem uploader plugin.<a href=\"https:\/\/randomnerdtutorials.com\/arduino-ide-2-install-esp32-littlefs\/\" title=\"\"> 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>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<h3 class=\"wp-block-heading\">Demonstration<\/h3>\n\n\n\n<p>Open a browser on your local network and paste the ESP32 IP address. You&#8217;ll get access to the HTML form to control the stepper motor. This works similarly to the example of the previous section, but with a better look.<\/p>\n\n\n<div class=\"wp-block-image is-resized\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"368\" height=\"750\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Web-Server-HTML-Form-with-CSS.jpg?resize=368%2C750&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 Stepper Motor Web Server HTML Form with CSS\" class=\"wp-image-105555\" style=\"width:253px;height:auto\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Web-Server-HTML-Form-with-CSS.jpg?w=368&amp;quality=100&amp;strip=all&amp;ssl=1 368w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/ESP32-Stepper-Motor-Web-Server-HTML-Form-with-CSS.jpg?resize=147%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 147w\" sizes=\"(max-width: 368px) 100vw, 368px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>This tutorial is already quite long. So, we&#8217;ll include the third part of this tutorial in a separate publication. In that third part, the ESP32 and the client communicate using WebSocket protocol and the web page shows whether the motor is spinning or stopped. We&#8217;ve also included an animation with some gears spinning in the same direction as the motor.<\/p>\n\n\n\n<p>Continue to <strong>PART 3<\/strong> <a href=\"https:\/\/randomnerdtutorials.com\/stepper-motor-esp32-websocket\/\">ESP32 Web Server: Control Stepper Motor (WebSocket)<\/a>. Sneak peek at the third part in the video below.<\/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<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, 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>Thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this tutorial, you&#8217;ll learn how to create a web server with the ESP32 to control a stepper motor remotely. The web server displays a web page with an HTML &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32 Web Server: Control Stepper Motor (HTML Form)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/stepper-motor-esp32-web-server\/#more-105501\" aria-label=\"Read more about ESP32 Web Server: Control Stepper Motor (HTML Form)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":105615,"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":[276,281,277,299,264],"tags":[],"class_list":["post-105501","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32","category-esp32-project","category-esp32-arduino-ide","category-0-esp32","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/07\/Control-Stepper-Motor-ESP32-Web-Server-HTML-Forml.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\/105501","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=105501"}],"version-history":[{"count":51,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/105501\/revisions"}],"predecessor-version":[{"id":167935,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/105501\/revisions\/167935"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/105615"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=105501"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=105501"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=105501"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}