commit 75e7e8bf9980569228cdede7c1d6715d7cd78484 Author: Simon Date: Wed Jun 24 20:28:00 2020 +0100 initial commit of working card reader diff --git a/authorized_cards.db b/authorized_cards.db new file mode 100644 index 0000000..95d7145 Binary files /dev/null and b/authorized_cards.db differ diff --git a/database.py b/database.py new file mode 100644 index 0000000..a3ebc34 --- /dev/null +++ b/database.py @@ -0,0 +1,96 @@ +import sqlite3 +from sqlite3 import Error +from datetime import datetime + +database = 'authorized_cards.db' + +sql_create_user_table = """ CREATE TABLE IF NOT EXISTS users ( + id integer PRIMARY KEY, + name text NOT NULL, + card_id integer NOT NULL, + counter integer NOT NULL, + first_seen date NOT NULL, + last_seen date NOT NULL + ); """ + + +def create_connection(db_file): + """ create a database connection to the SQLite database + specified by the db_file + :param db_file: database file + :return: Connection object or None + """ + conn = None + try: + conn = sqlite3.connect(db_file) + except Error as e: + print(e) + + return conn + + +def create_table(conn, create_table_sql): + """ create a table from the create_table_sql statement + :param conn: Connection object + :param create_table_sql: a CREATE TABLE statement + :return: + """ + try: + c = conn.cursor() + c.execute(create_table_sql) + except Error as e: + print(e) + + +def create_user(conn, user, card_id, counter, first_seen, last_seen): + """ + Create a new task + :param conn: + :return: + """ + + sql = ''' INSERT INTO users(name, card_id, counter, first_seen, last_seen) + VALUES(?,?,?,?,?) ''' + cur = conn.cursor() + cur.execute(sql, (user, card_id, counter, first_seen, last_seen)) + return cur.lastrowid + + +def select_all_users(conn): + """ + Query all rows in the tasks table + :param conn: the Connection object + :return: + """ + cur = conn.cursor() + cur.execute("SELECT * FROM users") + + rows = cur.fetchall() + + return rows + +def increment_counter(conn, id): + """ + increment the authentication counter in the database for the given id + """ + sql = ''' UPDATE users + SET counter = counter + 1 , + last_seen = ? + WHERE id = ?''' + cur = conn.cursor() + cur.execute(sql, (str(datetime.utcnow()), id,)) + conn.commit() + + +def setup_db(): + # create a database connection + conn = create_connection(database) + + # create tables + if conn is not None: + # create projects table + create_table(conn, sql_create_user_table) + else: + print("Error! cannot create the database connection.") + + return conn \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..8f2b02e --- /dev/null +++ b/main.py @@ -0,0 +1,123 @@ +# Setting up raspi for card reader +# https://pimylifeup.com/raspberry-pi-rfid-rc522/ +# +from database import * +import time + +import RPi.GPIO as GPIO +from mfrc522 import SimpleMFRC522 + +class DoorLock(): + def __init__(self): + # initialize card reader + self.reader = SimpleMFRC522() + + def increment(self, counter): + # increment counter and send it to card + counter += 1 + data_new = str(counter) + + self.reader.write(data_new) + + # check if counter was updated successfully + _, text = self.reader.read() + try: + counter_new = int(text) + except ValueError: + return False + return counter == counter_new + + def check_authorization(self, reader_id, counter): + # open database + conn = create_connection(database) + + # check if id is in the database + with conn: + users = select_all_users(conn) + + for user in users: + db_id = user[0] + name = user[1] + user_card_id = user[2] + user_counter = user[3] + if reader_id == user_card_id: + # check if use counter on the card matches counter in the database + # if counter is different -> assume the card has been cloned + if counter == user_counter: + print("user {} with card_id {} authorized".format(name, hex(reader_id))) + return True, db_id + else: + print("error: counter does not match! please investigate!") + + # if no match was found in the database: deny entry + print("You shall not pass!") + print("could not authorize card_id {}".format(reader_id)) + return False, None + + + def unlock_door(self): + # TODO send command to open door lock + print("Unlocking door!\n\n") + + def release_the_kraken(self): + # TODO notify that authentication failed + # not implemented yet + print("Release the Kraken!") + + def run_authorization(self): + try: + while True: + print("Hold card before reader..") + uid, data = self.reader.read() + + print("data = ", data) + #counter = int.from_bytes(data, byteorder='big') + try: + counter = int(data) + except ValueError: + print("error: data on the card could not be converted") + counter = None + + if counter is not None: + print("card read: \n uid = {}\ncounter = {}\n".format(hex(uid), counter)) + authorized, db_id = self.check_authorization(uid, counter) + + if authorized: + # increment use counter on the card + increment_status = self.increment(counter) + + if increment_status: + # update the counter and the time of last access in the database + # open database + conn = create_connection(database) + increment_counter(conn, db_id) + + self.unlock_door() + else: + # if we cannot increment the counter on the card (e.g. because the card was removed too quickly) + # we do not let the user in even though authentication was correct -> try again + print("increment failed!") + else: + print("authentication failed") + self.release_the_kraken() + time.sleep(1.5) + finally: + #GPIO.cleanup() + pass + + +if __name__ == "__main__": + # create database with some users + # conn = setup_db() + # with conn: + # create_user(conn, 'Simon', 4225799947, 0, str(datetime.utcnow()), str(datetime.utcnow())) + # create_user(conn, 'Valentin', 154921302, 0, str(datetime.utcnow()), str(datetime.utcnow())) + # users = select_all_users(conn) + + doors_of_durin = DoorLock() + + data = bytearray([0]*16) + #data = '0' + #write_success = doors_of_durin.reader.write(data) + doors_of_durin.run_authorization() + pass \ No newline at end of file