Skip to content

Commit

Permalink
Merge pull request #1012 from ProchaskaMarkus/multi_rfid
Browse files Browse the repository at this point in the history
Added option for multiple RFID Readers
  • Loading branch information
MiczFlor authored Jul 16, 2020
2 parents c9a7f7d + dc2a864 commit 5b64981
Show file tree
Hide file tree
Showing 4 changed files with 393 additions and 1 deletion.
73 changes: 73 additions & 0 deletions scripts/Reader.py.Multi
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env python3
# There are a variety of RFID readers out there, USB and non-USB variants.
# This might create problems in recognizing the reader you are using.
# We haven't found the silver bullet yet. If you can contribute to this
# quest, please comment in the issue thread or create pull requests.
# ALTERNATIVE SCRIPTS:
# If you encounter problems with this script Reader.py
# consider and test one of the alternatives in the same scripts folder.
# Replace the Reader.py file with one of the following files:
# * Reader.py.experimental
# This alternative Reader.py script was meant to cover not only USB readers but more.
# It can be used to replace Reader.py if you have readers such as
# MFRC522, RDM6300 or PN532.
# * Reader.py.kkmoonRFIDreader
# KKMOON RFID Reader which appears twice in the devices list as HID 413d:2107
# and this required to check "if" the device is a keyboard.

# import string
# import csv
import os.path
import sys

from evdev import InputDevice, ecodes, list_devices
from select import select


def get_devices():
return [InputDevice(fn) for fn in list_devices()]


class Reader:
reader = None

def __init__(self):
self.reader = self
devs = list()
path = os.path.dirname(os.path.realpath(__file__))
self.keys = "X^1234567890XXXXqwertzuiopXXXXasdfghjklXXXXXyxcvbnmXXXXXXXXXXXXXXXXXXXXXXX"
if not os.path.isfile(path + '/deviceName.txt'):
sys.exit('Please run RegisterDevice.py first')
else:
with open(path + '/deviceName.txt', 'r') as f:
device_keys = f.readlines()
devices = get_devices()
for device in devices:
for dev_key in device_keys:
dev_name, dev_phys = dev_key.rstrip().split(';', 1)
if device.name == dev_name and device.phys == dev_phys:
devs.append(device)
break
for dev in devs:
try:
dev
except:
sys.exit('Could not find the device %s\n. Make sure is connected' % dev.name)

str_devs = ','.join([str(x) for x in devs])
#print("Devs: " + str_devs)
self.devices = map(InputDevice, str_devs)
self.devices = {dev.fd: dev for dev in devs}

def readCard(self):
stri = ''
key = ''
while key != 'KEY_ENTER':
r, w, x = select(self.devices, [], [])
for fd in r:
for event in self.devices[fd].read():
if event.type == 1 and event.value == 1:
stri += self.keys[event.code]
# print( keys[ event.code ] )
key = ecodes.KEY[event.code]
return stri[:-1]
211 changes: 211 additions & 0 deletions scripts/Reader.py.experimental.Multi
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
#!/usr/bin/env python3
# This alternative Reader.py script was meant to cover not only USB readers but more.
# It can be used to replace Reader.py if you have readers such as
# MFRC522, RDM6300 or PN532.
# Please use the github issue threads to share bugs and improvements
# or create pull requests.
import multiprocessing
try:
from multiprocessing import SimpleQueue
except ImportError:
from multiprocessing.queues import SimpleQueue
import os.path
import sys
import serial
import string
import RPi.GPIO as GPIO
import logging
from enum import Enum
from evdev import InputDevice, ecodes, list_devices
# Workaround: when using RC522 reader with pirc522 pkg the py532lib pkg may not be installed and vice-versa
try:
import pirc522
from py532lib.i2c import *
from py532lib.mifare import *
except ImportError:
pass

logger = logging.getLogger(__name__)

class EDevices(Enum):
MFRC522 = 0
RDM6300 = 1
PN532 = 2


def get_devices():
devices = [InputDevice(fn) for fn in list_devices()]
devices.append(NonUsbDevice(EDevices.MFRC522.name))
devices.append(NonUsbDevice(EDevices.RDM6300.name))
devices.append(NonUsbDevice(EDevices.PN532.name))
return devices


class NonUsbDevice(object):
name = None

def __init__(self, name, phys=''):
self.name = name
self.phys = phys


class UsbReader(object):
def __init__(self, device):
self.keys = "X^1234567890XXXXqwertzuiopXXXXasdfghjklXXXXXyxcvbnmXXXXXXXXXXXXXXXXXXXXXXX"
self.dev = device

def readCard(self):
from select import select
stri = ''
key = ''
while key != 'KEY_ENTER':
select([self.dev], [], [])
for event in self.dev.read():
if event.type == 1 and event.value == 1:
stri += self.keys[event.code]
key = ecodes.KEY[event.code]
return stri[:-1]


class Mfrc522Reader(object):
def __init__(self):
self.device = pirc522.RFID()

def readCard(self):
# Scan for cards
self.device.wait_for_tag()
(error, tag_type) = self.device.request()

if not error:
logger.info("Card detected.")
# Perform anti-collision detection to find card uid
(error, uid) = self.device.anticoll()
if not error:
card_id = ''.join((str(x) for x in uid))
logger.info(card_id)
return card_id
logger.debug("No Device ID found.")
return None

@staticmethod
def cleanup():
GPIO.cleanup()


class Rdm6300Reader:
def __init__(self):
device = '/dev/ttyS0'
baudrate = 9600
ser_timeout = 0.1
self.last_card_id = ''
try:
self.rfid_serial = serial.Serial(device, baudrate, timeout=ser_timeout)
except serial.SerialException as e:
logger.error(e)
exit(1)

def readCard(self):
byte_card_id = b''

try:
while True:
try:
read_byte = self.rfid_serial.read()

if read_byte == b'\x02': # start byte
while read_byte != b'\x03': # end bye
read_byte = self.rfid_serial.read()
byte_card_id += read_byte

card_id = byte_card_id.decode('utf-8')
byte_card_id = ''
card_id = ''.join(x for x in card_id if x in string.printable)

# Only return UUIDs with correct length
if len(card_id) == 12 and card_id != self.last_card_id:
self.last_card_id = card_id
self.rfid_serial.reset_input_buffer()
return self.last_card_id

else: # wrong UUID length or already send that UUID last time
self.rfid_serial.reset_input_buffer()

except ValueError as ve:
logger.errror(ve)

except serial.SerialException as se:
logger.error(se)

def cleanup(self):
self.rfid_serial.close()


class Pn532Reader:
def __init__(self):
pn532 = Pn532_i2c()
self.device = Mifare()
self.device.SAMconfigure()
self.device.set_max_retries(MIFARE_WAIT_FOR_ENTRY)

def readCard(self):
return str(+int('0x' + self.device.scan_field().hex(), 0))

def cleanup(self):
# Not sure if something needs to be done here.
logger.debug("PN532Reader clean up.")


class Reader(object):
def __init__(self):
self.reader = self
self.devs = list()
path = os.path.dirname(os.path.realpath(__file__))
if not os.path.isfile(path + '/deviceName.txt'):
sys.exit('Please run RegisterDevice.py first')
else:
with open(path + '/deviceName.txt', 'r') as f:
device_keys = f.readlines()
devices = get_devices()
for device in devices:
for dev_key in device_keys:
dev_name_phys = dev_key.rstrip().split(';', 1)
dev_name = dev_name_phys[0]
dev_phys = ''
if len(dev_name_phys) > 1:
dev_phys = dev_name_phys[1]
if device.name == dev_name and device.phys == dev_phys:
if dev_name == 'MFRC522':
self.devs.append(Mfrc522Reader())
elif dev_name == 'RDM6300':
self.devs.append(Rdm6300Reader())
elif dev_name == 'PN532':
self.devs.append(Pn532Reader())
else:
try:
usb_reader = UsbReader(device)
self.devs.append(usb_reader)
except IndexError:
sys.exit('Could not find the device %s.\n Make sure it is connected' % dev_name)
break

def readCard(self):
que = SimpleQueue()
threads_list = list()

for dev in self.devs:
t = multiprocessing.Process(target=lambda q: q.put(dev.readCard()), args=(que,))
t.start()
threads_list.append(t)

found_result = False
while not found_result:
for process in threads_list:
process.join(0.001)
if not process.is_alive():
found_result = True
break

for process in threads_list:
process.terminate()

return que.get()
103 changes: 103 additions & 0 deletions scripts/RegisterDevice.py.Multi
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/usr/bin/env python3

import os.path
import subprocess

JUKEBOX_HOME_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))

def runCmd(cmd, wait=True):
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
(output, err) = p.communicate()
if wait:
p.wait()
return output

def setupPN532():
answer = input('Please make sure that the PN532 reader is wired up correctly '
'to the GPIO ports before continuing...\n Continue?: [Y/n]')
if not answer or answer[0] != 'Y':
return False
print("Activating I2C interface...\n")
runCmd("sudo raspi-config nonint do_i2c 0")
print("Installing i2c-tools...\n")
runCmd("sudo apt-get -qq -y install i2c-tools")
print("Checking if PN532 RFID reader is found through I2C...\n")
output = runCmd("sudo i2cdetect -y 1")
if "24" in str(output):
print(" PN532 was found.\n")
else:
print(" ERROR: PN532 was not found.\n")
print(str(output))
return False
print("Installing Python requirements for PN532...\n")
runCmd("sudo python3 -m pip install --upgrade --force-reinstall "
"-q -r {}/components/rfid-reader/PN532/requirements.txt".format(JUKEBOX_HOME_DIR))
print("Done")
return True


def setupMFRC522():
answer = input('Please make sure that the RC522 reader is wired up correctly '
'to the GPIO ports before continuing...\n Continue?: [Y/n]')
if not answer or answer[0] != 'Y':
return False
print("Installing Python requirements for RC522...\n")
runCmd("sudo python3 -m pip install --upgrade --force-reinstall "
"-q -r {}/components/rfid-reader/RC522/requirements.txt".format(JUKEBOX_HOME_DIR))
print("Done")
return True


runCmd("cp {0}/scripts/Reader.py.experimental.Multi {1}/scripts/Reader.py".format(JUKEBOX_HOME_DIR, JUKEBOX_HOME_DIR))
from Reader import get_devices, EDevices
list_dev_ids = list()
devices = get_devices()

def addDevice():
i = 0
print("Choose the reader from list")
for dev in devices:
if i not in list_dev_ids:
print(i, dev.name + str(dev.phys))
i += 1
dev_id = int(input('Device Number: '))
if dev_id not in list_dev_ids:
if devices[dev_id].name == EDevices.PN532.name:
if not setupPN532():
return
if devices[dev_id].name == EDevices.MFRC522.name:
if not setupMFRC522():
return
list_dev_ids.append(dev_id)


def configureDevices():
addDevice()
while True:
answer = input('Do you want to add another device: [Y/n]')
if not answer or answer[0] != 'Y':
break
addDevice()


print("Stopping phoniebox-rfid-reader service...\n")
runCmd("sudo systemctl stop phoniebox-rfid-reader.service")

configureDevices()

path = os.path.dirname(os.path.realpath(__file__))
with open(path + '/deviceName.txt', 'w') as f:
for sel_dev_id in list_dev_ids:
f.write(devices[sel_dev_id].name + ";" + devices[sel_dev_id].phys + '\n')
f.close()

print("Restarting phoniebox-rfid-reader service...\n")
runCmd("sudo systemctl start phoniebox-rfid-reader.service")

runCmd("sudo chown pi:www-data {}/scripts/deviceName.txt".format(JUKEBOX_HOME_DIR))
runCmd("sudo chmod 644 {}/scripts/deviceName.txt".format(JUKEBOX_HOME_DIR))

print("Register Device(s) Done!")



Loading

0 comments on commit 5b64981

Please sign in to comment.