RFID Dooropener


List of parts:

  • Raspberry Pi
  • Arduino Nano
  • MFRC522 13.53MHz RFID Reader for Arduino
  • 5V/230V Relay for Arduino/Raspberry Pi
  • Speaker // you can also use an old PC mainboard speaker
  • Cat7 Cable
  • Waterproof box for the RFID Reader
  • Arduino (outside the house)



    Arduino schematic:




    C++ Code:

    
        #include < Wire.h>
        #include < SPI.h>
        #include < MFRC522.h>
    
        #define SS_PIN 10             // RFID-RC522 SDA
        #define RST_PIN 9             // RFID-RC522 RST
        #define SLAVE_ADDRESS 0x04    // Wire address
    
    
        //Var
        MFRC522 mfrc522(SS_PIN, RST_PIN); // create reader
        byte readCard[4];                 // Array to save card uid
        boolean dataOk = true;
        boolean newCard = false;
        int count = 0;
    
        void setup() {
            // put your setup code here, to run once:
            pinMode(5, OUTPUT); // Sound
            pinMode(13, OUTPUT);
            digitalWrite(13,LOW);
            Serial.begin(9600); // start serial for output
            SPI.begin();        // Start serial interface
            mfrc522.PCD_Init(); // Ini rfid card reader
            // initialize i2c as slave
            Wire.begin(SLAVE_ADDRESS);
    
    
            // Define callbacks for i2c communication
            Wire.onReceive(receiveData);
            Wire.onRequest(sendData);
            cleanReader();
            Serial.println("Ready!");
        }
    
        void loop() {
            delay(100);
            if ( ! mfrc522.PICC_IsNewCardPresent()) { // If a new PICC placed to RFID reader continue
                return;
            }
            if ( ! mfrc522.PICC_ReadCardSerial()) {   // Since a PICC placed get Serial and continue
                return;
            }
            for ( uint8_t i = 0; i < 4; i++) {      // Read 4 bytes from card uid
                readCard[i] = mfrc522.uid.uidByte[i]; // Saves bytes from card in array
            }
            if(checkCard()){
                newCard = true;
                sound(300,1); // Beep one time when the uid was read correctly
            }else{
                sound(100,3);
                cleanReader(); // Beep three times when reading the uid failed
            }
            mfrc522.PICC_HaltA();       // Stop reading
        }
    
        bool checkCard(){
            for(int c = 0; c < 4; c++){
                if(readCard[c]==0){
                    return false;
                }
            }
            return true;
        }
    
        void sound(int t,int f){
          for(int j=0;j < f; j++){
            for(int i=0; i < t; i++) {  // Generate a 1KHz tone for 1/2 second
                digitalWrite(5, HIGH);
                delayMicroseconds(450);
                digitalWrite(5, LOW);
                delayMicroseconds(400);
            }
            delay(100);
          }
        }
    
        void receiveData(){
          int data = Wire.read();
          if(data == 255){
            // Data ok reset reader
            cleanReader();
          }else if(data == 150){
            // Access denied
            sound(80,4);
          }else if(data == 100){
            // Data wrong, resend
            dataOk = false;
          }else if(data == 50){
            // Reader start, reset reader
            cleanReader();
          }else{
            // Error, reset reader
            Serial.print("error");
            cleanReader();
          }
        }
    
        void sendData(){
    
          if((!dataOk && !newCard) || count > 0){
            // Send card data
            Wire.write(readCard[count]);
            count++;
            if(count == 4){
              count = 0;
            }
          }else if(newCard){
            // Send byte for new Card
            Wire.write(0xff);
            dataOk=false;
            newCard=false;
    
          }else{
            // No card
            Wire.write(0x00);
          }
    
    
        }
    
        void cleanReader(){
          dataOk = true;
          newCard = false;
          count = 0;
          for(uint8_t c = 0; c < 4; c++){
            readCard[c] = 0;
          }
        }
    

    Raspberry Pi (inside the house)



    Configuration:

    Raspberry Pi system: Raspbian


    installed:
    Mysql Server for the user Database and entrylog.
    Wiring Pi to use the raspberry GPIO.
    Web Server to have an Web interface for the Mysql Database.


    extra:
    Crontab to start the pythonscript on reboot and reboot the raspberry every day.


    Rasperry schematic:



    Python Code:

       
        #!/usr/bin/env python
        # coding: utf8
    
        import smbus
        import time
        import MySQLdb
        import RPi.GPIO as GPIO
    
        # Set RelaiPins
        GPIO.setwarnings(False)
        GPIO.setmode(GPIO.BOARD)
        GPIO.setup(11, GPIO.OUT) #Relay/Debug Pin
    
        # for RPI version 1, use "bus = smbus.SMBus(0)"
        bus = smbus.SMBus(1)
        # Array to save the incomming uid 
        number = []
        # This is the address we setup in the Arduino Program
        address = 0x04
    
        # Send data to the Arduino
        def writeNumber(value):
            print("send %s" %(value))
            bus.write_byte(address, value)
            return -1
    
        # Read uid from Arduino
        def readCard():
            # Clean the array for new data
            del number[:]
            for i in range(4):
                number.append(bus.read_byte(address))
                time.sleep(0.5)
            return -1
    
        # Ask if there is a new card available
        def askForCard():
            request = bus.read_byte(address)
            if request == 255:
                return True
            else:
                return False
    
        # Check the data into the number array
        def checkData():
            if len(number)==0:
                print("array is empty")
                return False
            for i in range(len(number)):
                # Because of some transmission failues were some parts of the uid are raplced with 0x00, the code filters card uid with the value 0x00 in it.
                if(number[i]==0x00):
                    print("data corrupted")
                    return False
            print("data ok")
            return True
    
        # Check if the card uid is inside the database
        def checkCard(uid):
            # Open database
            db = MySQLdb.connect(host="127.0.0.1", db="yourDatabase", user="yourUser",passwd="yourPassword")
            cur = db.cursor()
            cur.execute("SELECT * FROM table")
            for row in cur.fetchall():
                if row[x] == uid: # x = placeholder
                    # if the uid is found in the database, the door open
                    openDoor()
                    cur.execute("SQL for Log database") # Placeholder
                    db.commit()
                    db.close()
                    return
            if uid != "0:0:0:0":
                print uid
                print "Access denied"
                # Send Arduino an signal that the card has no access
                writeNumber(150)
                cur.execute("SQL for Log database") # Placeholder
                db.commit()
                db.close()
    
        # Open Door 
        def openDoor():
            print("open door")
            GPIO.output(11, GPIO.HIGH)
            time.sleep(1)
            GPIO.output(11, GPIO.LOW)    
    
        # Reset reader
        writeNumber(50)
        while 1:
            time.sleep(1)
            if askForCard():
                print("new card")
                read = True
                count = 0
                while read:
                    print("read")
                    time.sleep(0.5)
                    readCard()
                    # Format the uid for the database
                    uid = "%s-%s-%s-%s" %(hex(number[0])[2:],hex(number[1])[2:],hex(number[2])[2:],hex(number[3])[2:])
                    print(uid)
    
                    if checkData():
                        writeNumber(255)
                        checkCard(uid)
                        read = False
                    elif count > 3:
                        # if the raspberry reads the uid three times wrong, the Arduino stop sending the uid 
                        print("error")
                        writeNumber(0)
                        read = False
                    else:
                        writeNumber(100)
                    count+=1
                print("read complete")