Making A Web Server Using ESP32 to Control LED via WiFi Communication

ESP32 Project #8

Nadya Laurentia
7 min readMar 27, 2021

Hello fellows!

Welcome to the 8th Project : WiFi Communication - Controlling Devices! Menurutku, project kali ini adalah project yang paling menarik so far karena bisa bikin web server sendiri buat mengendalikan LED dari jarak jauh. Kendalinya ini menggunakan WiFi yang dimiliki oleh ESP32. Keren banget, kan? Yuk langsung bahas aja!

What You‘ll Need

Eksperimen kali ini menggunakan referensi dari Random Nerd Tutorials. Di referensi tersebut, ada 2 buah LED yang akan dikendalikan melalui web server. But, supaya lebih challenging, aku mau langsung coba pake 4 buah LED karena aku punya 4 warna LED. Komponen yang dibutuhkan untuk project ini cukup simple, yaitu :

  • 1 buah ESP32 Development Board
  • 2 buah breadboard
  • 1 helai kabel micro-USB
  • 5 helai jumper wire male-to-male
  • 4 buah LED (kalau bisa beda warna)
  • 4 buah resistor 330 Ohm
  • 1 buah smartphone (atau device lain yang bisa akses website)

How It Will Look Like

Semua komponen di atas bakal dirangkai seperti skema di bawah ini :

Skema Project WiFi Communication - Controlling Devices

Semua LED yang digunakan ini harus dihubungkan ke GPIO pada ESP32. Aku menggunakan GPIO 2 untuk LED Biru, GPIO 5 untuk LED Merah, GPIO 21 untuk LED Kuning, dan GPIO23 untuk LED Hijau. Supaya rangkaian terlihat lebih rapi, aku menggunakan jumper wire yang warnanya sama dengan LED untuk menghubungkan LED ke GPIO.

The Magic Spell

Setelah rangkaian selesai, kita harus memprogram ESP32-nya. Code yang digunakan pada project ini merupakan modifikasi dari code pada referensi yaitu Random Nerd Tutorials. Hasil modifikasi code yang akan dipakai itu :

// Load Wi-Fi library
#include <WiFi.h>
// Replace with your network credentials
const char* ssid = "naadd";
const char* password = "croissant";
// Set web server port number to 80
WiFiServer server(80);
// Variable to store the HTTP request
String header;
// Auxiliar variables to store the current output state
String output23State = "off";
String output21State = "off";
String output5State = "off";
String output2State = "off";
// Assign output variables to GPIO pins
const int output23 = 23; //green
const int output21 = 21; //yellow
const int output5 = 5; //red
const int output2 = 2; //blue
// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;
void setup() {
Serial.begin(115200);
// Initialize the output variables as outputs
pinMode(output23, OUTPUT);
pinMode(output21, OUTPUT);
pinMode(output5, OUTPUT);
pinMode(output2, OUTPUT);
// Set outputs to LOW
digitalWrite(output23, LOW);
digitalWrite(output21, LOW);
digitalWrite(output5, LOW);
digitalWrite(output2, LOW);
// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
void loop(){
WiFiClient client = server.available(); // Listen for incoming clients
if (client) { // If a new client connects,
currentTime = millis();
previousTime = currentTime;
Serial.println("New Client."); // print a message out in the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
currentTime = millis();
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
header += c;
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();

// turns the GPIOs on and off
if (header.indexOf("GET /GREEN/on") >= 0) {
Serial.println("GREEN ON");
output23State = "on";
digitalWrite(output23, HIGH);
} else if (header.indexOf("GET /GREEN/off") >= 0) {
Serial.println("GREEN OFF");
output23State = "off";
digitalWrite(output23, LOW);
} else if (header.indexOf("GET /YELLOW/on") >= 0) {
Serial.println("YELLOW ON");
output21State = "on";
digitalWrite(output21, HIGH);
} else if (header.indexOf("GET /YELLOW/off") >= 0) {
Serial.println("YELLOW OFF");
output21State = "off";
digitalWrite(output21, LOW);
} else if (header.indexOf("GET /RED/on") >= 0) {
Serial.println("RED ON");
output5State = "on";
digitalWrite(output5, HIGH);
} else if (header.indexOf("GET /RED/off") >= 0) {
Serial.println("RED OFF");
output5State = "off";
digitalWrite(output5, LOW);
} else if (header.indexOf("GET /BLUE/on") >= 0) {
Serial.println("YELLOW ON");
output2State = "on";
digitalWrite(output2, HIGH);
} else if (header.indexOf("GET /BLUE/off") >= 0) {
Serial.println("BLUE OFF");
output2State = "off";
digitalWrite(output2, LOW);
}


// Display the HTML web page
client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\">");
// CSS to style the on/off buttons
// Feel free to change the background-color and font-size attributes to fit your preferences
client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
client.println(".button2 {background-color: #555555;}</style></head>");

// Web Page Heading
client.println("<body><h1>Hello Fellows!</h1>");
client.println("<body><h2>Welcome to Nadya's Web Server</h2>");


// Display current state, and ON/OFF buttons for GREEN LED
client.println("<p>GREEN - State " + output23State + "</p>");
// If the output26State is off, it displays the ON button
if (output23State=="off") {
client.println("<p><a href=\"/GREEN/on\"><button class=\"button\">ON</button></a></p>");
} else {
client.println("<p><a href=\"/GREEN/off\"><button class=\"button button2\">OFF</button></a></p>");
}

// Display current state, and ON/OFF buttons for YELLOW LED
client.println("<p>YELLOW - State " + output21State + "</p>");
// If the output27State is off, it displays the ON button
if (output21State=="off") {
client.println("<p><a href=\"/YELLOW/on\"><button class=\"button\">ON</button></a></p>");
} else {
client.println("<p><a href=\"/YELLOW/off\"><button class=\"button button2\">OFF</button></a></p>");
}

// Display current state, and ON/OFF buttons for RED LED
client.println("<p>RED - State " + output5State + "</p>");
// If the output27State is off, it displays the ON button
if (output5State=="off") {
client.println("<p><a href=\"/RED/on\"><button class=\"button\">ON</button></a></p>");
} else {
client.println("<p><a href=\"/RED/off\"><button class=\"button button2\">OFF</button></a></p>");
}
// Display current state, and ON/OFF buttons for BLUE LED
client.println("<p>BLUE - State " + output2State + "</p>");
// If the output27State is off, it displays the ON button
if (output2State=="off") {
client.println("<p><a href=\"/BLUE/on\"><button class=\"button\">ON</button></a></p>");
} else {
client.println("<p><a href=\"/BLUE/off\"><button class=\"button button2\">OFF</button></a></p>");
}


client.println("</body></html>");

// The HTTP response ends with another blank line
client.println();
// Break out of the while loop
break;
} else { // if you got a newline, then clear currentLine
currentLine = "";
}
} else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// Clear the header variable
header = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}

Lines yang aku bold itu yang aku modifikasi. Rangkuman modifikasinya itu :

  1. SSID & Password. Bagian ini wajib banget kalian modifikasi, sesuaikan dengan SSID dan password WiFi yang akan kalian gunakan.
  2. Variabel, setup(), dan loop() untuk LED. Karena di referensi hanya memakai 2 buah LED sedangkan aku memakai 4 buah, perlu dilakukan modifikasi pada bagian-bagian yang menyangkut LED. Bagian-bagian tersebut adalah pendeklarasian variabel, setup(), dan program utama di loop(). Modifikasinya gampang kok soalnya tinggal copy-paste dan sesuaikan nama-nama variabelnya aja.
  3. HTML. Aku buat modifikasi untuk web page heading dan tentu modifikasi pada tombol untuk mengendalikan LED karena aku nambah 2 buah LED. Sama seperti sebelumnya, modifikasi terkait LED tinggal copy-paste dan sesuaikan aja.

Let’s Get It!

Rangkaian udah, code udah, sooo langsung aja kita coba! Ini video aku waktu merangkai dan eksekusi percobaannya :

The Result & Lesson Learned

Ternyata berhasil gaesss! Keren banget! Sebenernya itu kalau smartphone-nya di bawa ke tempat yang agak jauh pun masih bisa mengendalikan LED-nya, cuma agak susah divideoinnya jadi ga bisa aku kasih lihat dehh:( By the way, video itu adalah hasil dari beberapa kali mencoba dan gagal. Kegagalan yang aku alami waktu eksperimen ini adalah :

  1. WiFi-nya connecting terus. Awalnya aku bingung SSID dan password-nya dari mana jadi aku define sendiri gitu. WiFi dengan SSID dan password itu kan “ngasal” jadi pastinya ga mungkin ketemu, bakal connecting terus. Harusnya tulis SSID dan password dari WiFi yang bakal dipakai. SSID itu nama WiFi-nya, hal ini bisa kalian cek di WiFi Settings, klik WiFi yang mau dipakai, lalu cek properties-nya.
  2. Can’t reach the site. Setelah berhasil connected ke WiFi di rumah dan dapat IP address-nya, ternyata website-nya ga bisa diakses. Lalu, aku coba connect ke WiFi dari smartphone (mobile hotspot). Ternyata kalau pakai WiFi ini, website bisa diakses. Sampai sekarang aku juga belum tahu kenapa. Dugaanku sih karena provider jaringan WiFi-ku ga memperbolehkan akses ke website itu, tetapi belum yakin sih. Mungkin kalau kalian tahu kenapa, tolong kasih tau aku yaa🥺 FYI, WiFi-ku MyRepubl*c.
  3. Tombol di webpage ga berhasil mengendalikan LED. Setelah aku pakai mobile hotspot, aku bisa akses webpage tapi ternyata tombolnya ga berfungsi. Setelah aku telusuri Serial Monitor, ternyata penyebabnya adalah salah modifikasi code. Di bagian “turns the GPIOs on and off”, aku modifikasi kalimat di “header.indexOf” dan jadi ga sesuai dengan kalimat request yang diset di bagian “href” untuk button (bagian HTML yang “Display current state, and ON/OFF buttons for LED”). Kalimat di dalam “header.indexOf” itu strukturnya harus “GET [href di button]”.
  4. Wiring. Setelah semua masalah software sudah solved, ternyata hardware bermasalah juga. Masalahnya di LED Hijau yang tidak bisa menyala. Ternyata hal ini karena LED Hijaunya kurang masuk ke breadboard. Kemudian LED merah juga tidak bisa menyala. Masalahnya ternyata di resistor yang salah pin di breadboard sehingga tidak terhubung ke ground. Makanya harus teliti ya gaes kalo wiring supaya ga mengulangi kesalahan yang aku perbuat ini!^^

Setelah beberapa kali mencoba, akhirnya berhasil seperti di video yeayy! Kuncinya adalah teliti dan pantang menyerah. Banyak-banyak juga cari referensi supaya lebih paham tentang alur code-nya. Anyway, kesimpulannyaaaa

Project 8 : Successful!

Sekian cerita aku soal project WiFi Communication- Controlling Devices, semoga bisa bermanfaat dan membantu kalian. Selamat mencoba dan ingat jangan nyerah yaa~ See you in the next project!

Adiós amigos!

--

--