#include <SPI.h>
#include <MFRC522.h>
#include <LiquidCrystal_I2C.h>
#include <ESP32Servo.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <EEPROM.h>
#define SS_PIN 5
#define RST_PIN 4
#define TRIG 14
#define ECHO 12
#define SERVO_PIN 13
#define LED_G 26
#define LED_R 27
#define BUZZER 25
#define THRESHOLD 20
#define EEPROM_SIZE 250
#define MAX_VEHICLES 4
#define SLOT_SIZE 41
#define UID_LEN 8
#define NUMBER_LEN 12
#define INIT_FLAG 0xAB
MFRC522 rfid(SS_PIN, RST_PIN);
LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo barrier;
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* apiURL = "https://httpbin.org/post";
int uidAddr(int i) { return 1 + i * SLOT_SIZE; }
int numberAddr(int i) { return 1 + i * SLOT_SIZE + UID_LEN; }
int balanceAddr(int i) { return 1 + i * SLOT_SIZE + UID_LEN + NUMBER_LEN; }
int tripAddr(int i) { return 1 + i * SLOT_SIZE + UID_LEN + NUMBER_LEN + 4; }
int typeAddr(int i) { return 1 + i * SLOT_SIZE + UID_LEN + NUMBER_LEN + 8; }
void eepromWriteStr(int addr, const char* s, int len) {
for (int i = 0; i < len; i++)
EEPROM.write(addr + i, i < (int)strlen(s) ? s[i] : 0);
}
String eepromReadStr(int addr, int len) {
String s = "";
for (int i = 0; i < len; i++) {
char c = EEPROM.read(addr + i);
if (c == 0) break;
s += c;
}
return s;
}
void eepromWriteFloat(int addr, float val) { EEPROM.put(addr, val); }
float eepromReadFloat(int addr) { float v; EEPROM.get(addr, v); return v; }
void eepromWriteInt(int addr, int val) { EEPROM.put(addr, val); }
int eepromReadInt(int addr) { int v; EEPROM.get(addr, v); return v; }
String getTypeName(int type) {
if (type == 0) return "Car";
if (type == 1) return "Truck";
return "Car";
}
float getToll(int type) {
if (type == 0) return 50.0;
if (type == 1) return 100.0;
return 50.0;
}
void seedEEPROM() {
if (EEPROM.read(0) == INIT_FLAG) return;
struct { const char* uid; const char* number; float balance; int type; }
defaults[] = {
{"AABBCCDD", "TS09AB1234", 200.0, 0},
{"55667788", "AP28XY5678", 300.0, 1},
{"11223344", "KA01ZZ9999", 150.0, 0},
{"01020304", "MH12CD3456", 400.0, 1}
};
for (int i = 0; i < MAX_VEHICLES; i++) {
eepromWriteStr (uidAddr(i), defaults[i].uid, UID_LEN);
eepromWriteStr (numberAddr(i), defaults[i].number, NUMBER_LEN);
eepromWriteFloat(balanceAddr(i), defaults[i].balance);
eepromWriteInt (tripAddr(i), 0);
EEPROM.write (typeAddr(i), defaults[i].type);
}
EEPROM.write(0, INIT_FLAG);
EEPROM.commit();
}
int findVehicle(String uid) {
for (int i = 0; i < MAX_VEHICLES; i++)
if (eepromReadStr(uidAddr(i), UID_LEN) == uid) return i;
return -1;
}
bool chargePayment(int idx, float toll) {
float bal = eepromReadFloat(balanceAddr(idx));
if (bal >= toll) {
bal -= toll;
eepromWriteFloat(balanceAddr(idx), bal);
int trips = eepromReadInt(tripAddr(idx)) + 1;
eepromWriteInt(tripAddr(idx), trips);
EEPROM.commit();
return true;
}
return false;
}
void connectWiFi() {
lcd.clear();
lcd.print("Connecting WiFi");
WiFi.begin(ssid, password);
int tries = 0;
while (WiFi.status() != WL_CONNECTED && tries < 20) {
delay(300);
Serial.print(".");
tries++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi Connected!");
lcd.clear();
lcd.print("WiFi Connected");
delay(800);
} else {
Serial.println("\nWiFi Failed");
lcd.clear();
lcd.print("WiFi Failed");
lcd.setCursor(0, 1);
lcd.print("Offline Mode");
delay(1000);
}
}
void sendTransaction(String uid, String number, String type, float amount, float remainingBal, bool success, int trips) {
if (WiFi.status() != WL_CONNECTED) return;
HTTPClient http;
http.begin(apiURL);
http.addHeader("Content-Type", "application/json");
String payload = "{";
payload += "\"uid\":\"" + uid + "\",";
payload += "\"vehicle\":\"" + number + "\",";
payload += "\"type\":\"" + type + "\",";
payload += "\"amount\":" + String(amount, 2) + ",";
payload += "\"balance\":" + String(remainingBal, 2) + ",";
payload += "\"status\":\"" + String(success ? "paid" : "denied") + "\",";
payload += "\"trips\":" + String(trips) + ",";
payload += "\"timestamp\":" + String(millis());
payload += "}";
Serial.println("Sending: " + payload);
int code = http.POST(payload);
Serial.println("HTTP: " + String(code));
http.end();
}
long getDistance() {
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
long dur = pulseIn(ECHO, HIGH, 30000UL);
if (dur == 0) return 999;
return dur * 0.034 / 2;
}
String getUID() {
String uid = "";
for (byte i = 0; i < rfid.uid.size; i++) {
if (rfid.uid.uidByte[i] < 0x10) uid += "0";
uid += String(rfid.uid.uidByte[i], HEX);
}
uid.toUpperCase();
return uid;
}
void openGate() {
digitalWrite(LED_G, HIGH);
barrier.write(90);
lcd.clear();
lcd.print("Gate Open");
}
void closeGate() {
barrier.write(0);
delay(800);
digitalWrite(LED_G, LOW);
lcd.clear();
lcd.print("Gate Closed");
delay(1000);
}
void deny() {
digitalWrite(LED_R, HIGH);
tone(BUZZER, 400, 800);
lcd.clear();
lcd.print("Low Balance");
lcd.setCursor(0, 1);
lcd.print("Recharge Req");
delay(1500);
digitalWrite(LED_R, LOW);
}
void setup() {
Serial.begin(115200);
EEPROM.begin(EEPROM_SIZE);
seedEEPROM();
SPI.begin();
rfid.PCD_Init();
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
pinMode(LED_G, OUTPUT);
pinMode(LED_R, OUTPUT);
pinMode(BUZZER, OUTPUT);
barrier.setPeriodHertz(50);
barrier.attach(SERVO_PIN, 500, 2400);
barrier.write(0);
lcd.init();
lcd.backlight();
lcd.print("Welcome to Toll");
delay(1000);
connectWiFi();
lcd.clear();
lcd.print("Waiting Vehicle");
}
void loop() {
if (WiFi.status() != WL_CONNECTED) connectWiFi();
long dist = getDistance();
if (dist < THRESHOLD) {
lcd.clear();
lcd.print("Vehicle Detected");
delay(300);
lcd.clear();
lcd.print("Scan FASTag");
unsigned long scanStart = millis();
bool cardFound = false;
while (millis() - scanStart < 6000) {
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) {
cardFound = true;
break;
}
delay(50);
}
if (!cardFound) {
lcd.clear();
lcd.print("No Card Found");
delay(1200);
lcd.clear();
lcd.print("Waiting Vehicle");
return;
}
String uid = getUID();
Serial.println("UID: " + uid);
tone(BUZZER, 1000, 100);
int idx = findVehicle(uid);
if (idx == -1) {
lcd.clear();
lcd.print("Unknown Tag");
lcd.setCursor(0, 1);
lcd.print("Access Denied");
digitalWrite(LED_R, HIGH);
tone(BUZZER, 400, 1000);
delay(2000);
digitalWrite(LED_R, LOW);
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
lcd.clear();
lcd.print("Waiting Vehicle");
return;
}
String number = eepromReadStr(numberAddr(idx), NUMBER_LEN);
int type = EEPROM.read(typeAddr(idx));
String typeName = getTypeName(type);
float toll = getToll(type);
float bal = eepromReadFloat(balanceAddr(idx));
lcd.clear();
lcd.print(number);
lcd.setCursor(0, 1);
lcd.print(typeName + " | Rs" + String((int)toll));
delay(1200);
lcd.clear();
lcd.print("Processing...");
delay(500);
bool paid = chargePayment(idx, toll);
float newBal = eepromReadFloat(balanceAddr(idx));
int trips = eepromReadInt(tripAddr(idx));
lcd.clear();
lcd.print("Uploading...");
sendTransaction(uid, number, typeName, toll, newBal, paid, trips);
if (paid) {
lcd.clear();
lcd.print("Paid Rs" + String((int)toll));
lcd.setCursor(0, 1);
lcd.print("Bal:" + String(newBal, 1));
delay(2000);
lcd.clear();
lcd.print("Trip No: " + String(trips));
lcd.setCursor(0, 1);
lcd.print(number);
delay(1500);
lcd.clear();
lcd.print("Thank You!");
lcd.setCursor(0, 1);
lcd.print("Visit Again");
delay(1500);
openGate();
lcd.clear();
lcd.print("Waiting Exit...");
unsigned long start = millis();
while (getDistance() < THRESHOLD) {
if (millis() - start > 5000) break;
delay(100);
}
closeGate();
lcd.clear();
lcd.print("Waiting Vehicle");
delay(800);
} else {
deny();
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
lcd.clear();
lcd.print("Waiting Vehicle");
return;
}
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
}
delay(50);
}Loading
mfrc522
mfrc522