// === Seth Evans ====
// Final Project: Multi-Intersection Traffic Light with IoT Access
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqttServer = "test.mosquitto.org";
int port = 1883;
WiFiClient espClient;
PubSubClient client(espClient);
LiquidCrystal_I2C lcd(0x27, 16, 2); // Try 0x3F if LCD doesn’t display
// LED Pins
const int redNS = 14, yellowNS = 12, greenNS = 13;
const int redEW = 25, yellowEW = 26, greenEW = 27;
const int blueEmergencyLED = 16;
// Buzzer & Button
const int buzzerPin = 32;
const int crossWalkButton = 19;
// State variables
volatile int crossWalkButtonState = 1;
int iotControl = 0; // 0 = Normal, 1 = Emergency
char clientId[50];
void setup() {
Serial.begin(115200);
delay(10);
randomSeed(analogRead(0));
// WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected");
client.setServer(mqttServer, port);
client.setCallback(callback);
// LCD
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("=== CEIS-114 ===");
// Pins
pinMode(redNS, OUTPUT); pinMode(yellowNS, OUTPUT); pinMode(greenNS, OUTPUT);
pinMode(redEW, OUTPUT); pinMode(yellowEW, OUTPUT); pinMode(greenEW, OUTPUT);
pinMode(blueEmergencyLED, OUTPUT);
pinMode(buzzerPin, OUTPUT);
pinMode(crossWalkButton, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(crossWalkButton), buttonPressed, FALLING);
}
void loop() {
if (!client.connected()) mqttReconnect();
client.loop();
// Emergency mode
if (iotControl == 1) {
emergencyMode();
return;
}
// Normal Mode
lcd.setCursor(0, 1);
lcd.print("= Do Not Walk! =");
Serial.println("== Do Not Walk ==");
digitalWrite(blueEmergencyLED, LOW);
if (crossWalkButtonState == 0) {
walkSignal();
crossWalkButtonState = 1;
} else {
trafficCycle();
}
}
void walkSignal() {
lcd.setCursor(0, 1);
lcd.print(" == Walk! == ");
int secondsLeft = 15;
while (secondsLeft > 0) {
displayCountdown(secondsLeft);
flashRedBoth();
secondsLeft--;
client.loop();
if (iotControl == 1) break;
}
}
void displayCountdown(int seconds) {
Serial.print("== Walk == ");
Serial.println(seconds);
lcd.setCursor(14, 1);
if (seconds >= 10) {
lcd.print(seconds);
} else {
lcd.print(" "); // clear left digit
lcd.setCursor(15, 1);
lcd.print(seconds);
}
}
void flashRedBoth() {
digitalWrite(redNS, HIGH);
digitalWrite(redEW, HIGH);
delay(500);
digitalWrite(redNS, LOW);
digitalWrite(redEW, LOW);
delay(500);
}
void trafficCycle() {
// NS Red, EW Green
setLights(HIGH, LOW, LOW, LOW, LOW, HIGH);
delay(2000);
if (iotControl == 1) return;
// EW Yellow
setLights(HIGH, LOW, LOW, LOW, HIGH, LOW);
delay(2000);
if (iotControl == 1) return;
// EW Red, NS Green
setLights(LOW, LOW, HIGH, HIGH, LOW, LOW);
delay(2000);
if (iotControl == 1) return;
// NS Yellow
setLights(LOW, HIGH, LOW, HIGH, LOW, LOW);
delay(2000);
}
void emergencyMode() {
lcd.setCursor(0, 1);
lcd.print("= Emergency! =");
Serial.println("= Emergency =");
setLights(HIGH, LOW, LOW, HIGH, LOW, LOW);
for (int i = 0; i < 5; i++) {
digitalWrite(blueEmergencyLED, HIGH);
digitalWrite(buzzerPin, HIGH);
delay(500);
digitalWrite(blueEmergencyLED, LOW);
digitalWrite(buzzerPin, LOW);
delay(500);
client.loop();
}
client.loop();
}
void setLights(int rNS, int yNS, int gNS, int rEW, int yEW, int gEW) {
digitalWrite(redNS, rNS);
digitalWrite(yellowNS, yNS);
digitalWrite(greenNS, gNS);
digitalWrite(redEW, rEW);
digitalWrite(yellowEW, yEW);
digitalWrite(greenEW, gEW);
}
void buttonPressed() {
static unsigned long lastInterrupt = 0;
unsigned long now = millis();
if (now - lastInterrupt > 200) {
crossWalkButtonState = 0;
}
lastInterrupt = now;
}
void mqttReconnect() {
while (!client.connected()) {
Serial.print("Connecting to MQTT...");
long r = random(1000);
sprintf(clientId, "clientId-%ld", r);
if (client.connect(clientId)) {
Serial.println(" connected");
client.subscribe("LED");
} else {
Serial.print("failed, rc=");
Serial.println(client.state());
delay(5000);
}
}
}
void callback(char* topic, byte* message, unsigned int length) {
String stMessage;
for (int i = 0; i < length; i++) {
stMessage += (char)message[i];
}
if (String(topic) == "LED") {
if (stMessage == "ON") {
iotControl = 1;
} else if (stMessage == "OFF") {
iotControl = 0;
}
}
}