· 8 years ago · Dec 17, 2017, 06:06 PM
1'''
2 * NFC Door Lock - Raspberry Pi Code
3 * Author: Stefen Sharkey
4 * Date: December 6, 2017
5 * School: Monroe Community College
6 * Course: Computer Science 202 - Embedded Programming in C and Assembly
7 * Professor: George Fazekas
8'''
9
10from enum import IntEnum
11import serial
12import sqlite3
13import struct
14import time
15import traceback
16
17ser_ard = serial.Serial('/dev/ttyACM0', 115200)
18ser_tb = serial.Serial('/dev/ttyUSB0', 9600)
19db_conn = sqlite3.connect(r'/home/pi/Documents/doorlock.db')
20c = db_conn.cursor()
21
22def __main__():
23 programming = False
24 deleting = False
25
26 try:
27 # Create the CardID table if it doesn't already exist.
28 c.executescript('''CREATE TABLE IF NOT EXISTS CardIDs (
29 'CardID' INT PRIMARY KEY NOT NULL,
30 'Rank' INT NOT NULL,
31 'Name' TEXT,
32 'LastUsed' DATETIME
33 );
34 CREATE TABLE IF NOT EXISTS UsageLog (
35 'Time' DATETIME PRIMARY KEY NOT NULL,
36 'CardID' INT NOT NULL,
37 'Rank' INT NOT NULL
38 );''')
39
40 # Add default cards to database if they don't exist.
41 addDefaultCards()
42
43 #ser_ard.write(b'0')
44
45 while True:
46 print("Ready to receive input.")
47
48 # Stores the raw incoming serial mesage from the Arduino.
49 raw_rx_ard = ser_ard.readline().decode('utf-8')
50 #raw_rx_ard = '721416196'
51
52 print('Received input:', raw_rx_ard)
53
54 # Ensures the serial message is usable.
55 if len(raw_rx_ard) > 2:
56 # Strips the incoming serial message of carriage return and newline characters
57 rx_ard = raw_rx_ard[:-2]
58
59 print('Received usable input:', rx_ard)
60
61 # Check if serial message was a card ID.
62 #if len(rx_ard) >= 9:
63 if len(rx_ard) >= 9:
64 # Store the received card ID.
65 #card_id = int(rx_ard)
66 card_id = int(rx_ard)
67
68 print('Input was a card:', card_id)
69
70 # Holds the card rank, defaulting to unknown.
71 card_rank = 0
72
73 # Obtains the card's rank from the database.
74 c.execute('SELECT Rank FROM CardIDs WHERE CardID IS {};'.format(card_id))
75
76 # Holds the first entry that the previous SQLite command returned.
77 db_query = c.fetchone()
78
79 # Checks if the card exists in the database.
80 if db_query is not None:
81 # Sets the card rank to what the database holds.
82 card_rank = db_query[0]
83
84 # Sets the card's last used time in the database.
85 c.execute('UPDATE CardIDs SET LastUsed = datetime(\'now\') WHERE CardID IS {};'.format(card_id))
86
87 print('Card rank is', card_rank)
88
89 # If the system is not programmor, nor deleting, send the Arduino and Thunderbird the card rank.
90 if not programming and not deleting:
91 print('Sending Arduino card rank.')
92
93 # Send the card rank to Arduino and Thunderbird.
94 card_rank_bytes = str(card_rank).encode()
95 ser_ard.write(card_rank_bytes)
96 ser_tb.write(card_rank_bytes)
97
98 if programming:
99 # If the system is programming and an unknown card is read, add it to the system and signal the Arduino and Thunderbird.
100 if card_rank == Rank.unknown.value:
101 print('programming new card: {}'.format(card_id))
102 c.execute('INSERT INTO CardIDs VALUES ({}, 1, NULL, NULL);'.format(card_id))
103 ser_ard.write(b'1')
104 else:
105 ser_ard.write(b'0')
106
107 ser_tb.write(b'4')
108 programming = False
109 elif deleting:
110 # If the system is deleting and a normal user card is read, remove it from the system and signal the Arduino and Thunderbird.
111 if card_rank == Rank.user.value:
112 print('Deleting card: {}'.format(card_id))
113 c.execute('DELETE FROM CardIDs WHERE CardID IS {};'.format(card_id))
114 ser_ard.write(b'1')
115 else:
116 ser_ard.write(b'0')
117
118 ser_tb.write(b'5')
119 deleting = False
120 elif card_rank == Rank.wipe.value:
121 print('Wiping card database...')
122 c.executescript('DELETE FROM CardIDs; VACUUM;')
123 elif card_rank == Rank.master.value:
124 print('Master card detected. Reprogramming database.')
125 addDefaultCards()
126
127 # Toggle deleting or programming modes.
128 if not deleting and card_rank == Rank.programming.value:
129 programming = not programming
130 elif not programming and card_rank == Rank.delete.value:
131 deleting = not deleting
132
133 # Adds the usage to usage log table.
134 c.execute('INSERT INTO "UsageLog" VALUES (datetime(\'now\'), {}, {})'.format(card_id, card_rank))
135
136 # Send the Arduino the card's name.
137 if card_rank == Rank.user.value or card_rank == Rank.administrator.value:
138 # Obtains the card's name from the database.
139 c.execute('SELECT Name FROM CardIDs WHERE CardID IS {};'.format(card_id))
140
141 db_query = c.fetchone()
142
143 # Set the card name to the card ID in case no name exists in the database.
144 card_name = card_id
145
146 # If a name exists in the database, set the card name to it.
147 if db_query is not None and db_query[0] is not None:
148 card_name = db_query[0]
149
150 print('Card name:', card_name)
151
152 time.sleep(0.05)
153
154 # Send the card name to the Arduino.
155 ser_ard.write(str(card_name).encode())
156 time.sleep(5)
157
158 ser_ard.write(b'c')
159 ser_tb.write(b'c')
160 except Exception as e:
161 # Print the exception.
162 #print("Exception: {}".format(e))
163 traceback.print_exc()
164
165 # Close the serial line.
166 ser_ard.close()
167 ser_tb.close()
168
169# Checks if each query exists in the table.
170# TODO: Figure out if SQLite supports the following with a single execution statement per query.
171def addDefaultCards():
172 # Check for Stefen's card.
173 c.execute('SELECT Rank FROM CardIDs WHERE CardID IS 721416196;')
174
175 if c.fetchone() is None:
176 c.execute("INSERT INTO CardIDs VALUES (721416196, 2, 'Stefen Sharkey', NULL);")
177
178 # Check for Master Wiper's card.
179 c.execute('SELECT Rank FROM CardIDs WHERE CardID IS 704852996;')
180
181 if c.fetchone() is None:
182 c.execute("INSERT INTO CardIDs VALUES (704852996, 3, 'Master Wiper', NULL);")
183
184 # Check for Master Programming's card.
185 c.execute('SELECT Rank FROM CardIDs WHERE CardID IS 711223556;')
186
187 if c.fetchone() is None:
188 c.execute("INSERT INTO CardIDs VALUES (711223556, 4, 'Master Programming', NULL);")
189
190 # Check for Master Deletion's card.
191 c.execute('SELECT Rank FROM CardIDs WHERE CardID IS 709711364;')
192
193 if c.fetchone() is None:
194 c.execute("INSERT INTO CardIDs VALUES (709711364, 5, 'Master Deletion', NULL);")
195
196 # Check for Master Card's card.
197 c.execute('SELECT Rank FROM CardIDs WHERE CardID IS 707829764;')
198
199 if c.fetchone() is None:
200 c.execute("INSERT INTO CardIDs VALUES (707829764, 6, 'Master Card', NULL);")
201
202class Rank(IntEnum):
203 unknown = 0
204 user = 1
205 administrator = 2
206 wipe = 3
207 programming = 4
208 delete = 5
209 master = 6
210
211__main__()