#!/usr/bin/env python import argparse import json import os import serial import serial.tools.list_ports import subprocess import sys def screensaver_osx(action): """Perform actions relating to the MacOS X screensaver. action='lock' Lock the screen action='unlock' Unlock the screen """ osascript = """osascript -e 'tell application "ScreenSaverEngine" to %s'""" if action == 'lock': return subprocess.call(osascript % 'activate', shell=True) elif action == 'unlock': return subprocess.call(osascript % 'quit', shell=True) return False class RFIDReader: def __init__(self, args, security_function): self.args = args self.serialPort = serial.Serial(self.args.serial_port, 2400) self.readStoredCards() self.security_function = security_function def addCard(self, card): self.known_cards[card] = self.args.learn self.storeCards() print 'Learned %s card: "%s"' % (self.args.learn, card) def checkCard(self, card=None): if not card: card=self.readCard() if card in self.known_cards: return True else: return False def learnCard(self, card=None): if not card: card=self.readCard() if card not in self.known_cards: self.addCard(card) else: print 'Already know card: "%s"' % card def learnMode(self): while True: print '*** (learn: %s) Waiting for card read...' % self.args.learn self.learnCard() def readData(self): while True: data = rfid.serialPort.readline() if len(data) == 12: return data.strip() def readCard(self): while True: first_read = self.readData() second_read = self.readData() if first_read == second_read: return first_read.strip() def readMode(self): while True: print '*** Waiting for card read...' card = rfid.readCard() if rfid.checkCard(card): print '%s card: "%s"' % (self.known_cards[card], card) self.security_function(self.known_cards[card]) else: print 'Unknown card: "%s"' % card def readStoredCards(self): if not self.args.file: self.args.file = 'rfid.access' if os.path.exists(self.args.file): self.known_cards = json.load(open(self.args.file)) else: self.known_cards = {} def storeCards(self): fd = open(self.args.file, 'w') fd.seek(0) json.dump(self.known_cards, fd) fd.close() def port_list(): ports = [] for port, desc, hwid in sorted(serial.tools.list_ports.comports()): ports.append(port) return ports if __name__ == '__main__': # Parse the options parser = argparse.ArgumentParser(description='Listen for RFID cards') parser.add_argument('-s', '--serial-port', help='Serial Port for RFID Reader') parser.add_argument('-l', '--learn', nargs='?', default=False, const='lock', choices=['lock', 'unlock'], help='Learn cards and assign them an action') parser.add_argument('-lp', '--list-ports', action='store_true', help='List the serial ports available.') parser.add_argument('-f', '--file', help='File to store active cards in.') args = parser.parse_args() # If requested, print the port list and exit if args.list_ports: print '\n'.join(port_list()) sys.exit(0) # Determine our serial port if it wasn't provided if not args.serial_port: while True: ports = port_list() i = 0 for port in ports: print "%d. %s" % (i, port) i += 1 answer = raw_input('Which serial port is your RFID reader? ') try: if 0 <= int(answer) < i: args.serial_port = ports[int(answer)] break except ValueError: continue # Main logic rfid = RFIDReader(args, screensaver_osx) if rfid.args.learn: rfid.learnMode() else: rfid.readMode()