#include <WiFi.h>
#include <WebServer.h>
// Wokwi-specific WiFi (no password needed)
const char* ssid = "Wokwi-GUEST";
const char* password = "";
WebServer server(80);
// GPIO pins for 4 traffic lights (each has R, Y, G)
const int redPins[4] = {32, 26, 19, 16};
const int yellowPins[4] = {33, 27, 18, 17};
const int greenPins[4] = {25, 14, 5, 4};
const int buttonPin = 34; // push button to toggle manual mode
bool manualMode = false;
int activeLane = 0; // 0-3
unsigned long lastChange = 0;
unsigned long normalInterval = 30000; // 30 seconds
bool allRedPhase = false;
unsigned long allRedStart = 0;
// Function to set specific lane color
void setLaneColor(int lane, bool red, bool yellow, bool green) {
digitalWrite(redPins[lane], red);
digitalWrite(yellowPins[lane], yellow);
digitalWrite(greenPins[lane], green);
}
// Function to set only one lane green, others red
void setLaneGreen(int lane) {
for (int i = 0; i < 4; i++) {
if (i == lane) {
digitalWrite(redPins[i], LOW);
digitalWrite(yellowPins[i], LOW);
digitalWrite(greenPins[i], HIGH);
} else {
digitalWrite(redPins[i], HIGH);
digitalWrite(yellowPins[i], LOW);
digitalWrite(greenPins[i], LOW);
}
}
}
// Web page handler
void handleRoot() {
String html = "<!DOCTYPE html><html><head><meta name='viewport' content='width=device-width'>";
html += "<title>Traffic Light Control</title><style>";
html += "body{font-family:Arial;margin:20px;text-align:center;background:#1a1a2e;color:white}";
html += ".lane{display:inline-block;margin:20px;padding:20px;border:2px solid #444;border-radius:10px;background:#16213e}";
html += ".light{width:60px;height:60px;border-radius:50%;margin:10px auto;transition:0.3s}";
html += ".red{background:#600}.red.active{background:#ff0000;box-shadow:0 0 20px red}";
html += ".yellow{background:#660}.yellow.active{background:#ffff00;box-shadow:0 0 20px yellow}";
html += ".green{background:#060}.green.active{background:#00ff00;box-shadow:0 0 20px #0f0}";
html += "button{padding:12px 24px;margin:10px;font-size:16px;background:#0f3460;color:white;border:none;border-radius:5px;cursor:pointer}";
html += "button:hover{background:#e94560}";
html += ".mode{margin:20px;font-size:28px}";
html += ".auto{color:#0f0}.manual{color:#f00}";
html += "</style></head><body>";
html += "<h1>🚦 Smart Traffic Management System 🚦</h1>";
html += "<div class='mode'>Mode: <span class='" + String(manualMode ? "manual" : "auto") + "'>" + String(manualMode ? "🔧 MANUAL" : "🤖 AUTO") + "</span></div>";
html += "<button onclick=\"fetch('/toggle')\">🔄 Toggle Manual/Auto</button>";
for (int i = 0; i < 4; i++) {
html += "<div class='lane'><h2>Lane " + String(i+1) + "</h2>";
html += "<div class='light red " + String(digitalRead(redPins[i]) ? "active" : "") + "'></div>";
html += "<div class='light yellow " + String(digitalRead(yellowPins[i]) ? "active" : "") + "'></div>";
html += "<div class='light green " + String(digitalRead(greenPins[i]) ? "active" : "") + "'></div>";
if (manualMode) {
html += "<button onclick=\"fetch('/setlane?lane=" + String(i) + "')\">🟢 Set Green</button>";
}
html += "</div>";
}
html += "<script>setInterval(function(){location.reload()},3000);</script>";
html += "</body></html>";
server.send(200, "text/html", html);
}
// Toggle manual/auto mode
void handleToggle() {
manualMode = !manualMode;
if (!manualMode) {
setLaneGreen(0);
activeLane = 0;
lastChange = millis();
allRedPhase = false;
}
server.send(200, "text/plain", manualMode ? "MANUAL" : "AUTO");
}
// Set specific lane to green (manual mode only)
void handleSetLane() {
if (manualMode && server.hasArg("lane")) {
int lane = server.arg("lane").toInt();
if (lane >= 0 && lane < 4) {
setLaneGreen(lane);
}
}
server.send(200, "text/plain", "OK");
}
void setup() {
Serial.begin(115200);
// Initialize all LED pins
for (int i = 0; i < 4; i++) {
pinMode(redPins[i], OUTPUT);
pinMode(yellowPins[i], OUTPUT);
pinMode(greenPins[i], OUTPUT);
}
pinMode(buttonPin, INPUT_PULLUP);
// Start with Lane 0 Green, all others Red
for (int i = 0; i < 4; i++) {
digitalWrite(redPins[i], HIGH);
digitalWrite(yellowPins[i], LOW);
digitalWrite(greenPins[i], LOW);
}
digitalWrite(greenPins[0], HIGH);
digitalWrite(redPins[0], LOW);
// Connect to Wokwi WiFi (no password, channel 6 for faster connection)
Serial.print("Connecting to WiFi");
WiFi.begin(ssid, password, 6);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
Serial.println("\nConnected!");
Serial.print("ESP32 IP address: ");
Serial.println(WiFi.localIP());
// Setup web routes
server.on("/", handleRoot);
server.on("/toggle", handleToggle);
server.on("/setlane", handleSetLane);
server.begin();
Serial.println("Web server started");
Serial.println("Open browser to: http://" + WiFi.localIP().toString());
lastChange = millis();
}
void loop() {
server.handleClient();
// Check button press (toggle manual mode)
if (digitalRead(buttonPin) == LOW) {
delay(50); // debounce
if (digitalRead(buttonPin) == LOW) {
manualMode = !manualMode;
Serial.print("Manual mode: ");
Serial.println(manualMode ? "ON" : "OFF");
if (!manualMode) {
setLaneGreen(0);
activeLane = 0;
lastChange = millis();
allRedPhase = false;
}
while (digitalRead(buttonPin) == LOW) delay(10);
}
}
// Normal mode sequence
if (!manualMode) {
unsigned long now = millis();
if (allRedPhase) {
if (now - allRedStart >= 2000) { // 2 sec all-red
allRedPhase = false;
activeLane = (activeLane + 1) % 4;
setLaneGreen(activeLane);
lastChange = now;
Serial.print("Switched to Lane ");
Serial.println(activeLane + 1);
}
} else {
if (now - lastChange >= normalInterval) {
// Start all-red phase
allRedPhase = true;
allRedStart = now;
// Turn all red
for (int i = 0; i < 4; i++) {
digitalWrite(redPins[i], HIGH);
digitalWrite(yellowPins[i], LOW);
digitalWrite(greenPins[i], LOW);
}
Serial.println("All-Red phase (2 seconds)");
}
}
}
}