Skip to content

Commit 9124d51

Browse files
Critical: Fixed a case where the system fails to allow the user to check out a key.
Minor logging fixes.
1 parent 844bc61 commit 9124d51

14 files changed

+90
-47
lines changed

current_key_store.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import dataclasses
1+
22
import datetime
3+
import logging
34
from data_objects import KeyData
45
from database import KeysDB
56
from event import Event
67
from key_solenoid_lock import KeySolenoidLock
8+
from logger_instance import logger
79
from mfrc522 import SimpleMFRC522
810

911
KEY_STOLEN_LIMIT = datetime.timedelta(seconds=1)
@@ -39,14 +41,6 @@ def __init__(
3941
self.keys_db = keys_db if keys_db is not None else KeysDB()
4042

4143
def key_tick(self):
42-
card_id = self.key_reader.read_id(timeout=self.key_reader_timeout_s)
43-
# if card_id is not None:
44-
# print("Past Key: ", past_key_card_id)
45-
# print("Key: ", card_id)
46-
if self.past_key_card_id == card_id:
47-
self.past_key_card_id = card_id
48-
return
49-
5044
if (
5145
self._is_key_being_stolen
5246
and datetime.datetime.now() >= self._key_stolen_decision_time
@@ -56,14 +50,22 @@ def key_tick(self):
5650
self._key_stolen_decision_time = None
5751
self.key_stolen.trigger()
5852

53+
card_id = self.key_reader.read_id(timeout=self.key_reader_timeout_s)
54+
# if card_id is not None:
55+
# print("Past Key: ", past_key_card_id)
56+
# print("Key: ", card_id)
57+
if self.past_key_card_id == card_id:
58+
self.past_key_card_id = card_id
59+
return
60+
5961
if self.key_locker.is_key_locked:
6062
if self.past_key_card_id is None:
6163
if (
6264
self._is_key_being_stolen
6365
and datetime.datetime.now() < self._key_stolen_decision_time
6466
and self._past_stolen_key_card_id == card_id
6567
):
66-
print("Key re-found")
68+
logger.log(logging.INFO, "Key re-found")
6769
self.past_key_card_id = card_id
6870
self._is_key_being_stolen = False
6971
self._past_stolen_key_card_id = None
@@ -72,7 +74,7 @@ def key_tick(self):
7274
else:
7375
self.unauthorized_key_swap_attempted.trigger()
7476
else:
75-
print("Key missing")
77+
logger.log(logging.INFO, "Key missing")
7678
self._is_key_being_stolen = True
7779
self._past_stolen_key_card_id = self.past_key_card_id
7880
self.past_key_card_id = None
@@ -87,3 +89,6 @@ def key_tick(self):
8789
self.key_locker.is_key_locked = True
8890
else:
8991
self.unauthorized_key_swap_attempted.trigger()
92+
else:
93+
self.past_key_card_id = None
94+
self.key_locker.is_key_locked = True

data_objects.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
12
from dataclasses import dataclass
3+
from typing import List
24

35

46
@dataclass
@@ -13,4 +15,4 @@ class UserData:
1315
id: str
1416
rf_id: str
1517
name: str
16-
authorized_for: [str]
18+
authorized_for: List[str]

database.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"name": "Key 1"
77
}
88
// f37199a6bd
9+
// b815fc1243
910
],
1011
"users": [
1112
{
@@ -17,5 +18,6 @@
1718
]
1819
}
1920
// 53b5249654
21+
// 625b46512e
2022
]
2123
}

database.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
import functools
23
from typing import Dict
34

@@ -11,7 +12,8 @@
1112
def parse_database():
1213
with open('./database.json') as json_data:
1314
d = pyjson5.load(json_data)
14-
keys = [KeyData(id=v["id"], rf_id=v["rf_id"], name=v["name"]) for v in d["keys"]]
15+
keys = [KeyData(id=v["id"], rf_id=v["rf_id"], name=v["name"])
16+
for v in d["keys"]]
1517
users = [UserData(id=v["id"], rf_id=v["rf_id"], name=v["name"], authorized_for=v["authorized_for"]) for v in
1618
d["users"]]
1719
return keys, users

event.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
class Event:
23
def __init__(self):
34
# Initialise a list of listeners

key_solenoid_lock.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
12
from threading import RLock
3+
from logger_instance import logger
4+
import logging
25

36
import gpiozero
47

@@ -21,10 +24,10 @@ def is_key_locked(self) -> bool:
2124
def is_key_locked(self, value: bool):
2225
with self._lock:
2326
if value:
24-
print("Locking key")
27+
logger.log(logging.INFO, "Locking key")
2528
self._is_key_locked = True
2629
self._solenoid_controller.off()
2730
else:
28-
print("Unlocking key")
31+
logger.log(logging.INFO, "Unlocking key")
2932
self._is_key_locked = False
3033
self._solenoid_controller.on()

logger_instance.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
import logging
3+
import logging.handlers
4+
5+
logger = logging.getLogger("mfrc522Logger")
6+
logFormatter = logging.Formatter(
7+
"%(asctime)s [%(threadName)-12.12s] [%(levelname)-8.8s] %(message)s")
8+
9+
fileHandler = logging.FileHandler("./key_guard.log")
10+
fileHandler.setFormatter(logFormatter)
11+
logger.addHandler(fileHandler)
12+
13+
consoleHandler = logging.StreamHandler()
14+
consoleHandler.setFormatter(logFormatter)
15+
logger.addHandler(consoleHandler)
16+
level = logging.getLevelName(logging.INFO)
17+
logger.setLevel(level)

main.py

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
12
import logging
23
import threading
34
import time
45

56
import gpiozero
67
from RPi import GPIO
7-
from gpiozero.tones import Tone
8+
# from gpiozero.tones import Tone
89

910
from current_key_store import CurrentKeyStore
1011
from data_objects import UserData, KeyData
@@ -13,6 +14,8 @@
1314
from mfrc522 import SimpleMFRC522
1415
from mfrc522.chip_select_lock import ChipSelectLinesLock
1516

17+
from logger_instance import logger
18+
1619

1720
def set_pin_mode():
1821
pin_mode = GPIO.BCM
@@ -26,17 +29,12 @@ def set_pin_mode():
2629

2730
# source ../.virtualenvs/key-guard/bin/activate
2831

29-
logger = logging.getLogger("mfrc522Logger")
30-
logger.addHandler(logging.StreamHandler())
31-
level = logging.getLevelName(logging.WARN)
32-
logger.setLevel(level)
33-
3432
RELOCK_KEY_TIMEOUT_S = 5
3533
READER_TIMEOUT_S = 0.5
3634
MAIN_LOOP_DELAY_S = 1 / 1000
3735

3836
led = gpiozero.LED(27)
39-
buzzer = gpiozero.TonalBuzzer(12, mid_tone=Tone("A5"))
37+
# buzzer = gpiozero.TonalBuzzer(12, mid_tone=Tone("A5"))
4038
solenoid_controller = gpiozero.DigitalOutputDevice(23)
4139
set_pin_mode()
4240
reset_pin = gpiozero.DigitalOutputDevice(22)
@@ -48,9 +46,12 @@ def set_pin_mode():
4846
user_reader_select = gpiozero.DigitalOutputDevice(5)
4947
key_reader_select = gpiozero.DigitalOutputDevice(6)
5048
lines_locks = ChipSelectLinesLock([user_reader_select, key_reader_select])
51-
user_reader = SimpleMFRC522(bus=0, device=0, lock=lines_locks.individual_line_lock(0))
52-
key_reader = SimpleMFRC522(bus=0, device=0, lock=lines_locks.individual_line_lock(1))
53-
key_locker = KeySolenoidLock(init_locked=False, solenoid_controller=solenoid_controller)
49+
user_reader = SimpleMFRC522(
50+
bus=0, device=0, lock=lines_locks.individual_line_lock(0))
51+
key_reader = SimpleMFRC522(
52+
bus=0, device=0, lock=lines_locks.individual_line_lock(1))
53+
key_locker = KeySolenoidLock(
54+
init_locked=False, solenoid_controller=solenoid_controller)
5455
past_user_card_id: str | None = None
5556
current_key_store = CurrentKeyStore(
5657
key_locker=key_locker,
@@ -59,58 +60,58 @@ def set_pin_mode():
5960
key_relock_timeout_s=RELOCK_KEY_TIMEOUT_S,
6061
)
6162

62-
print(
63-
f"Buzzer data: min: {buzzer.min_tone.frequency}, mid: {buzzer.mid_tone.frequency}, max: {buzzer.max_tone.frequency}"
64-
)
63+
# print(
64+
# f"Buzzer data: min: {buzzer.min_tone.frequency}, mid: {buzzer.mid_tone.frequency}, max: {buzzer.max_tone.frequency}"
65+
# )
6566

6667

67-
def turn_off_buzzer():
68-
buzzer.stop()
68+
# def turn_off_buzzer():
69+
# buzzer.stop()
6970

7071

7172
@current_key_store.unauthorized_key_swap_attempted.on
7273
def on_unauthorized_key_swap_attempted():
73-
print("Unauthorized key swap attempted.")
74+
logger.log(logging.WARNING, "Unauthorized key swap attempted.")
7475
led.blink(0.125, 0.125, 16)
7576
# buzzer.play(Tone.from_frequency(1300))
7677
# threading.Timer(3, turn_off_buzzer).start()
7778

7879

7980
@current_key_store.key_stolen.on
8081
def on_key_stolen():
81-
print("Key stolen.")
82+
logger.log(logging.WARNING, "Key stolen.")
8283
led.blink(0.125, 0.125, 8)
83-
buzzer.play(Tone.from_frequency(1700))
84-
threading.Timer(7, turn_off_buzzer).start()
84+
# buzzer.play(Tone.from_frequency(1700))
85+
# threading.Timer(7, turn_off_buzzer).start()
8586

8687

8788
@current_key_store.key_found.on
8889
def on_key_found(key: KeyData):
89-
print("Key found: ", key)
90+
logger.log(logging.INFO, "Key found: %s", key)
9091
led.blink(0.25, 0.25, 4)
91-
buzzer.play(Tone.from_frequency(440))
92-
threading.Timer(1, turn_off_buzzer).start()
92+
# buzzer.play(Tone.from_frequency(440))
93+
# threading.Timer(1, turn_off_buzzer).start()
9394

9495

9596
def on_user_found(user: UserData):
96-
print("User found: ", user)
97+
logger.log(logging.WARNING, "User found: %s", user.name)
9798
led.blink(0.5, 0.5, 2)
98-
buzzer.play(Tone.from_frequency(880))
99-
threading.Timer(RELOCK_KEY_TIMEOUT_S, turn_off_buzzer).start()
99+
# buzzer.play(Tone.from_frequency(880))
100+
# threading.Timer(RELOCK_KEY_TIMEOUT_S, turn_off_buzzer).start()
100101

101102

102103
def on_unknown_user_found(card_id):
103-
print("Unknown user: Card ID: ", card_id)
104+
logger.log(logging.WARNING, "Unknown user: Card ID: %s", card_id)
104105
led.blink(1, 1, 1)
105106
# buzzer.play(Tone.from_frequency(440))
106107
# threading.Timer(3, turn_off_buzzer).start()
107108

108109

109110
def relock_key_timeout_handler():
110-
print("Re-locking key")
111+
logger.log(logging.INFO, "Re-locking key")
111112
current_key_store.key_tick()
112113
key_locker.is_key_locked = True
113-
turn_off_buzzer()
114+
# turn_off_buzzer()
114115

115116

116117
def user_tick():
@@ -127,7 +128,8 @@ def user_tick():
127128
if user is not None:
128129
on_user_found(user)
129130
key_locker.is_key_locked = False
130-
threading.Timer(RELOCK_KEY_TIMEOUT_S, relock_key_timeout_handler).start()
131+
threading.Timer(RELOCK_KEY_TIMEOUT_S,
132+
relock_key_timeout_handler).start()
131133
elif card_id is not None:
132134
on_unknown_user_found(card_id)
133135

@@ -136,7 +138,7 @@ def user_tick():
136138

137139
def on_rfid_card_found(card_id):
138140
led.blink(0.75, 0.25, 3)
139-
print("Unknown card given: ", card_id)
141+
logger.log(logging.WARNING, "Unknown card given: %s", card_id)
140142

141143

142144
try:
@@ -150,3 +152,4 @@ def on_rfid_card_found(card_id):
150152
key_reader.cleanup()
151153
user_reader.cleanup()
152154
GPIO.cleanup()
155+
logging.shutdown()

mfrc522/MFRC522.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
# You should have received a copy of the GNU Lesser General Public License
2121
# along with MFRC522-Python. If not, see <http://www.gnu.org/licenses/>.
2222
#
23+
2324
import logging
2425
import traceback
2526

mfrc522/SimpleMFRC522.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
import math
23
import time
34

mfrc522/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
from .MFRC522 import MFRC522
23
from .SimpleMFRC522 import SimpleMFRC522
34

mfrc522/chip_select_lock.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
from dataclasses import dataclass
23
from threading import RLock
34
from typing import List

singleton.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
class _Singleton(type):
23
""" A metaclass that creates a Singleton base class when called. """
34
_instances = {}

utils.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from contextlib import contextmanager
22
from functools import wraps
33
from time import perf_counter
4+
from logger_instance import logger
5+
import logging
46

57

68
def timing_decorator(f):
@@ -9,7 +11,8 @@ def wrap(*args, **kw):
911
ts = perf_counter()
1012
result = f(*args, **kw)
1113
te = perf_counter()
12-
print(f'func:{f.__name__!r} args:[{args!r}, {kw!r}] took: {te - ts:2.4f} sec')
14+
logger.log(
15+
logging.INFO, f'func:{f.__name__!r} args:[{args!r}, {kw!r}] took: {te - ts:2.4f} sec')
1316
return result
1417

1518
return wrap
@@ -27,4 +30,4 @@ def timing_wither(name) -> float:
2730
t1 = t2 = perf_counter()
2831
yield
2932
t2 = perf_counter()
30-
print(f'func:{name} took: {t2 - t1:2.4f} sec')
33+
logger.log(logging.INFO, f'func:{name} took: {t2 - t1:2.4f} sec')

0 commit comments

Comments
 (0)