In this article, you’ll learn how to use the ESP32 to create a web server to operate a stepper motor from afar. The web server shows a web page with an HTML form on which you may choose the motor’s direction and number of steps. In this article, you’ll learn how to use the ESP32 to create a web server to operate a stepper motor from afar. The web server shows a web page with an HTML form on which you may choose the motor’s direction and number of steps.

Parts Required

To follow this tutorial, you need the following parts:

  • 28BYJ-48 Stepper Motor + ULN2003 Motor Driver
  • ESP32-
  • Jumper Wires
  • 5V Power Supply

Schematic Diagram

The following schematic diagram shows the connections between the stepper motor to the ESP32.

ESP32 with Stepper Motor 28BYJ-48 and ULN2003A Schematic Diagram Wiring

ESP32 with Stepper Motor 28BYJ-48 and ULN2003A Schematic Diagram Wiring

1. Control Stepper Motor with HTML Form

In this section, you’ll learn how to create a simple HTML form to control the stepper motor.

  • You can choose whether you want the motor to turn clockwise or counterclockwise on the web page. Radio buttons are what they’re called. When a radio button is selected, it appears as a little circle that is filled or highlighted. In each group, you can only select one radio button at a time.
  • The user can enter a number—in this case, the number of steps—in a number input field of type number.
  • Finally, using an HTTP POST request, a button called GO! of type submit transmits the data to the server.

HTML Form and Input Fields

In this section, we’ll take a look at the HTML to build the form.

In HTML, the <form> 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—in this case, spin the motor a determined number of steps.

Here’s the HTML we’ll use for this project.

<!DOCTYPE html>
<html>
<head>
  <title>Stepper Motor</title>
  <meta name=”viewport” content=”width=device-width, initial-scale=1″>
</head>
<body>
  <h1>Stepper Motor Control</h1>
   <form action=”/” method=”POST”>
      <input type=”radio” name=”direction” value=”CW” checked>
      <label for=”CW”>Clockwise</label>
      <input type=”radio” name=”direction” value=”CCW”>
      <label for=”CW”>Counterclockwise</label><br><br><br>
      <label for=”steps”>Number of steps:</label>
      <input type=”number” name=”steps”>
      <input type=”submit” value=”GO!”>
    </form>
</body>
</html>

Different form elements can be found in an HTML form. The <form> tag is used to enclose all form components. It has input controls (radio buttons and a number input field) as well as labels (<label>) for those controls.

The action element, which indicates what you want to do when the form is submitted, must also be included in the <form> tag. When the user presses the submit button, we want to send that data to the server (ESP32/ESP8266). When submitting form data, the method attribute provides the HTTP method (GET or POST).

<form action="/" method="POST">

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.

Radio Buttons

A radio button is defined as follows:

<input type="radio">

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 name attribute—in this case direction).

<input type="radio" name="direction">

Finally, we also need the value 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.

In our example, we created one radio button with the value CW (to select clockwise) and another CCW (to select counterclockwise).

<input type="radio" name="direction" value="CW">
<input type="radio" name="direction" value="CCW">

Finally, if you want one radio button to be selected by default, you can add the keyword checked. In our example, the clockwise direction is selected by default.

<input type="radio" name="direction" value="CW" checked>

So, this is how the radio buttons and corresponding labels look like:

<input type="radio" name="direction" value="CW" checked>
<label for="CW">Clockwise</label>
<input type="radio" name="direction" value="CCW">
<label for="CW">Counterclockwise</label><br><br><br>

Input Field

Finally, we also need an input field where the user enters the number of steps—an input field of type number. The name attribute allows us to determine in which input field the user entered the data.

<input type=”number” name=”steps”>

Submit Button

To complete the form, we need a submit button. A submit button is an input of type submit. When you click this button, the form’s data is sent to the server (the ESP32 or ESP8266 boards). The value attribute specifies the text to display on the button.

<input type="submit" value="GO!">

For example, if you select the clockwise direction and enter 2000 steps, the client will make the following request to the ESP:

POST /

Host: localhost

direction=CW steps=2000

The ESP receives this request and can get the direction and number of steps from the body of the request.

Code

The HTML text can be saved on an HTML file saved on the ESP32 filesystem (SPIFFS) or it can be saved in a variable in your Arduino sketch.

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Stepper.h>

// Stepper Motor Settings
const int stepsPerRevolution = 2048;  // change this to fit the number of steps per revolution
#define IN1 19
#define IN2 18
#define IN3 5
#define IN4 17
Stepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4);

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

// Search for parameters in HTTP POST request
const char* PARAM_INPUT_1 = "direction";
const char* PARAM_INPUT_2 = "steps";

// Variables to save values from HTML form
String direction;
String steps;

// Variable to detect whether a new request occurred
bool newRequest = false;

// HTML to build the web page
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
  <title>Stepper Motor</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
  <h1>Stepper Motor Control</h1>
    <form action="/" method="POST">
      <input type="radio" name="direction" value="CW" checked>
      <label for="CW">Clockwise</label>
      <input type="radio" name="direction" value="CCW">
      <label for="CW">Counterclockwise</label><br><br><br>
      <label for="steps">Number of steps:</label>
      <input type="number" name="steps">
      <input type="submit" value="GO!">
    </form>
</body>
</html>
)rawliteral";

// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}


void setup() {
  Serial.begin(115200);

  initWiFi();

  myStepper.setSpeed(5);

  // Web Server Root URL
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/html", index_html);
  });
  
  // Handle request (form)
  server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) {
    int params = request->params();
    for(int i=0;i<params;i++){
      AsyncWebParameter* p = request->getParam(i);
      if(p->isPost()){
        // HTTP POST input1 value (direction)
        if (p->name() == PARAM_INPUT_1) {
          direction = p->value().c_str();
          Serial.print("Direction set to: ");
          Serial.println(direction);
        }
        // HTTP POST input2 value (steps)
        if (p->name() == PARAM_INPUT_2) {
          steps = p->value().c_str();
          Serial.print("Number of steps set to: ");
          Serial.println(steps);
        }
      }
    }
    request->send(200, "text/html", index_html);
    newRequest = true;
  });

  server.begin();
}

void loop() {
  // Check if there was a new request and move the stepper accordingly
  if (newRequest){
    if (direction == "CW"){
      // Spin the stepper clockwise direction
      myStepper.step(steps.toInt());
    }
    else{
      // Spin the stepper counterclockwise direction
      myStepper.step(-steps.toInt());
    }
    newRequest = false;
  }
}

How the Code Works

Include Libraries

First, include the required libraries. The WiFi, AsyncTCP, and ESPAsyncWebServer to create the web server and the Stepper library to control the stepper motor.

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Stepper.h>

Stepper Motor Pins and Steps per Revolution

Define the steps per revolution of your stepper motor—in our case, it’s 2048:

const int stepsPerRevolution = 2048;  // change this to fit the number of steps per revolution

Define the motor input pins. In this example, we’re connecting to GPIOs 19, 18, 5, and 17, but you can use any other suitable GPIOs.

#define IN1 19
#define IN2 18
#define IN3 5
#define IN4 17

Initialize an instance of the stepper library called myStepper. 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 IN1, IN3, IN2, IN4—it might be different for your motor.

Stepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4);

Network Credentials

Insert your network credentials in the following lines.

/ Replace with your network credentials
const char* ssid = “REPLACE_WITH_YOUR_SSID”;
const char* password = “REPLACE_WITH_YOUR_PASSWORD”;
Create an AsyncWebServer object called server on port 80.
AsyncWebServer server(80);

Initializing Variables

The PARAM_INPUT_1 and PARAM_INPUT_2 variables will be used to search for parameters in the HTTP POST request. Remember that it contains the direction and number of steps.

// Search for parameters in HTTP POST request
const char* PARAM_INPUT_1 = “direction”;
const char* PARAM_INPUT_2 = “steps”;
//  The following variables will save the direction and number of steps.
String direction;
String steps;

The newRequest variable will be used to check whether a new request occurred. Then, in the loop(), we’ll spin the motor when a new request is received—when the newRequest variable is true.

bool newRequest = false;

HTML Form

The index_html variable saves the HTML text to build the web page—we’ve seen previously how the HTML to build the web page with the form works.

// HTML to build the web page
const char index_html[] PROGMEM = R”rawliteral(
				<!DOCTYPE html>
				<html>
				<head>
				  <title>Stepper Motor</title>
				  <meta name=”viewport” content=”width=device-width, initial-scale=1″>
				</head>
				<body>
				  <h1>Stepper Motor Control</h1>
					<form action=”/” method=”POST”>
					  <input type=”radio” name=”direction” value=”CW” checked>
					  <label for=”CW”>Clockwise</label>
					  <input type=”radio” name=”direction” value=”CCW”>
					  <label for=”CW”>Counterclockwise</label><br><br><br>
					  <label for=”steps”>Number of steps:</label>
					 <input type=”number” name=”steps”>
					 <input type=”submit” value=”GO!”>
					</form>
				</body>
				</html>
)rawliteral”;

initWiFi()

The initWiFi() function initializes WiFi.

// Initialize WiFi

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print(“Connecting to WiFi ..”);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(‘.’);
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

setup()

In the setup(), initialize the Serial Monitor.

Serial.begin(115200);

Call the initWiFi() function to initialize WiFi.

initWiFi();

And set the stepper motor speed in rpm.

myStepper.setSpeed(5);

Handle requests

Then, handle the web server. When you receive a request on the root (/) URL—this happens when you access the ESP IP address—send the HTML text to build the web page:

server.on(“/”, HTTP_GET, [](AsyncWebServerRequest *request){

  request->send(200, “text/html”, index_html);

});

Then, you need to handle what happens when the ESP receives a POST request with the form details.

server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) {

First, we search for parameters in the HTTP POST request:

int params = request->params();

for(int i=0;i<params;i++){

  AsyncWebParameter* p = request->getParam(i);

  if(p->isPost()){

If one of the parameters is equal to PARAM_INPUT_1, we know its value contains the direction of the motor. If that’s the case, we get the value of that parameter and save it in the direction variable.

if (p->name() == PARAM_INPUT_1) {

  direction = p->value().c_str();

  Serial.print(“Direction set to: “);

  Serial.println(direction);

}

We follow a similar procedure for PARAM_INPUT_2, but we save the value in the steps variable.

if (p->name() == PARAM_INPUT_2) {

  steps = p->value().c_str();

  Serial.print(“Number of steps set to: “);

  Serial.println(steps);

}

Finally, we respond with the content of the HTML page—it will reload the page.

request->send(200, "text/html", index_html);

After this, we set the newRequest variable to true, so that it spins the motor in the loop().

newRequest = true;

loop()

If the newRequest variable is true, we’ll check what’s the spinning direction: CW or CCW. If it is CW, we move the motor the number of steps saved in the steps variable using the step() method on the myStepper object.

To move the motor counterclockwise, we just need to pass the number of steps but with a minus – sign.

if (direction == “CW”){

  // Spin the stepper clockwise direction

  myStepper.step(steps.toInt());

}

else{

  // Spin the stepper counterclockwise direction

  myStepper.step(-steps.toInt());

}

After spinning the motor, set the newRequest variable to false, so that it can detect new requests again.

newRequest = false;

Demonstration

  • You can then upload the code to your board after entering your network credentials.
  • Open the Serial Monitor with a baud rate of 115200 and push the on-board RESET button after uploading. The IP address of the ESP will be displayed.
  • On your local network, open a browser and type in the ESP IP address. You’ll be able to operate the stepper motor using an HTML form.
  • Select the direction and enter a determined number of steps. Then, press GO!. The stepper motor will start spinning.
  • At the same time, you can see the values of the direction and steps variables on the Serial Monitor.

2. Styling the Form with CSS

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’ll create separated HTML and CSS files.

Organizing Your Files

The files you want to upload to the ESP filesystem should be placed in a folder called data under the project folder. We’ll move two files to that folder:

  • index.html to build the web page
  • style.css to style the web page

HTML File

We need to make some modifications to the HTML file to make it easier to format using CSS. Create a file called index.html and copy the following into that file.

<!DOCTYPE html>
<html>
<head>
  <title>Stepper Motor</title>
  <meta name=”viewport” content=”width=device-width, initial-scale=1″>
  <link rel=”stylesheet” type=”text/css” href=”style.css”>
  <link rel=”icon” type=”image/png” href=”favicon.png”>
  <link rel=”stylesheet” href=”https://use.fontawesome.com/releases/v5.7.2/css/all.css” integrity=”sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr” crossorigin=”anonymous”>
</head>
<body>
  <div class=”topnav”>
    <h1>Stepper Motor Control <i class=”fas fa-cogs”></i></h1>
  </div>
  <div class=”content”>
    <form action=”/” method=”POST”>
      <input type=”radio” name=”direction” value=”CW” checked>
      <label for=”CW”>Clockwise</label>
      <input type=”radio” name=”direction” value=”CCW”>
      <label for=”CW”>Counterclockwise</label><br><br><br>
      <label for=”steps”>Number of steps:</label>
      <input type=”number” name=”steps”>
      <input type=”submit” value=”GO!”>
    </form>
  </div>
</body>
</html>

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 <head> tags of your document:

<link rel="stylesheet" type="text/css" href="stylesheet.css">

This <link> tag informs the HTML file that the page will be formatted using an external style sheet. The external file’s type is specified by the rel attribute. In this situation, a style sheet—the CSS file—will be utilized to change the appearance of the page.

The type attribute is set to “text/css” to indicate that the styles are defined in a CSS file. The href element specifies the file’s location; because the file is in the same folder as the HTML file, you just need to refer to it by its name. Otherwise, you’ll have to refer to the file’s path.

To use the fontawesome icons in the web page like the cogs, we need to add the following line.

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">

We created a <div> tag with the class topnav to make it easier to format the first heading.

<div class=”topnav”>
  <h1>Stepper Motor Control <i class=”fas fa-cogs”></i></h1>
</div>

Then, we include the form inside a <div> tag with the class content. This will make it easier to format the area occupied by the form.

<div class="content">

CSS File

Create a file called style.css with the following content to format the form.

html {
  font-family: Arial, Helvetica, sans-serif;
}
h1 {
  font-size: 1.8rem;
  color: white;
}
.topnav {
  overflow: hidden;
  background-color: #0A1128;
  text-align: center;
}
body {
  margin: 0;
}

.content {
  padding: 20px;
  max-width: max-content;
  margin: 0 auto;
}
form{
  border-radius: 5px;
  background-color: #f2f2f2;
  padding: 20px;
}
input[type=number], select {
  width: 100%;
  padding: 12px 20px;
  margin: 8px 0;
  display: inline-block;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
}

input[type=submit] {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-color: #034078;
  border: none;
  padding: 14px 20px;
  text-align: center;
  font-size: 20px;
  border-radius: 4px;
  transition-duration: 0.4s;
  width: 100%;
  color: white;
  cursor: pointer;
}
input[type=submit]:hover {
   background-color: #1282A2;
}
input[type=”radio”] {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  border-radius: 50%;
  width: 16px;
  height: 16px;
  border: 2px solid #999;
  transition: 0.2s all linear;
  margin-right: 5px;
  position: relative;
  top: 4px;
}
input[type=”radio”]:checked{
  border: 6px solid #1282A2;

the HTML selector includes the styles that apply to the whole HTML page. In this case, we’re setting the font.

html {

  font-family: Arial, Helvetica, sans-serif;

}

The h1 selector includes the styles for heading 1. In our case, heading 1 includes the text “Stepper Motor Control”. This sets the text font size and colour.

html {

  font-family: Arial, Helvetica, sans-serif;

}

To select the <div> with the topnav class, use a dot (.) before the class name, like this:

.topnav {

Set the .topnav background color using the background-color property. You can choose any background colour. We’re using #0A1128. The text is aligned at the center. Additionally, set the overflow property to hidden like this:

.topnav {
  overflow: hidden;
  background-color: #0A1128;
  text-align: center;
}

It’s a bit difficult to explain what the overflow property does. To spot the differences, the best way to understand them is to render your web page with and without that property.

The margin of the <body>—the container that includes the whole HTML page—is set to 0 so that it occupies all the browser window space.

body {
  margin: 0;
}

The following lines style the content div (that contains the form): padding and margin. Additionally, set its max-width to the maximum width of its content (the form itself).

.content {
  padding: 20px;
  max-width: max-content;
  margin: 0 auto;
}

The form is a container with round borders (border-radius property) and light gray background color (background-color property). We also add some padding.

form{
  border-radius: 5px;
  background-color: #f2f2f2;
  padding: 20px;
}

Then, we need to style each individual element of the form. To select the input number, we use the input[type=number] selector.

input[type=number], select {
  width: 100%;
  padding: 12px 20px;
  margin: 8px 0;
  display: inline-block;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
}

To style the submit button, use the input[type=submit] selector.

input[type=submit] {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-color: #034078;
  border: none;
  padding: 14px 20px;
  text-align: center;
  font-size: 20px;
  border-radius: 4px;
  transition-duration: 0.4s;
  width: 100%;
  color: white;
  cursor: pointer;
}

To make the button change color when you hover your mouse over it, you can use the :hover selector.

input[type=submit]:hover {
  background-color: #1282A2;
}

Finally, to select the radio buttons, use the input[type=”radio”] selector.

input[type=”radio”] {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  border-radius: 50%;
  width: 16px;
  height: 16px;
  border: 2px solid #999;
  transition: 0.2s all linear;
  margin-right: 5px;
  position: relative;
  top: 4px;
 }

To style the selected radio button, you can use the :checked selector.

input[type=”radio”]:checked{
  border: 6px solid #1282A2;
}

CODE

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "SPIFFS.h"
#include <Arduino_JSON.h>
#include <Stepper.h>

const int stepsPerRevolution = 2048;  // change this to fit the number of steps per revolution
#define IN1 19
#define IN2 18
#define IN3 5
#define IN4 17
Stepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4);

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

// Search for parameter in HTTP POST request
const char* PARAM_INPUT_1 = "direction";
const char* PARAM_INPUT_2 = "steps";

//Variables to save values from HTML form
String direction;
String steps;

bool newRequest = false;

// Initialize SPIFFS
void initSPIFFS() {
  if (!SPIFFS.begin(true)) {
    Serial.println("An error has occurred while mounting SPIFFS");
  }
  else {
  Serial.println("SPIFFS mounted successfully");
  }
}

// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

void setup() {
  // Serial port for debugging purposes

  Serial.begin(115200);
  initWiFi();
  initSPIFFS();
  myStepper.setSpeed(5);


  // Web Server Root URL
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/index.html", "text/html");
  });
  
  server.serveStatic("/", SPIFFS, "/");

  server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) {
    int params = request->params();
    for(int i=0;i<params;i++){
      AsyncWebParameter* p = request->getParam(i);
      if(p->isPost()){
        // HTTP POST input1 value
        if (p->name() == PARAM_INPUT_1) {
          direction = p->value().c_str();
          Serial.print("Direction set to: ");
          Serial.println(direction);
        }
        // HTTP POST input2 value
        if (p->name() == PARAM_INPUT_2) {
          steps = p->value().c_str();
          Serial.print("Number of steps set to: ");
          Serial.println(steps);
          // Write file to save value
        }
        newRequest = true;
        //Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
      }
    }
    request->send(SPIFFS, "/index.html", "text/html");
  });

  server.begin();
}

void loop() {
  if (newRequest){
    if (direction == "CW"){
      myStepper.step(steps.toInt());
      Serial.print("CW");
    }
    else{
      myStepper.step(-steps.toInt());
    }
    newRequest = false;
  }
}

How code works

First, you need to include the SPIFFS.h library.

#include “SPIFFS.h”

Then, you need to initialize SPIFFS. We created a function called initSPIFFS() to do that.

void initSPIFFS() {

  if (!SPIFFS.begin(true)) {

    Serial.println(“An error has occurred while mounting SPIFFS”);

  }

  else {

  Serial.println(“SPIFFS mounted successfully”);

  }

}

Then, you need to call that function in the setup() before initializing the web server.

initSPIFFS();

Then, to handle requests, you need to indicate that your HTML file is saved in SPIFFS, as follows:

server.on(“/”, HTTP_GET, [](AsyncWebServerRequest *request){

  request->send(SPIFFS, “/index.html”, “text/html”);

});

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 (SPIFFS). 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.

server.serveStatic(“/”, SPIFFS, “/”);

Upload Code and Files

After inserting your network credentials, save the code. Go to Sketch > Show Sketch Folder, and create a folder called data.

Inside that folder, you should save the HTML and CSS files.

Then, upload the code to your ESP32 board. Make sure you have the right board and COM port selected. Also, make sure you’ve added your network credentials.

After uploading the code, you need to upload the files. Go to Tools > ESP32 Data Sketch Upload and wait for the files to be uploaded.

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.

Demonstration

Open a browser on your local network and paste the ESP32 IP address. You’ll get access to the HTML form to control the stepper motor.

author avatar
Aravind S S