In this tutorial, we are going to make an IoT based Smart Traffic Light system. We will connect the lights by using ESP32. Let’s begin!
Contents:
Introduction
First of all, we will create a web server using ESP32. After accessing the web server, the person will see three options. Basically, they will be the three lights of the system. To that, we will also keep updating the status of all the lights so that the person need not stay near the lights to observe them. Moreover, the changes could also be seen in the Serial monitor of Arduino.
In this project, I will be using a single RGB LED to show three colors for the same. For that, we need three GPIO pins of the NodeMCU. Since the LED which I am using is Common Anode, so for that only I have made the circuit. Change the common pin to GND and do the other necessary changes if you have Common Cathode type LED.
Materials Required
- NodeMCU
- LED-3 (or a RGB LED)
- Jumper wires
- Resistor
Circuit
The circuit is quite simple. You just need to join the four pins of the RGB LED and just power the NodeMCU. There is nothing much complex in this part. Refer the diagram given below.
Code and Explanation
The most important part of this project is the code. We are not only using the C/C++ for Arduino. Rather, we also need to write some HTML part to design our user interface. However, that won’t be a big issue. Refer the code given below.
#include <WiFi.h>
#include <WebServer.h>
const char* ssid = "ESP32"; // Enter SSID here
const char* password = "12345678"; //Enter Password here
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);
WebServer server(80);
uint8_t LED1pin = 4;
bool LED1status = LOW;
uint8_t LED2pin = 5;
bool LED2status = LOW;
uint8_t LED3pin = 19;
bool LED3status = LOW;
void setup() {
Serial.begin(115200);
pinMode(LED1pin, OUTPUT);
pinMode(LED2pin, OUTPUT);
pinMode(LED3pin, OUTPUT);
WiFi.softAP(ssid, password);
WiFi.softAPConfig(local_ip, gateway, subnet);
delay(100);
server.on("/", handle_OnConnect);
server.on("/led1on", handle_led1on);
server.on("/led1off", handle_led1off);
server.on("/led2on", handle_led2on);
server.on("/led2off", handle_led2off);
server.on("/led3on", handle_led3on);
server.on("/led3off", handle_led3off);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop() {
server.handleClient();
if(LED1status)
{digitalWrite(LED1pin, LOW);}
else
{digitalWrite(LED1pin, HIGH);}
if(LED2status)
{digitalWrite(LED2pin, LOW);}
else
{digitalWrite(LED2pin, HIGH);}
if(LED3status)
{digitalWrite(LED3pin, LOW);}
else
{digitalWrite(LED3pin, HIGH);}
}
void handle_OnConnect() {
LED1status = LOW;
LED2status = LOW;
LED3status = LOW;
Serial.println("GPIO4 Status: OFF | GPIO5 Status: OFF | GPIO19 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,LED2status,LED3status));
}
void handle_led1on() {
LED1status = HIGH;
Serial.println("GPIO4 Status: ON");
server.send(200, "text/html", SendHTML(true,LED2status,LED3status));
}
void handle_led1off() {
LED1status = LOW;
Serial.println("GPIO4 Status: OFF");
server.send(200, "text/html", SendHTML(false,LED2status,LED3status));
}
void handle_led2on() {
LED2status = HIGH;
Serial.println("GPIO5 Status: ON");
server.send(200, "text/html", SendHTML(LED1status,true,LED3status));
}
void handle_led2off() {
LED2status = LOW;
Serial.println("GPIO5 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,false,LED3status));
}
void handle_led3on() {
LED3status = HIGH;
Serial.println("GPIO19 Status: ON");
server.send(200, "text/html", SendHTML(LED1status,LED2status,true));
}
void handle_led3off() {
LED3status = LOW;
Serial.println("GPIO19 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,LED2status,false));
}
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
String SendHTML(uint8_t led1stat,uint8_t led2stat, uint8_t led3stat){
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>LED Control</title>\n";
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
ptr +=".button {display: block;width: 80px;background-color: #3498db;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n";
ptr +=".button-on {background-color: #3498db;}\n";
ptr +=".button-on:active {background-color: #2980b9;}\n";
ptr +=".button-off {background-color: #34495e;}\n";
ptr +=".button-off:active {background-color: #2c3e50;}\n";
ptr +="p {font-size: 14px;color: #888;margin-bottom: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<h1>Control Room</h1>\n";
ptr +="<h3>Traffic Light System</h3>\n";
if(led1stat)
{ptr +="<p>Blue LED Status: ON</p><a class=\"button button-off\" href=\"/led1off\">OFF</a>\n";}
else
{ptr +="<p>Blue LED Status: OFF</p><a class=\"button button-on\" href=\"/led1on\">ON</a>\n";}
if(led2stat)
{ptr +="<p>Green LED Status: ON</p><a class=\"button button-off\" href=\"/led2off\">OFF</a>\n";}
else
{ptr +="<p>Green LED Status: OFF</p><a class=\"button button-on\" href=\"/led2on\">ON</a>\n";}
if(led3stat)
{ptr +="<p>Red LED Status: ON</p><a class=\"button button-off\" href=\"/led3off\">OFF</a>\n";}
else
{ptr +="<p>Red LED Status: OFF</p><a class=\"button button-on\" href=\"/led3on\">ON</a>\n";}
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
We will first set the ESP32 as our board. In case of any doubt, Read my previous article on how to configure NodeMCU with Arduino.
#include <WiFi.h>
#include <WebServer.h>
const char* ssid = "ESP32"; // Enter SSID here
const char* password = "12345678"; //Enter Password here
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);
WebServer server(80);
uint8_t LED1pin = 4;
bool LED1status = LOW;
uint8_t LED2pin = 5;
bool LED2status = LOW;
uint8_t LED3pin = 19;
bool LED3status = LOW;
First of all. we have included the desired library for the project. You can download them although they are default for the board. We then set the “SSID” i.e. the name we will give to the server that we will create along with the password. After that, we define the LED pins and their status. We have then created the Web server communication. On a Web server or Hypertext Transfer Protocol daemon port 80 is the port that the server listens to or expects to receive from a Web client . The IP addresses are then set here.
void setup() {
Serial.begin(115200);
pinMode(LED1pin, OUTPUT);
pinMode(LED2pin, OUTPUT);
pinMode(LED3pin, OUTPUT);
WiFi.softAP(ssid, password);
WiFi.softAPConfig(local_ip, gateway, subnet);
delay(100);
server.on("/", handle_OnConnect);
server.on("/led1on", handle_led1on);
server.on("/led1off", handle_led1off);
server.on("/led2on", handle_led2on);
server.on("/led2off", handle_led2off);
server.on("/led3on", handle_led3on);
server.on("/led3off", handle_led3off);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("HTTP server started");
}
After this, we have set the setup() function. Here we need to start the server and the serial communication using .begin() function. Since we are working on AP mode, so, we have used the .softAP method. The Pin Mode is also set up here. At the end, various commands, which will be called while we switch on/off the lights, are also called in this part.
void loop() {
server.handleClient();
if(LED1status)
{digitalWrite(LED1pin, LOW);}
else
{digitalWrite(LED1pin, HIGH);}
if(LED2status)
{digitalWrite(LED2pin, LOW);}
else
{digitalWrite(LED2pin, HIGH);}
if(LED3status)
{digitalWrite(LED3pin, LOW);}
else
{digitalWrite(LED3pin, HIGH);}
}
Then comes the loop() function. We have set the basic on/off setup here. Remember, since I have used a Common Anode LED, so by keeping it low, it will light up. Be alert in this step.
void handle_OnConnect() {
LED1status = LOW;
LED2status = LOW;
LED3status = LOW;
Serial.println("GPIO4 Status: OFF | GPIO5 Status: OFF | GPIO19 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,LED2status,LED3status));
}
void handle_led1on() {
LED1status = HIGH;
Serial.println("GPIO4 Status: ON");
server.send(200, "text/html", SendHTML(true,LED2status,LED3status));
}
void handle_led1off() {
LED1status = LOW;
Serial.println("GPIO4 Status: OFF");
server.send(200, "text/html", SendHTML(false,LED2status,LED3status));
}
void handle_led2on() {
LED2status = HIGH;
Serial.println("GPIO5 Status: ON");
server.send(200, "text/html", SendHTML(LED1status,true,LED3status));
}
void handle_led2off() {
LED2status = LOW;
Serial.println("GPIO5 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,false,LED3status));
}
void handle_led3on() {
LED3status = HIGH;
Serial.println("GPIO19 Status: ON");
server.send(200, "text/html", SendHTML(LED1status,LED2status,true));
}
void handle_led3off() {
LED3status = LOW;
Serial.println("GPIO19 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,LED2status,false));
}
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
Now, we need to define the functions which will be called on the web, when we want to switch on. Starting with handle_OnConnect() to the status and the error.
String SendHTML(uint8_t led1stat,uint8_t led2stat, uint8_t led3stat){
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>LED Control</title>\n";
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
ptr +=".button {display: block;width: 80px;background-color: #3498db;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n";
ptr +=".button-on {background-color: #3498db;}\n";
ptr +=".button-on:active {background-color: #2980b9;}\n";
ptr +=".button-off {background-color: #34495e;}\n";
ptr +=".button-off:active {background-color: #2c3e50;}\n";
ptr +="p {font-size: 14px;color: #888;margin-bottom: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<h1>Control Room</h1>\n";
ptr +="<h3>Traffic Light System</h3>\n";
if(led1stat)
{ptr +="<p>Blue LED Status: ON</p><a class=\"button button-off\" href=\"/led1off\">OFF</a>\n";}
else
{ptr +="<p>Blue LED Status: OFF</p><a class=\"button button-on\" href=\"/led1on\">ON</a>\n";}
if(led2stat)
{ptr +="<p>Green LED Status: ON</p><a class=\"button button-off\" href=\"/led2off\">OFF</a>\n";}
else
{ptr +="<p>Green LED Status: OFF</p><a class=\"button button-on\" href=\"/led2on\">ON</a>\n";}
if(led3stat)
{ptr +="<p>Red LED Status: ON</p><a class=\"button button-off\" href=\"/led3off\">OFF</a>\n";}
else
{ptr +="<p>Red LED Status: OFF</p><a class=\"button button-on\" href=\"/led3on\">ON</a>\n";}
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
This section consists of the HTML code for the server. All the headings, etc. are set here only. With this, we complete our code and now we are ready to run our code.
Final Run
After successfully writing the code, we are ready to upload it. Set the board as per the one you are using. I am using the DOIT ESP32 DEVKIT V1. After successfully uploading the code, open the serial monitor. You will see the message, ” HTTP server started”. After that, you can see the status of your LED. Once you see that, copy the Local IP address, 192.168.1.1 in this case. Before that, open your wifi and you would be able to see the ESP32 Server. Connect with it.
Now open a browser and enter the IP address that you copied. You will soon be able to see this.
I hope you could cope up with every step and complete this Smart Traffic Light System. In case of any problem, feel free to comment. Happy Learning!