brmdoor_libnfc/brmdoor_nfc_daemon.py

130 lines
3.6 KiB
Python
Executable file

#!/usr/bin/env python
import sys
import logging
import time
import ConfigParser
from binascii import hexlify
from brmdoor_nfc import NFCDevice, NFCError
from brmdoor_authenticator import UidAuthenticator
class BrmdoorConfigError(ConfigParser.Error):
"""
Signifies that config has missing or bad values.
"""
pass
class BrmdoorConfig(object):
"""
Configuration parser. Holds config variables from config file.
"""
_defaults = {
"lock_opened_secs": "5",
"unknown_uid_timeout_secs": "5",
"log_level": "info"
}
def __init__(self, filename):
"""
Parse and read config from given filename.
@throws ConfigParser.Error if parsing failed
@throws BrmdoorConfigError if some value was missing or invalid
"""
self.config = ConfigParser.SafeConfigParser(defaults=BrmdoorConfig._defaults)
self.config.read(filename)
self.authDbFilename = self.config.get("brmdoor", "auth_db_filename")
self.lockOpenedSecs = self.config.getint("brmdoor", "lock_opened_secs")
self.unknownUidTimeoutSecs = self.config.getint("brmdoor", "unknown_uid_timeout_secs")
self.logFile = self.config.get("brmdoor", "log_file")
self.logLevel = self.convertLoglevel(self.config.get("brmdoor", "log_level"))
def convertLoglevel(self, levelString):
"""Converts string 'debug', 'info', etc. into corresponding
logging.XXX value which is returned.
@raises ValueError if the level is undefined
"""
try:
return getattr(logging, levelString.upper())
except AttributeError:
raise BrmdoorConfigError("No such loglevel - %s" % levelString)
class NFCScanner(object):
"""Thread reading data from NFC reader"""
def __init__(self, config):
"""Create worker reading UIDs from PN53x reader.
"""
self.authenticator = UidAuthenticator(config.authDbFilename)
self.unknownUidTimeoutSecs = config.unknownUidTimeoutSecs
self.lockOpenedSecs = config.lockOpenedSecs
def run(self):
"""
Waits for a card to get into reader field. Reads its UID and
compares to database of authorized users. Unlocks lock if
authorized.
"""
self.nfc = NFCDevice()
#self.nfc.pollNr = 0xFF #poll indefinitely
while True:
try:
uid_hex = hexlify(self.nfc.scanUID())
logging.debug("Got UID %s", uid_hex)
if len(uid_hex) > 0:
self.actOnUid(uid_hex)
else:
#prevent busy loop if reader goes awry
time.sleep(0.3)
except NFCError, e:
#this exception happens also when scanUID times out
logging.debug("Failed to wait for RFID card: %s", e)
except KeyboardInterrupt:
logging.info("Exiting on keyboard interrupt")
self.nfc.close()
self.nfc.unload()
sys.exit(2)
except Exception:
logging.exception("Exception in main unlock thread")
def actOnUid(self, uid_hex):
"""
Do something with the UID scanned. Try to authenticate it against
database and open lock if authorized.
"""
record = self.authenticator.fetchUidRecord(uid_hex)
#no match
if record is None:
logging.info("Unknown UID %s", uid_hex)
time.sleep(self.unknownUidTimeoutSecs)
return
logging.info("Unlocking for UID %s", record)
time.sleep(self.lockOpenedSecs)
if __name__ == "__main__":
if len(sys.argv) < 2:
print >> sys.stderr, "Syntax: brmdoor_nfc_daemon.py brmdoor_nfc.config"
sys.exit(1)
config = BrmdoorConfig(sys.argv[1])
if config.logFile == "-":
logging.basicConfig(stream=sys.stderr, level=config.logLevel,
format="%(asctime)s %(levelname)s %(message)s [%(pathname)s:%(lineno)d]")
else:
logging.basicConfig(filename=config.logFile, level=config.logLevel,
format="%(asctime)s %(levelname)s %(message)s [%(pathname)s:%(lineno)d]")
nfcUnlocker = NFCUnlocker(config)
nfcUnlocker.run()