#include <SPI.h>
#include <MFRC522.h>
#include <LiquidCrystal_I2C.h>
// تعريف أرقام المداخل (معدلة لتناسب Wokwi)
#define RFID_SDA 5
#define RFID_RST 4
#define GREEN_LED 2 // تغيير إلى رقم مناسب في Wokwi
#define RED_LED 15 // تغيير إلى رقم مناسب في Wokwi
#define BUZZER_PIN 14
#define SERVO_PIN 13
#define BUTTON_PIN 32
// البطاقة المسموح بها
const byte AUTHORIZED_CARD[] = {0x84, 0xA8, 0x3D, 0x02};
// إنشاء كائن RFID
MFRC522 rfid(RFID_SDA, RFID_RST);
// إنشاء كائن LCD
LiquidCrystal_I2C lcd(0x27, 16, 2);
// حالة الخزنة
bool safeOpen = false;
// حالة الزر
bool buttonPressed = false;
bool lastButtonState = HIGH;
// إعدادات سيرفو 360 درجة
const int SERVO_STOP = 90; // توقف
const int SERVO_OPEN = 70; // فتح
const int SERVO_CLOSE = 110; // إغلاق
const unsigned long SERVO_RUN_TIME = 500; // 0.5 ثانية
// إعدادات الصوت
const int BEEP_SHORT = 100; // أقصر للتجربة في Wokwi
const int BEEP_LONG = 300; // أقصر للتجربة في Wokwi
// متغيرات التوقيت
unsigned long servoStartTime = 0;
bool servoRunning = false;
int servoAction = 0;
// متغيرات LCD refresh
unsigned long lastLCDUpdate = 0;
String lastDisplayMessage = "";
// --- دوال البطاقة ---
bool isCardAuthorized(byte* card) {
for (byte i = 0; i < 4; i++) {
if (card[i] != AUTHORIZED_CARD[i]) return false;
}
return true;
}
String cardToString(byte* buffer) {
String result = "";
for (byte i = 0; i < 4; i++) {
if (buffer[i] < 0x10) result += "0";
result += String(buffer[i], HEX);
result.toUpperCase();
}
return result;
}
// --- دوال سيرفو 360 درجة (محسنة لـ Wokwi) ---
void setupServo() {
pinMode(SERVO_PIN, OUTPUT);
stopServo();
}
void setServoPosition(int pos) {
// في Wokwi، نستخدم PWM بسيط للموتور
pos = constrain(pos, 0, 180);
int pulseWidth = map(pos, 0, 180, 500, 2500);
// محاكاة PWM
digitalWrite(SERVO_PIN, HIGH);
delayMicroseconds(pulseWidth);
digitalWrite(SERVO_PIN, LOW);
delay(20 - pulseWidth/1000);
}
void stopServo() {
// إيقاف السيرفو
digitalWrite(SERVO_PIN, LOW);
servoRunning = false;
}
void startOpenServo() {
servoStartTime = millis();
servoRunning = true;
servoAction = 1;
displayOpening();
Serial.println("Opening safe...");
// تشغيل السيرفو للفتح
digitalWrite(SERVO_PIN, HIGH);
delay(SERVO_RUN_TIME);
digitalWrite(SERVO_PIN, LOW);
// اكتمل الفتح مباشرة
stopServo();
safeOpen = true;
greenLEDOn();
displaySafeOpen();
servoRunning = false;
servoAction = 0;
}
void startCloseServo() {
servoStartTime = millis();
servoRunning = true;
servoAction = 2;
displayClosing();
Serial.println("Closing safe...");
// تشغيل السيرفو للإغلاق
digitalWrite(SERVO_PIN, HIGH);
delay(SERVO_RUN_TIME);
digitalWrite(SERVO_PIN, LOW);
// اكتمل الإغلاق مباشرة
stopServo();
safeOpen = false;
redLEDOn();
displaySafeClosed();
servoRunning = false;
servoAction = 0;
}
void updateServo() {
// تم التعديل لجعل السيرفو يعمل مباشرة
}
// --- دوال الزر (محسنة لـ Wokwi) ---
void checkButton() {
bool buttonState = digitalRead(BUTTON_PIN);
if (buttonState == LOW && lastButtonState == HIGH) {
delay(50); // منع الارتداد
if (digitalRead(BUTTON_PIN) == LOW) {
buttonPressed = true;
Serial.println("Button pressed");
}
}
lastButtonState = buttonState;
}
void handleButton() {
if (buttonPressed) {
if (safeOpen && !servoRunning) {
// إغلاق الخزنة يدوياً
Serial.println("Closing safe manually");
startCloseServo();
playShortBeep();
} else if (!safeOpen && !servoRunning) {
// الخزنة مقفلة بالفعل
Serial.println("Safe already closed");
playLongBeep();
displayAlreadyClosed();
delay(1000);
displaySafeClosed();
} else if (servoRunning) {
// السيرفو مشغول حالياً
Serial.println("System busy");
playLongBeep();
displayBusy();
delay(1000);
if (safeOpen) {
displaySafeOpen();
} else {
displaySafeClosed();
}
}
buttonPressed = false;
}
}
// --- دوال الصوت (محسنة لـ Wokwi) ---
void playShortBeep() {
tone(BUZZER_PIN, 1000, BEEP_SHORT);
delay(BEEP_SHORT);
}
void playLongBeep() {
tone(BUZZER_PIN, 500, BEEP_LONG);
delay(BEEP_LONG);
}
// --- دوال الـ LED ---
void greenLEDOn() {
digitalWrite(GREEN_LED, HIGH);
digitalWrite(RED_LED, LOW);
Serial.println("Green LED ON");
}
void redLEDOn() {
digitalWrite(GREEN_LED, LOW);
digitalWrite(RED_LED, HIGH);
Serial.println("Red LED ON");
}
void testLEDs() {
digitalWrite(GREEN_LED, HIGH);
delay(200);
digitalWrite(GREEN_LED, LOW);
digitalWrite(RED_LED, HIGH);
delay(200);
digitalWrite(RED_LED, LOW);
}
// --- دوال الشاشة (محسنة لـ Wokwi) ---
void displayStartup() {
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" TANK POWER ");
lcd.setCursor(0, 1);
lcd.print(" RFID SYSTEM ");
delay(1500);
}
void displaySafeClosed() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" SAFE LOCKED ");
lcd.setCursor(0, 1);
lcd.print(" SCAN CARD --> ");
Serial.println("Display: Safe Locked");
}
void displayCardDetected(String cardID) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("CARD DETECTED ");
lcd.setCursor(0, 1);
lcd.print(cardID.substring(0, 12));
Serial.print("Display: Card Detected - ");
Serial.println(cardID);
}
void displayProcessing() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" PROCESSING ");
lcd.setCursor(0, 1);
lcd.print(" PLEASE WAIT ");
Serial.println("Display: Processing");
}
void displayOpening() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" OPENING SAFE ");
lcd.setCursor(0, 1);
lcd.print(" 0.5 SECONDS ");
Serial.println("Display: Opening Safe");
}
void displayClosing() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" CLOSING SAFE ");
lcd.setCursor(0, 1);
lcd.print(" 0.5 SECONDS ");
Serial.println("Display: Closing Safe");
}
void displaySafeOpen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" SAFE OPENED ");
lcd.setCursor(0, 1);
lcd.print(" PRESS TO CLOSE ");
Serial.println("Display: Safe Opened");
}
void displayAccessDenied() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" ACCESS DENIED ");
lcd.setCursor(0, 1);
lcd.print(" INVALID CARD ");
Serial.println("Display: Access Denied");
}
void displayAlreadyClosed() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" SAFE ALREADY ");
lcd.setCursor(0, 1);
lcd.print(" LOCKED ");
Serial.println("Display: Already Closed");
}
void displayBusy() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" SYSTEM BUSY ");
lcd.setCursor(0, 1);
lcd.print(" PLEASE WAIT ");
Serial.println("Display: System Busy");
}
void displayAlreadyOpen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" SAFE ALREADY ");
lcd.setCursor(0, 1);
lcd.print(" OPEN ");
Serial.println("Display: Already Open");
}
// --- الإعداد الأولي ---
void setup() {
Serial.begin(115200);
Serial.println("\n=== TANK POWER RFID SYSTEM ===");
// تهيئة الـ LED
pinMode(GREEN_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
// تهيئة الصفارة
pinMode(BUZZER_PIN, OUTPUT);
// تهيئة الزر
pinMode(BUTTON_PIN, INPUT_PULLUP);
// اختبار سريع
testLEDs();
// تهيئة الشاشة
displayStartup();
// تهيئة السيرفو
setupServo();
// تهيئة RFID
SPI.begin();
rfid.PCD_Init();
delay(50);
// تشغيل LED الأحمر
redLEDOn();
// عرض حالة الانتظار
displaySafeClosed();
Serial.println("System Ready!");
Serial.print("Authorized Card: ");
Serial.println(cardToString((byte*)AUTHORIZED_CARD));
Serial.println("Scan your RFID card to test");
Serial.println("Press button to close when safe is open");
}
// --- الحلقة الرئيسية ---
void loop() {
// تحديث حالة السيرفو
updateServo();
// التحقق من الزر
checkButton();
handleButton();
// التحقق من RFID
if (!servoRunning) {
static unsigned long lastRFIDCheck = 0;
if (millis() - lastRFIDCheck > 100) {
lastRFIDCheck = millis();
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) {
String cardID = cardToString(rfid.uid.uidByte);
Serial.println("------------------------");
Serial.print("Card Detected: ");
Serial.println(cardID);
displayCardDetected(cardID);
delay(200);
displayProcessing();
delay(200);
if (isCardAuthorized(rfid.uid.uidByte)) {
Serial.println("ACCESS GRANTED - Authorized Card");
playShortBeep();
if (!safeOpen) {
Serial.println("Opening safe...");
startOpenServo();
} else {
Serial.println("Safe already open");
playLongBeep();
displayAlreadyOpen();
delay(1000);
if (safeOpen) {
displaySafeOpen();
} else {
displaySafeClosed();
}
}
} else {
Serial.println("ACCESS DENIED - Unauthorized Card");
displayAccessDenied();
redLEDOn();
playLongBeep();
delay(1000);
if (!safeOpen) {
displaySafeClosed();
} else {
displaySafeOpen();
}
}
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
Serial.println("------------------------");
}
}
}
delay(50);
}