From 44ece0b3b05a9ddd6cc302093154e1a00bb66e56 Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Wed, 30 Aug 2023 23:07:59 +0100 Subject: [PATCH] Integrate PN532 reader, handle disconnections --- main.py | 91 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/main.py b/main.py index c11bab7..114366e 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,4 @@ -import os +import os, sys import logging logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', @@ -13,16 +13,16 @@ import json import requests import time from signal import * +import binascii if not TEST: - import serial import RPi.GPIO as GPIO + from pn532pi import Pn532, Pn532Hsu, pn532 import secrets RELAY_PIN = 17 -RFID_EN_PIN = 27 CARDS_FILE = 'card_data.json' OPEN_DURATION = 4 VALID_PACKAGES = [ @@ -36,55 +36,72 @@ VALID_PACKAGES = [ 'Day Pass Holder', 'Access to everything 24/7', 'Barter Membership', - 'Loft Member', + #'Loft Member', ] TEST_PIPE = '/tmp/airlock' -os.remove(TEST_PIPE) +try: + os.remove(TEST_PIPE) +except FileNotFoundError: + pass API_MEMBERS = 'https://fabman.io/api/v1/members?limit=1000&embed=key&embed=activePackages&includeKeyToken=true' -ser = None +nfc = None def unlock_door(): logging.info('Unlocking door...') if not TEST: GPIO.output(RELAY_PIN, GPIO.HIGH) - GPIO.output(RFID_EN_PIN, GPIO.HIGH) time.sleep(OPEN_DURATION) GPIO.output(RELAY_PIN, GPIO.LOW) - GPIO.output(RFID_EN_PIN, GPIO.LOW) + + logging.info('Done.') def lock_door_on_exit(*args): logging.info('Exiting, locking door...') if not TEST: GPIO.output(RELAY_PIN, GPIO.LOW) - GPIO.output(RFID_EN_PIN, GPIO.LOW) os._exit(0) +def feed_watchdog(): + if DEBUG or TEST: + return + + with open('/dev/watchdog', 'w') as wdt: + wdt.write('1') + def init(): - global ser, cards + global nfc, cards if not TEST: GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) GPIO.setup(RELAY_PIN, GPIO.OUT) GPIO.output(RELAY_PIN, GPIO.LOW) - GPIO.setup(RFID_EN_PIN, GPIO.OUT) - GPIO.output(RFID_EN_PIN, GPIO.LOW) logging.info('GPIO initialized') if TEST: os.mkfifo(TEST_PIPE) logging.info('Test pipe initialized') else: - ser = serial.Serial(port='/dev/ttyAMA0', baudrate=2400, timeout=0.1) - logging.info('Serial initialized') + PN532_HSU = Pn532Hsu(Pn532Hsu.RPI_MINI_UART) + nfc = Pn532(PN532_HSU) + nfc.begin() + nfc.SAMConfig() + version = nfc.getFirmwareVersion() + logging.info('NFC reader initialized, verion: %s', version) + + if not version: + logging.error('Unable to communicate with reader, waiting 10s and exiting...') + time.sleep(10) + os._exit(0) + for sig in (SIGABRT, SIGILL, SIGINT, SIGSEGV, SIGTERM): signal(sig, lock_door_on_exit) @@ -105,17 +122,23 @@ def reader_thread(card_data_queue): if TEST: with open(TEST_PIPE, 'r') as pipe: - card = pipe.readline() + success, card = (True, pipe.readline()) else: - card = ser.readline() - - if not card: continue + success, card = nfc.readPassiveTargetID(pn532.PN532_MIFARE_ISO14443A_106KBPS) try: - card = card.decode().strip() - except AttributeError: + # ensure we have communication with the reader + if nfc.getFirmwareVersion(): + feed_watchdog() + except: + continue + + try: + card = binascii.hexlify(card).decode().strip() + except TypeError: card = card.strip() - except UnicodeDecodeError: + except: + logging.info('Unable to decode card: %s', str(card)) continue if len(card) != 14: continue @@ -125,6 +148,7 @@ def reader_thread(card_data_queue): if card in recent_scans: if now - recent_scans[card] < 5.0: logging.info('Debounce skipping card scan') + time.sleep(1) continue recent_scans[card] = now @@ -156,14 +180,10 @@ def reader_thread(card_data_queue): # continue def get_cards(card_data_queue): - try: - headers = {'Authorization': 'Bearer ' + secrets.FABMAN_API_KEY} - res = requests.get(API_MEMBERS, headers=headers, timeout=10) - res.raise_for_status() - res = res.json() - except BaseException as e: - logging.exception('Problem GETting Fabman API: {} - {}'.format(e.__class__.__name__, str(e))) - return + headers = {'Authorization': 'Bearer ' + secrets.FABMAN_API_KEY} + res = requests.get(API_MEMBERS, headers=headers, timeout=10) + res.raise_for_status() + res = res.json() members = res cards = {} @@ -211,17 +231,15 @@ def update_thread(card_data_queue): while True: logging.info('Updating cards...') - get_cards(card_data_queue) + + try: + get_cards(card_data_queue) + except BaseException as e: + logging.exception('Problem updating cards: {} - {}'.format(e.__class__.__name__, str(e))) time.sleep(300) -def watchdog_thread(): - while True: - with open('/dev/watchdog', 'w') as wdt: - wdt.write('1') - time.sleep(1) - if __name__ == '__main__': logging.info('Initializing...') init() @@ -230,4 +248,3 @@ if __name__ == '__main__': Process(target=reader_thread, args=(card_data,)).start() Process(target=update_thread, args=(card_data,)).start() - if not DEBUG: Process(target=watchdog_thread).start()