-
Notifications
You must be signed in to change notification settings - Fork 397
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1012 from ProchaskaMarkus/multi_rfid
Added option for multiple RFID Readers
- Loading branch information
Showing
4 changed files
with
393 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!") | ||
|
||
|
||
|
Oops, something went wrong.