In this guide, we’ll build a web server with the ESP8266 NodeMCU to control a DC motor remotely. The web server will serve a web page with buttons to make the motor spin forward, backward, and stop. To control the motors we’ll use the L298N motor driver and the ESP8266 will be programmed using Arduino IDE.
To better understand how this project works, we recommend taking a look at our DC motor getting started guide with the ESP8266:
Prerequisites
Before proceeding with the tutorial, make sure you check the following prerequisites.
1) Parts Required
To follow this tutorial, you need the following parts:
- Mini DC Motor
- L298N Motor Driver
- ESP8266 (read Best ESP8266 boards comparison)
- Jumper Wires
- External power supply for the motors—we’ll be using 4xAA batteries
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
2) Arduino IDE and ESP8266 Boards Add-on
We’ll program the ESP8266 using Arduino IDE. So, you must have the ESP8266 boards installed on your Arduino ÎDE if you haven’t already.
If you want to use VS Code with the PlatformIO extension, follow the next tutorial instead to learn how to program the ESP8266:
3) Filesystem Uploader Plugin
To upload the HTML and CSS files needed to build this project to the ESP8266 filesystem (LittleFS), we’ll use a plugin for Arduino IDE: LittleFS Filesystem uploader. Follow the next tutorial to install the filesystem uploader plugin on Arduino 2 if you haven’t already:
If you’re using VS Code with the PlatformIO extension, read the following tutorial to learn how to upload files to the filesystem:
4) Install Libraries
To build this project, you need to install the following libraries:
- ESPAsyncWebServer (.zip folder)
- ESPAsyncTCP (.zip folder)
The ESPAsyncWebServer and AsynTCP libraries aren’t available to install through the Arduino Library Manager. You need to click on the previous links to download the library files. Then, in your Arduino IDE, go to Sketch> Include Library > Add .zip Library and select the libraries you’ve just downloaded.
4) Schematic Diagram
The following schematic diagram shows how to connect a DC motor to the ESP8266 using a L298N motor driver.
Not familiar with the L298N motor driver? Follow this tutorial first: ESP8266 NodeMCU with DC Motor and L298N Motor Driver – Control Speed and Direction (Arduino IDE)
The motor we’ll control is connected to the motor A output pins, so we need to wire the ENABLEA, INPUT1, and INPUT2 pins of the motor driver to the ESP8266. Follow the next schematic diagram to wire the DC motor and the L298N motor driver to the ESP8266.
LN298N Motor Driver | Input 1 | Input 2 | Enable | GND |
ESP8266 | GPIO 12 (D6) | GPIO 14 (D5) | GPIO 13 (D7) | GND |
We’re using the GPIOs on the previous table to connect to the motor driver. You can use any other suitable GPIOs as long as you modify the code accordingly. Learn more about the ESP8266 GPIOs: ESP8266 Pinout Reference: Which GPIO pins should you use?
Powering the LN298N Motor Driver
The DC motor requires a big jump in current to move, so the motors should be powered using an external power source from the ESP8266. As an example, we’re using 4AA batteries, but you can use any other suitable power supply. In this configuration, you can use a power supply with 6V to 12V.
The switch between the battery holder and the motor driver is optional, but it is very handy to cut and apply power. This way you don’t need to connect and then disconnect the wires to save power constantly.
We recommend soldering a 0.1uF ceramic capacitor to the positive and negative terminals of the DC motor, as shown in the diagram to help smooth out any voltage spikes. (Note: the motors also work without the capacitor.)
Project Overview
The following image shows the web page you’ll build for this project.
The web page has three buttons to control the DC motor. Each button makes a request on a different URL so that the ESP8266 knows which button was pressed and acts accordingly.
- Forward button: makes a request on the /forward URL — the motor will spin forward
- Backward button: makes a request on the /backward URL—the motor will spin backward
- Stop button: makes a request on the /stop URL—the motor will stop
To build this web page, we’ll create an HTML file (index.html) and a CSS file (style.css) that will be saved on the ESP8266 filesystem (LittleFS).
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;
You should save the HTML, CSS, and JavaScript files inside a folder called data inside the Arduino sketch folder, as shown in the previous diagram. We’ll upload these files to the ESP8266 filesystem (LittleFS).
You can download all project files:
HTML File
Create a file called index.html with the following content:
<!DOCTYPE html>
<html>
<head>
<title>ESP IOT DASHBOARD</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">
<script src="https://kit.fontawesome.com/0294e3a09e.js" crossorigin="anonymous"></script>
</head>
<body>
<div class="topnav">
<h1>CONTROL DC MOTOR</h1>
</div>
<div class="content">
<div class="card-grid">
<div class="card">
<p class="card-title"><i class="fa-solid fa-gear"></i> DC Motor A</p>
<p>
<a href="forward"><button class="button-on"><i class="fa-solid fa-arrow-up"></i> FORWARD</button></a>
<a href="backward"><button class="button-off"><i class="fa-solid fa-arrow-down"></i> BACKWARD</button></a>
</p>
<p>
<a href="stop"><button class="button-stop"><i class="fa-solid fa-stop"></i> STOP</button></a>
</p>
</div>
</div>
</div>
</body>
</html>
In this HTML file, we create three buttons, that when clicked will make a request on different URLs.
- FORWARD: /forward
- BACKWARD: /backward
- STOP: /stop
<p>
<a href="forward"><button class="button-on"><i class="fa-solid fa-arrow-up"></i> FORWARD</button></a>
<a href="backward"><button class="button-off"><i class="fa-solid fa-arrow-down"></i> BACKWARD</button></a>
</p>
<p>
<a href="stop"><button class="button-stop"><i class="fa-solid fa-stop"></i> STOP</button></a>
</p>
CSS File
Create a file called style.css with the following content to style the web page.
html {
font-family: Arial, Helvetica, sans-serif;
text-align: center;
}
h1 {
font-size: 1.8rem;
color: white;
}
.topnav {
overflow: hidden;
background-color: #0A1128;
}
body {
margin: 0;
}
.content {
padding: 50px;
}
.card-grid {
max-width: 800px;
margin: 0 auto;
display: grid;
grid-gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.card {
background-color: white;
box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
}
.card-title {
font-size: 1.2rem;
font-weight: bold;
color: #034078
}
.state {
font-size: 1.2rem;
color:#1282A2;
}
button {
border: none;
color: #FEFCFB;
padding: 15px 32px;
text-align: center;
font-size: 16px;
width: 150px;
border-radius: 4px;
transition-duration: 0.4s;
}
.button-on {
background-color:#034078;
}
.button-on:hover {
background-color: #1282A2;
}
.button-off {
background-color:#858585;
}
.button-off:hover {
background-color: #252524;
}
.button-stop {
background-color:#5e0f0f;
width: 100%;
}
.button-stop:hover {
background-color: #9b332c;
}
ESP8266 Web Server: Control a DC Motor – Arduino Sketch
The following code creates a web server that serves the webpage you’ve created previously to control a DC motor remotely using a web browser on the local network.
/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete instructions at https://RandomNerdTutorials.com/esp8266-nodemcu-web-server-dc-motor-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <LittleFS.h>
// Motor A pins
int motor1Pin1 = 12;
int motor1Pin2 = 14;
int enable1Pin = 13;
// 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);
// Initialize LittleFS
void initFS() {
if (!LittleFS.begin()) {
Serial.println("An error has occurred while mounting LittleFS");
}
else {
Serial.println("LittleFS mounted successfully");
}
}
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void moveForward(){
Serial.println("Moving Forward");
digitalWrite(enable1Pin, HIGH);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, HIGH);
}
void moveBackward(){
Serial.println("Moving Backward");
digitalWrite(enable1Pin, HIGH);
digitalWrite(motor1Pin1, HIGH);
digitalWrite(motor1Pin2, LOW);
}
void stopMotor(){
digitalWrite(enable1Pin, LOW);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
}
void setup() {
Serial.begin(115200);
// Set motor pins as outputs
pinMode(motor1Pin1, OUTPUT);
pinMode(motor1Pin2, OUTPUT);
pinMode(enable1Pin, OUTPUT);
initWiFi();
initFS();
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html", "text/html");
});
server.serveStatic("/", LittleFS, "/");
server.on("/forward", HTTP_GET, [](AsyncWebServerRequest *request) {
moveForward();
request->send(LittleFS, "/index.html", "text/html", false);
});
server.on("/backward", HTTP_GET, [](AsyncWebServerRequest *request) {
moveBackward();
request->send(LittleFS, "/index.html", "text/html", false);
});
server.on("/stop", HTTP_GET, [](AsyncWebServerRequest *request) {
stopMotor();
request->send(LittleFS, "/index.html", "text/html", false);
});
server.begin();
}
void loop() {
}
You just need to insert your network credentials and upload the filesystem image and the code will work straight away.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_SSID";
How the Code Works
Continue reading to learn how the code works or skip to the Demonstration section.
Including Libraries
First, include the required libraries to connect to Wi-Fi, create the web server and use the LittleFS filesystem.
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <LittleFS.h>
Motor Pins
Define the GPIOs that will be controlling the motor.
// Motor A pins
int motor1Pin1 = 12;
int motor1Pin2 = 14;
int enable1Pin = 13;
Network Credentials
Insert your network credentials on the following variables so that the ESP8266 connects to your network.
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_SSID";
Creating a Server Object
Create an AsyncWebServer object called server on port 80.
AsyncWebServer server(80);
Initialize LittleFS
The following function initFS() initializes the LittleFS filesystem. We’ll call it later in the setup().
void initFS() {
if (!LittleFS.begin()) {
Serial.println("An error has occurred while mounting LittleFS");
}
else {
Serial.println("LittleFS mounted successfully");
}
}
Initialize Wi-Fi
The initWiFi() function connects to wi-fi using the SSID and password you’ve defined previously.
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
Functions to Control the DC Motors
We create three functions to control the DC Motor.
The moveForward() function will move the motor forward.
void moveForward(){
Serial.println("Moving Forward");
digitalWrite(enable1Pin, HIGH);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, HIGH);
}
The moveBackward() function moves the motor backward.
void moveBackward(){
Serial.println("Moving Backward");
digitalWrite(enable1Pin, HIGH);
digitalWrite(motor1Pin1, HIGH);
digitalWrite(motor1Pin2, LOW);
}
Finally, the stopMotor() function stops the motor by setting all motor pins to LOW.
void stopMotor(){
Serial.print("Motor Stopped")
digitalWrite(enable1Pin, LOW);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
}
setup()
In the setup(), initialize the Serial Monitor for debugging purposes.
Serial.begin(115200);
Set the motor pins as outputs.
// Set motor pins as outputs
pinMode(motor1Pin1, OUTPUT);
pinMode(motor1Pin2, OUTPUT);
pinMode(enable1Pin, OUTPUT);
Initialize Wi-Fi by calling the initWiFi() function.
initWiFi();
Initialize the LittleFS filesystem by calling the initFS() function we created previously.
initFS();
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(LittleFS, "/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 (LittleFS). So, we can simply add the following line to serve files in a directory when requested by the root URL—this way, the CSS file will be served automatically.
server.serveStatic("/", LittleFS, "/");
When you click the Forward button, you make a request on the /forward path. When the ESP8266 receives that request, it will call the moveForward() function to make the motor move forward.
server.on("/forward", HTTP_GET, [](AsyncWebServerRequest *request) {
moveForward();
request->send(LittleFS, "/index.html", "text/html", false);
});
Similarly, when you click the Backward button, the ESP8266 receives a request on the /backward path. When that happens, call the moveBackward() function to make the motor move in the other direction.
server.on("/backward", HTTP_GET, [](AsyncWebServerRequest *request) {
moveBackward();
request->send(LittleFS, "/index.html", "text/html", false);
});
When you click the Stop button, the ESP8266 receives a request on the /stop path and calls the stopMotor() function.
server.on("/stop", HTTP_GET, [](AsyncWebServerRequest *request) {
stopMotor();
request->send(LittleFS, "/index.html", "text/html", false);
});
Initialize the Server
Finally, call the begin() method on the server object to initialize the server.
server.begin();
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.
Upload Files to the Filesystem
With the HTML and CSS files saved in the data folder, you can now upload them to the board. Make sure you have the Filesystem Uploader Plugin installed.
Select the ESP8266 board you’re using (Tools > Board) and select the right COM port (Tools > Port).
Then, upload the files to the ESP8266 board. Press [Ctrl] + [Shift] + [P] on Windows or [⌘] + [Shift] + [P] on MacOS to open the command palette. Search for the Upload LittleFS to Pico/ESP8266/ESP32 and click on it.
Important: ensure the Serial Monitor is closed. Otherwise, the upload will fail.
After a few seconds, you should get the message “Completed upload. “. The files were successfully uploaded to the ESP8266 filesystem.
Upload the Code
Then, upload the code to your ESP8266 board (make sure you’ve added your network credentials in the code).
Demonstration
When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200.
Press the ESP8266 RST button, and it should print the ESP8266 IP address.
With the motor connected to the ESP8266 via the L298N motor driver and powered up with an external power supply, open any browser on your local network and type the ESP8266 IP address. The following web page will load.
Click on the buttons to control the DC motor.
The server can handle multiple clients simultaneously. You can also control the DC motor from your smartphone as long as it is connected to your local network.
Wrapping Up
In this tutorial, you’ve learned how to create a simple asynchronous web server with the ESP8266 to control a DC motor remotely from your computer or smartphone. You can now extend this project to control more motors or control other outputs or even display sensor readings. You can take a look at the following tutorials:
- ESP8266 Web Server: Display Sensor Readings in Gauges
- ESP8266 Web Server: Control Stepper Motor (WebSocket)
- ESP8266 Web Server (WebSocket) with Multiple Sliders: Control LEDs Brightness (PWM)
- ESP8266 Web Server using Server-Sent Events (Update Sensor Readings Automatically)
If you would like to learn more about building web servers with the ESP8266 from scratch, we recommend taking a look at our exclusive eBook:
Thanks for reading.
Hi – good article thank you.
Is this an error, a typo ?
“Finally, the stopMotor() function stops the motor by setting all motor pins to LOW.
void stopMotor(){
Serial.print(“Motor Stopped”)
digitalWrite(enable1Pin, LOW);
digitalWrite(motor1Pin1, HIGH);
digitalWrite(motor1Pin2, LOW);
}”
I would expect “LOW, LOW & LOW” but it will work as expected as it is.
It is in the code and in the explanations below it.
Hi.
You are right. It’s a typo. I’ll fix it.
Thanks for pointing that out.
Regards,
Sara
Thanks for the article;
I am very new to ESP8266 but I have done a lot of projects on Arduino.
Can the webserver and all the “LittleFS” stuff be expected to work on a Wemos D1 with ESP8266 ?
Do I try this project on a WemosD1 (it is the only 8266 board I have to start testing)
Hi.
Yes. It should work in a Wemos D1 mini.
Regards,
Sara
192.168.90.214 not working, This 192.168.90.214 page can’t be found
No webpage was found for the web address: http://192.168.90.214/
HTTP ERROR 404,
but..!
Executing task: C:\Users\varun M G.platformio\penv\Scripts\platformio.exe device monitor –environment nodemcuv2
— Terminal on COM7 | 115200 8-N-1
— Available filters and text transformations: colorize, debug, default, direct, esp8266_exception_decoder, hexlify, log2file, nocontrol, printable, send_on_enter, time
— More details at https://bit.ly/pio-monitor-filters
— Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H
��␂�␛�o��s��o|�␌$␄�␌l
␂␜b�␛␃␌�|␂r�␃l�o�␄�n�␀␄$
␂��r�d�l␛�␄␌␌�Connecting to WiFi ..………192.168.90.214
LittleFS mounted successfully
Hi.
You probably didn’t upload the filesystem image.
Make sure you upload the files to the filesystem before running the web server code.
Regards,
Sara