/*This is an improvement on the previous code for MultiTraffic Light
Changes Made:
Removed Redundant Comments: Most comments were either too verbose or unnecessary, so I removed them to make the code more readable.
Grouped Similar Operations: Grouped related operations together to avoid repeated function calls.
Extracted Repeated Code into Functions: Created separate functions for repetitive tasks such as handling traffic light cycles, walking signal, and emergency operations.
Simplified Conditional Checks: Streamlined the conditional logic within the loop function and callback.
Improved Readability: Used meaningful function names and variable names, ensuring that the code is self-explanatory without needing extensive comments.
*/

#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";
const int port = 1883;

WiFiClient espClient;
PubSubClient client(espClient);
LiquidCrystal_I2C lcd(0x27, 16, 2);

const int redLightNS = 14;
const int yellowLightNS = 12;
const int greenLightNS = 13;
const int redLightEW = 25;
const int yellowLightEW = 26;
const int greenLightEW = 27;
const int crossWalkButton = 19;
const int emergencyBlueLED = 16;
const int buzzerPin = 32;

int crossWalkButtonState = 1;
int iotControl = 0;
int secondsLeft;
char clientId[50];

void setup() {
  Serial.begin(115200);
  randomSeed(analogRead(0));
  delay(10);

  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nWiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.println(WiFi.macAddress());

  client.setServer(mqttServer, port);
  client.setCallback(callback);

  pinMode(crossWalkButton, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(crossWalkButton), buttonPressed, FALLING);

  pinMode(redLightNS, OUTPUT);
  pinMode(yellowLightNS, OUTPUT);
  pinMode(greenLightNS, OUTPUT);
  pinMode(redLightEW, OUTPUT);
  pinMode(yellowLightEW, OUTPUT);
  pinMode(greenLightEW, OUTPUT);
  pinMode(emergencyBlueLED, OUTPUT);
  pinMode(buzzerPin, OUTPUT);

  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("=== CEIS-114 ===");
}

void wifiConnect() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
}

void mqttReconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    long r = random(1000);
    sprintf(clientId, "clientId-%ld", r);
    if (client.connect(clientId)) {
      Serial.print(clientId);
      Serial.println(" connected");
      client.subscribe("LED");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      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;
    }
  }
}

void loop() {
  if (!client.connected()) {
    mqttReconnect();
  }

  if (iotControl == 0) {
    normalOperation();
  } else {
    emergencyOperation();
  }
  client.loop();
}

void normalOperation() {
  lcd.setCursor(0, 1);
  lcd.print("= Do Not Walk! =");
  Serial.println(" == Do Not Walk == ");
  digitalWrite(emergencyBlueLED, LOW);

  if (crossWalkButtonState == 0) {
    startWalk();
  } else {
    trafficLightCycle();
  }
}

void startWalk() {
  turnOffAllLights();
  lcd.setCursor(0, 1);
  lcd.print(" == Walk! == ");
  secondsLeft = 15;

  while (secondsLeft > 0) {
    if (secondsLeft >= 10) {
      lcd.setCursor(14, 1);
      lcd.print(secondsLeft);
    } else {
      lcd.setCursor(14, 1);
      lcd.print(" ");
      lcd.setCursor(15, 1);
      lcd.print(secondsLeft);
    }

    blinkRedLights();
    secondsLeft--;
    client.loop();

    if (iotControl == 1) break;
  }
  crossWalkButtonState = 1;
}

void trafficLightCycle() {
  lightSequence(redLightNS, yellowLightNS, greenLightNS, redLightEW, yellowLightEW, greenLightEW);
  delay(1000);
  lightSequence(redLightEW, yellowLightEW, greenLightEW, redLightNS, yellowLightNS, greenLightNS);
  delay(2000);
}

void lightSequence(int red1, int yellow1, int green1, int red2, int yellow2, int green2) {
  digitalWrite(red1, HIGH);
  digitalWrite(yellow1, LOW);
  digitalWrite(green1, LOW);
  digitalWrite(red2, HIGH);
  digitalWrite(yellow2, LOW);
  digitalWrite(green2, LOW);
}

void blinkRedLights() {
  digitalWrite(redLightNS, HIGH);
  digitalWrite(redLightEW, HIGH);
  delay(500);
  digitalWrite(redLightNS, LOW);
  digitalWrite(redLightEW, LOW);
  delay(500);
}

void turnOffAllLights() {
  digitalWrite(yellowLightNS, LOW);
  digitalWrite(greenLightNS, LOW);
  digitalWrite(yellowLightEW, LOW);
  digitalWrite(greenLightEW, LOW);
}

void emergencyOperation() {
  lcd.setCursor(0, 1);
  lcd.println("= Emergency! =");
  Serial.println("= Emergency! =");

  turnOffAllLights();
  digitalWrite(redLightNS, HIGH);
  digitalWrite(redLightEW, HIGH);
  digitalWrite(emergencyBlueLED, HIGH);
  digitalWrite(buzzerPin, HIGH);
  delay(500);
  digitalWrite(emergencyBlueLED, LOW);
  digitalWrite(buzzerPin, LOW);
  delay(500);
}

void buttonPressed() {
  static unsigned long lastInterruptTime = 0;
  unsigned long interruptTime = millis();
  if (interruptTime - lastInterruptTime > 20) {
    crossWalkButtonState = 0;
  }
  lastInterruptTime = interruptTime;
}
$abcdeabcde151015202530354045505560fghijfghij
$abcdeabcde151015202530fghijfghij
Loading
esp32-devkit-c-v4
led1:A
led1:C
led2:A
led2:C
led3:A
led3:C
led4:A
led4:C
led5:A
led5:C
led6:A
led6:C
led7:A
led7:C
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
bz1:1
bz1:2
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL