Zsapp01
Posts: 4
Joined: Tue May 28, 2019 5:57 pm

ATM Tracking Issue

Tue Jun 04, 2019 5:59 pm

Hello, I am trying to make an Atm where you scan an RFID card and then you type in a pin number and it opens the atm. Right now I have it where the ATM will scan a card and enter the pin code and everything works. The only issue I am have is that if you scan a RFID card then scan a second one before the first one times out then the program will freeze up. Below I have posted my code. I did my best to try to solve the issue on my own here is what I did. I created a tracking variable (see line 12). Then on all my resets and forgets I made sure the tracker variable will be returned to equal 0 (see line 68,79,83...etc). After that I tired to make it where if the tracker was equal to 0 (Meaning that somewhere the code has been reset) then let the RFID scan correctly and open the next panel. On line 161 i made it set tracker to 1 so that mean a rfid was scanned and should not allow another card to be scanned. The main issue is im not sure where and how i need to place the if statement to allow this to work. If anyone can help me it would be greatly appreciated. If you have more question just reply below and ill respond asap. Thanks again

Code: Select all

#!/usr/bin/env python3
import sys
import MySQLdb
from threading import Thread
import threading
import time
import RPi.GPIO as GPIO
import json
from random import randint
from evdev import InputDevice
from select import select
tracker = 0;
#from twilio.rest import Client

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(13,GPIO.OUT)

try:
    # python 2
    import Tkinter as tk
    import ttk
except ImportError:
    # python 3
    import tkinter as tk
    from tkinter import ttk
    
class Fullscreen_Window:
    
    global dbHost
    global dbName
    global dbUser
    global dbPass
    
    dbHost = 'localhost'
    dbName = 'door_lock'
    dbUser = 'admin'
    dbPass = 'Starwars1460'
    
    def __init__(self):
        self.tk = tk.Tk()
        self.tk.title("Three-Factor Authentication Security Door Lock")
        self.frame = tk.Frame(self.tk)
        self.frame.grid()
        self.tk.columnconfigure(1, weight=1)
        
        
        self.tk.attributes('-zoomed', True)
        self.tk.attributes('-fullscreen', True)
        self.state = True
        self.tk.bind("<F11>", self.toggle_fullscreen)
        self.tk.bind("<Escape>", self.end_fullscreen)
        self.tk.config(cursor="none")
        
        self.show_idle()
        
        t = Thread(target=self.listen_rfid)
        t.daemon = True
        t.start()
        
    
    def show_idle(self):
        self.welcomeLabel = ttk.Label(self.tk, text="WELCOME TO\nBANK OF ESCAPE KEMAH\nPLEASE INSERT CARD")
        self.welcomeLabel.config(font='size, 30 bold', justify='center', anchor='center',foreground="white", background="royalblue3")
        self.welcomeLabel.grid(column=1, sticky=tk.W+tk.E, pady=170)
        
    def pin_entry_forget(self):
        tracker = 0
        self.validUser.grid_forget()
        self.photoLabel.grid_forget()
        self.enterPINlabel.grid_forget()
        self.row4bg.grid_forget()
        count = 0
        while (count < 12):
            self.btn[count].grid_forget()
            count += 1
            
    def openAtm_forget(self):
        tracker = 0
        self.openAtm.grid_forget()
    
    def closeAtm_forget(self):
        tracker = 0
        self.closeAtm.grid_forget()
        
    def returnToIdle_fromPINentry(self):
        tracker = 0
        self.pin_entry_forget()
        self.show_idle()
        
    def returnToIdle_fromopenAtm(self):
        tracker = 0
        self.openAtm_forget()
        self.show_idle()
        
    def returnToIdle_fromcloseAtm(self):
        tracker = 0
        self.closeAtm_forget()
        self.show_idle()
        
    def returnToIdle_fromPINentered(self):
        tracker = 0
        self.PINresultLabel.grid_forget()
        self.show_idle()
        
    #def returnToIdle_fromAccessGranted(self):
        #GPIO.output(13,GPIO.LOW)
        #self.SMSresultLabel.grid_forget()
        #self.show_idle()
        
    #def returnToIdle_fromSMSentry(self):
        #self.PINresultLabel.grid_forget()
        #self.smsDigitsLabel.grid_forget()
        #count = 0
        #while (count < 12):
            #self.btn[count].grid_forget()
            #count += 1
        #self.show_idle()
        
    #def returnToIdle_fromSMSentered(self):
        #self.SMSresultLabel.grid_forget()
        #self.show_idle()
    
    def toggle_fullscreen(self, event=None):
        self.state = not self.state  # Just toggling the boolean
        self.tk.attributes("-fullscreen", self.state)
        return "break"

    def end_fullscreen(self, event=None):
        self.state = False
        self.tk.attributes("-fullscreen", False)
        return "break"
        
    def listen_rfid(self):
        global pin
        global accessLogId
        
        keys = "X^1234567890XXXXqwertzuiopXXXXasdfghjklXXXXXyxcvbnmXXXXXXXXXXXXXXXXXXXXXXX"
        dev = InputDevice('/dev/input/event3')
        rfid_presented = ""    
        while True:
            r,w,x = select([dev], [], [])
            for event in dev.read():
                if event.type==1 and event.value==1:
                        if event.code==28:
                            dbConnection = MySQLdb.connect(host=dbHost, user=dbUser, passwd=dbPass, db=dbName)
                            cur = dbConnection.cursor(MySQLdb.cursors.DictCursor)
                            cur.execute("SELECT * FROM access_list WHERE rfid_code = '%s'" % (rfid_presented))
 
                            if cur.rowcount != 1:
                                self.welcomeLabel.config(text="ACCESS DENIED")
                                
                                # Log access attempt
                                cur.execute("INSERT INTO access_log SET rfid_presented = '%s', rfid_presented_datetime = NOW(), rfid_granted = 0" % (rfid_presented))
                                dbConnection.commit()
                                
                                time.sleep(3)
                                self.welcomeLabel.grid_forget()
                                self.show_idle()
                            else:
                                tracker = 1
                                user_info = cur.fetchone()
                                userPin = user_info['pin']
                                self.welcomeLabel.grid_forget()
                                self.validUser = ttk.Label(self.tk, text="Welcome\n %s!" % (user_info['name']), font='size, 18', justify='center', anchor='center',foreground="white", background="royalblue3")
                                self.validUser.grid(column=1,columnspan=1, sticky=tk.N+tk.S+tk.E+tk.W)
                                
                                self.image = tk.PhotoImage(file=user_info['image'] + ".gif")
                                self.photoLabel = ttk.Label(self.tk, image=self.image, background="royalblue3", justify="center", anchor="center")
                                self.photoLabel.grid(column=1, columnspan=1,sticky=tk.N+tk.S+tk.E+tk.W)
                                
                                self.enterPINlabel = ttk.Label(self.tk, text="Please enter your PIN:", font='size, 16', justify='center', anchor='center', foreground="white",background="royalblue3")
                                self.enterPINlabel.grid(column=1, columnspan=1, sticky=tk.N+tk.S+tk.E+tk.W)
                                
                                self.row4bg = ttk.Label(self.tk, background="royalblue3")
                                self.row4bg.grid(column=1, columnspan=1,sticky=tk.N+tk.S+tk.E+tk.W)
                                
            
                                pin = ''
                                
                                keypad = [
                                    '1', '2', '3',
                                    '4', '5', '6',
                                    '7', '8', '9',
                                    '*', '0', '#',
                                ]
                                
                                # create and position all buttons with a for-loop
                                # r, c used for row, column grid values
                                r = 1
                                c = 8
                                n = 0
                                # list(range()) needed for Python3
                                self.btn = list(range(len(keypad)))
                                for label in keypad:
                                    # partial takes care of function and argument
                                    #cmd = partial(click, label)
                                    # create the button
                                    self.btn[n] = tk.Button(self.tk, text=label, font='size, 18',foreground="white",background="royalblue3", width=4, height=1, command=lambda digitPressed=label:self.codeInput(digitPressed, userPin, user_info['sms_number']))
                                    # position the button
                                    self.btn[n].grid(row=r, column=c, ipadx=10, ipady=20, pady=20)
                                    # increment button index
                                    n += 1
                                    # update row/column position
                                    c += 1
                                    if c > 10:
                                        c = 8
                                        r += 1

                                
                                # Log access attempt
                                cur.execute("INSERT INTO access_log SET rfid_presented = '%s', rfid_presented_datetime = NOW(), rfid_granted = 1" % (rfid_presented))
                                dbConnection.commit()
                                accessLogId = cur.lastrowid
                                
                                self.PINentrytimeout = threading.Timer(10, self.returnToIdle_fromPINentry)
                                self.PINentrytimeout.start()
                                
                                self.PINenteredtimeout = threading.Timer(5, self.returnToIdle_fromPINentered)
                               
                            rfid_presented = ""
                            dbConnection.close()
                        else:
                            rfid_presented += keys[ event.code ]

    def codeInput(self, value, userPin, mobileNumber):
        global accessLogId
        global pin
        global smsCodeEntered
        pin += value
        pinLength = len(pin)
        
        self.enterPINlabel.config(text="Digits Entered: %d" % pinLength)
        
        if pinLength == 4:
            self.PINentrytimeout.cancel()
            self.pin_entry_forget()
            
            if pin == userPin:
                self.pin_entry_forget()
                
                self.openAtm = ttk.Label(self.tk, text="ACCESS GRANTED\nUNLOCKING ATM")
                self.openAtm.config(font='size, 30 bold', justify='center', anchor='center',foreground="white", background="green")
                self.openAtm.grid(column=1, sticky=tk.W+tk.E, pady=170)
        
                self.openAtmtimeout = threading.Timer(5, self.returnToIdle_fromopenAtm)
                self.openAtmtimeout.start()

            else:
                self.pin_entry_forget()
                
                self.closeAtm = ttk.Label(self.tk, text="ACCESS DENIED\nLOCKING ATM")
                self.closeAtm.config(font='size, 30 bold', justify='center', anchor='center',foreground="white", background="firebrick")
                self.closeAtm.grid(column=1, sticky=tk.W+tk.E, pady=170)
        
                self.closeAtmtimeout = threading.Timer(3, self.returnToIdle_fromcloseAtm)
                self.closeAtmtimeout.start()
            
            # Log access attempt
            dbConnection = MySQLdb.connect(host=dbHost, user=dbUser, passwd=dbPass, db=dbName)
            cur = dbConnection.cursor()
            cur.execute("UPDATE access_log SET pin_entered = '%s', pin_entered_datetime = NOW(), pin_granted = %s, mobile_number = '%s' WHERE access_id = %s" % (pin, pin_granted, mobileNumber, accessLogId))
            dbConnection.commit()
            
            #if pin == userPin:
                #self.PINresultLabel = ttk.Label(self.tk, text="Thank You, Now\nPlease Enter Code\nfrom SMS\n")
                #self.PINresultLabel.config(font='size, 20', justify='center', anchor='center')
                #self.PINresultLabel.grid(columnspan=3, sticky=tk.W+tk.E, pady=20)
                
                #self.smsDigitsLabel = ttk.Label(self.tk, text="Digits Entered: 0", font='size, 18', justify='center', anchor='center')
                #self.smsDigitsLabel.grid(columnspan=3, sticky=tk.W+tk.E)
                
                #smsCode = self.sendSMScode(mobileNumber)
                #smsCodeEntered = ''
                
                #keypad = [
                   # '1', '2', '3',
                   # '4', '5', '6',
                   # '7', '8', '9',
                   # '', '0', '',
                #]
                                
                # create and position all buttons with a for-loop
                # r, c used for row, column grid values
                #r = 4
                #c = 0
                #n = 0
                # list(range()) needed for Python3
                #self.btn = list(range(len(keypad)))
                #for label in keypad:
                    # partial takes care of function and argument
                    #cmd = partial(click, label)
                    # create the button
                    #self.btn[n] = tk.Button(self.tk, text=label, font='size, 18', width=4, height=1, command=lambda digitPressed=label:self.smsCodeEnteredInput(digitPressed, smsCode))
                    # position the button
                    #self.btn[n].grid(row=r, column=c, ipadx=10, ipady=10)
                    # increment button index
                    #n += 1
                    # update row/column position
                    #c += 1
                    #if c > 2:
                       # c = 0
                       # r += 1
                
                #self.SMSentrytimeout = threading.Timer(60, self.returnToIdle_fromSMSentry)
                #self.SMSentrytimeout.start()
                
            #else:
                #self.PINresultLabel = ttk.Label(self.tk, text="Incorrect PIN\nEntered!")
                #self.PINresultLabel.config(foreground="white", background="firebrick",font='size, 30 bold', justify='center', anchor='center')
                #self.PINresultLabel.grid(column=1,sticky=tk.W+tk.E, pady=170)
                #self.PINenteredtimeout.start()
                
    #def smsCodeEnteredInput(self, value, smsCode):
        #global smsCodeEntered
        #global accessLogId
        #smsCodeEntered += value
        #smsCodeEnteredLength = len(smsCodeEntered)
        #
        #self.smsDigitsLabel.config(text="Digits Entered: %d" % smsCodeEnteredLength)
        
        #if smsCodeEnteredLength == 6:
            #self.SMSentrytimeout.cancel()
            #self.pin_entry_forget()
            
            #if smsCodeEntered == smsCode:
                #smscode_granted = 1
            #else:
                #smscode_granted = 0
            
            # Log access attempt
            #dbConnection = MySQLdb.connect(host=dbHost, user=dbUser, passwd=dbPass, db=dbName)
           # cur = dbConnection.cursor()
            #cur.execute("UPDATE access_log SET smscode_entered = '%s', smscode_entered_datetime = NOW(), smscode_granted = %s WHERE access_id = %s" % (smsCodeEntered, smscode_granted, accessLogId))
            #dbConnection.commit()
            
            #if smsCodeEntered == smsCode:
                #self.SMSresultLabel = ttk.Label(self.tk, text="Thank You,\nAccess Granted")
                #self.SMSresultLabel.config(font='size, 20', justify='center', anchor='center')
                #self.SMSresultLabel.grid(columnspan=3, sticky=tk.W+tk.E, pady=210)
                
                #self.PINresultLabel.grid_forget()
                #self.smsDigitsLabel.grid_forget()
                #GPIO.output(13,GPIO.HIGH)
                
                #self.doorOpenTimeout = threading.Timer(10, self.returnToIdle_fromAccessGranted)
                #self.doorOpenTimeout.start()
            #else:
                #self.PINresultLabel.grid_forget()
                #self.smsDigitsLabel.grid_forget()
                
                #self.SMSresultLabel = ttk.Label(self.tk, text="Incorrect SMS\nCode Entered!")
                #self.SMSresultLabel.config(font='size, 20', justify='center', anchor='center')
                #self.SMSresultLabel.grid(sticky=tk.W+tk.E, pady=210)
                
                #self.SMSenteredtimeout = threading.Timer(10, self.returnToIdle_fromSMSentered)
                #self.SMSenteredtimeout.start()
                
    #def sendSMScode(self, mobileNumber):
    
        # Retreive our Twilio access credentials and "from" number
        #dbConnection = MySQLdb.connect(host=dbHost, user=dbUser, passwd=dbPass, db=dbName)
        #cur = dbConnection.cursor(MySQLdb.cursors.DictCursor)
        #cur.execute("SELECT account_sid, auth_token, twilio_sms_number FROM twilio_api_credentials WHERE id = 1")
        #credentials = cur.fetchone()
        #account_sid = credentials['account_sid']
        #auth_token = credentials['auth_token']
        #twilio_sms_number = credentials['twilio_sms_number']
        #dbConnection.close()
                
        #smsCode = str(randint(100000, 999999))
        #messageText = "Your access code is %s. Please enter this on the touchscreen to continue." % smsCode

        #client = Client(account_sid, auth_token)
        #message = client.messages.create(
            #to=mobileNumber, 
            #from_=twilio_sms_number,
            #body=messageText)
        
        #return smsCode

if __name__ == '__main__':
    w = Fullscreen_Window()
    w.tk.mainloop()

ghp
Posts: 1352
Joined: Wed Jun 12, 2013 12:41 pm
Location: Stuttgart Germany
Contact: Website

Re: ATM Tracking Issue

Wed Jun 05, 2019 8:55 pm

Hello, your code has some elements which make a test on a different system cumbersome.
- there is a database used, but you do not provide schema definition and data
- there is a rfid used which is unfortunately missing on my system
- and tkinter is in full screen. No cursor makes my mouse useless.
- and GPIO is used. On my development machine, there is no GPIO.

* In order to replace the database, there is now a wrapper class 'User' which has methods which can retrieve data from a mock implementation. If you like this idea, then place your sql statements inside this class.
* In order to replace the rfid, I first used a thread which reads data from sys.stdin. In current draft, there is a thread where you can place your current eventInput code. The draft just periodically produces RFID in ERROR state (you will check here for valid users also).
* modified tkinter to be not in full screen. And added a cursor, which is nice on my no-touch-screen
* GPIO is not a problem. I have a mockup which just print out the data.

Generally, I propose a more appropriate program structure. Your approach was to solve everything inside tkinter, which makes the code very difficult to understand. My proposal is to use tkinter just as plain front end, and all the control logic is handled in a state machine outside.

Details:
Core is a state machine "thread_state_machine". It maintains state. Inputs are from an event_queue.
--> The rfid-thread writes into this queue.
--> PIN input from GUI goes into this queue.
--> When needed, a Timer puts TIMEOUT events into the queue.
<-- state machine is only consumer of events here.

Whatever needs to be done in GUI is put onto a gui_queue.
<-- tkinter reads this periodically and just adds, removes widgets as needed. Timers, delays, database access, all this business logic is no longer needed inside tkinter.
--> statemachine puts simple controls onto the gui_queue as GUI_PIN (show heyboard), GUI_PIN_CANCEL (remove it), GUI_STATUS (status line)

I did not worry about the image things, I added a status line. Not very nice, but works.

There is a thread_TEST, which puts events into the event_queue. Used this to verify the draft. You can place more tests into this and remove then for release code.

The code is not production level, I just added, corrected, modified whatever needed to make the basics working.

Code: Select all

#!/usr/bin/env python3
import sys

#### import MySQLdb
from threading import Thread
import threading
import time

#
# TEST: replace GPIO by a mockup
#
try:
    import RPi.GPIO as GPIO
except Exception:
    class GPIO:
        BCM = 0
        OUT = 1
        IN = 2
        @staticmethod
        def setmode( m):
            print(GPIO, "setmode")
        @staticmethod
        def setwarnings( b):
            print(GPIO, "setwarnings")
        @staticmethod
        def setup(p,b):
            print(GPIO, "setup", b, b)

def deprecated(func):
    def wrapper(*args, **kwargs):
        print("deprecated")
        return func( * args, **kwargs)
    return wrapper
                        
import json
from random import randint
##### from evdev import InputDevice
from select import select
tracker = 0;
#from twilio.rest import Client

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(13,GPIO.OUT)

#
# TEST: replace mysql access by a wrapper class which uses some predefined users
#

class Users:
    def __init__(self):
        self.users = [
              { 'id' : "A",
                 'name': "AAA",
                'rfid' : 'AA',
                'pin' : '1',
                'image': 'ball1', 'sms_number':'4711'
              },
              { 'id' : "B",
                 'name': "BBB",
                'rfid' : 'BB',
                'pin' : '1',
                'image': 'ball2', 'sms_number':'4711'
              },
              { 'id' : "C",
                'name': "CCC",

                'rfid' : 'CC',
                'pin' : '1',
                'image': 'ball2', 'sms_number':'4711'


              },
              
            ]
    def getUsersByRfid(self, rfid):
        print("getUsersByRfid", rfid)
        for u in self.users:
            if u['rfid'] == rfid:
                return u
        print("getUsersByRfid", "nope")
        return None
    
    def addAccessLog(self, r):
        print(r)
        
users = Users()
    
import queue
import random

event_queue = queue.Queue()
gui_queue = queue.Queue()

def thread_rfid():
    print("thread_rfid")
    keys = "X^1234567890XXXXqwertzuiopXXXXasdfghjklXXXXXyxcvbnmXXXXXXXXXXXXXXXXXXXXXXX"
    ## dev = InputDevice('/dev/input/event3')
        
    while True:
        rfid_presented = ""    
#              r,w,x = select([dev], [], [])
#             for event in dev.read():
#                 if event.type==1 and event.value==1:
#                         if event.code==28:
#                             dbConnection = MySQLdb.connect(host=dbHost, user=dbUser, passwd=dbPass, db=dbName)
#                             cur = dbConnection.cursor(MySQLdb.cursors.DictCursor)
#                             cur.execute("SELECT * FROM access_list WHERE rfid_code = '%s'" % (rfid_presented))
#                             
#                             # post result to event_queue
#                             event_queue.put(
#                                 {
#                                     'command': "RFID",
#                                     'rfid': "your rfid",
#                                     'pin' : "the pin from database",
#                                     # possibly other data
#                                 }
#                             )
#

        # TEST CODE here 
        time.sleep( random.randint(15, 30))
        event_queue.put(
                            {
                                'command': "RFID",
                                'status' : 'ERROR',
                                'rfid': "your rfid",
                                'pin' : "the pin from database",
                                # possibly other data
                            }
                        ) 

def thread_timer():
    print("thread_timer")
    event_queue.put(
          {
              'command' : 'TIMEOUT'
          }
        )        

START = 'START'
WAIT_PIN = 'WAIT_PIN'
ERROR = "ERROR"
SUCCESS = "SUCCESS"


def thread_state_machine():
    print("thread_state_machine")
    status = START
    timer = None
    while True:
        e = event_queue.get(block = True)
        print("STATUS", status, e)
        
        if status == START:
            if e['command'] == "RFID":
                if e['status'] == 'OK':
                    gui_queue.put({ 
                                     'command' : 'GUI_PIN'
                                  })
                    timer = threading.Timer(20, thread_timer)
                    timer.start()
                    
                    status = WAIT_PIN
                
                elif e['status'] == 'ERROR':   
                    gui_queue.put({ 
                                     'command' : 'GUI_STATUS',
                                     'message' : 'wrong rfid'
                                  })
                    status = START
                    
        elif status == WAIT_PIN:
            if e['command'] == "TIMEOUT":
                gui_queue.put({ 
                                     'command' : 'GUI_PINCANCEL',
                                     
                                  })             
                gui_queue.put({ 
                                     'command' : 'GUI_STATUS',
                                     'message' : 'timeout error'
                                  })
                
            elif e['command'] == "PIN":
                timer.cancel()
                #
                # check pin 
                # TEST: assume its ok
                if e['pin'] == '1234':
                    print("SUCCESS")
                    #
                    # and switch the lock signal
                    #
                    gui_queue.put({ 
                                     'command' : 'GUI_PINCANCEL',
                                     
                                  })             
                    gui_queue.put({ 
                                         'command' : 'GUI_SUCCESS',
                                         
                                      })             
                    status = SUCCESS
                    timer = threading.Timer(5, thread_timer)
                    timer.start()
                    
                else:
                    gui_queue.put({ 
                                     'command' : 'GUI_PINCANCEL',
                                     
                                  })             
                    gui_queue.put({ 
                                         'command' : 'GUI_ERROR',
                                         
                                      })             
                    gui_queue.put({ 
                                     'command' : 'GUI_STATUS',
                                     'message' : 'try again'
                                  })
                    status = ERROR
                    timer = threading.Timer(5, thread_timer)
                    timer.start()
                    
        elif status == SUCCESS:
            if e['command'] == "TIMEOUT":
                gui_queue.put({ 
                                         'command' : 'GUI_START',
                                         
                                      })             
                  
                status = START
            elif e['command'] == 'RFID':
                if e['status'] == 'OK':
                    gui_queue.put({ 
                                         'command' : 'GUI_PIN'
                                      })
                    timer = threading.Timer(20, thread_timer)
                    timer.start()
                        
                    status = WAIT_PIN
                                       
        elif status == ERROR:
            
            if e['command'] == "TIMEOUT":
                gui_queue.put({ 
                                         'command' : 'GUI_START',
                                         
                                      })             
                
                status = START
                
            elif e['command'] == 'RFID':
                if e['status'] == 'OK':
                    gui_queue.put({ 
                                     'command' : 'GUI_PIN'
                                  })
                    timer = threading.Timer(20, thread_timer)
                    timer.start()
                    
                    status = WAIT_PIN
                    


threading.Thread(target=thread_state_machine).start()
threading.Thread(target=thread_rfid).start()

def thread_TEST():
    time.sleep(3)
    print("TEST", "RFID")
    event_queue.put(
                            {
                                'command': "RFID",
                                'status' : 'OK',
                                'rfid': "AA",
                                'pin' : "1234",
                                # possibly other data
                            }
                   )
    time.sleep(30)
    print("TEST", "RFID")
    event_queue.put(
                            {
                                'command': "RFID",
                                'status' : 'OK',
                                'rfid': "AA",
                                'pin' : "1234",
                                # possibly other data
                            }
                   )
    
threading.Thread(target=thread_TEST).start()
                    
try:
    # python 2
    import Tkinter as tk
    import ttk
except ImportError:
    # python 3
    import tkinter as tk
    from tkinter import ttk

class StatusBar(tk.Frame):   
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.variable=tk.StringVar()        
        self.label=tk.Label(self, bd=1, relief=tk.SUNKEN, anchor=tk.W,
                           textvariable=self.variable,
                           font=('arial',16,'normal'))
        self.variable.set('Status Bar')
        self.label.pack(fill=tk.X)        
        self.pack(side=tk.BOTTOM)
    def set_text(self, text):
        self.variable.set(text)
              
class Fullscreen_Window:
    
    global dbHost
    global dbName
    global dbUser
    global dbPass
    
    dbHost = 'localhost'
    dbName = 'door_lock'
    dbUser = 'admin'
    dbPass = 'Starwars1460'
    
    def __init__(self):
        print("initialize Window")
        self.tk = tk.Tk()
        self.tk.title("Three-Factor Authentication Security Door Lock")
        self.frame = tk.Frame(self.tk)
        self.frame.grid()
        self.tk.columnconfigure(1, weight=1)
        self.statusbar = StatusBar(self.frame)
        
        ##### error in:  self.tk.attributes('-zoomed', True)
        ##### self.tk.attributes('-fullscreen', True)
        self.state = True
        self.tk.bind("<F11>", self.toggle_fullscreen)
        self.tk.bind("<Escape>", self.end_fullscreen)
        self.tk.config(cursor="arrow")
        
        
        self.btn = []
        
        self.welcomeLabel = None
        self.closeAtm = None
        self.openAtm = None
        self.enterPINlabel = None
        
        self.show_idle(True)
        self.pin = ""
        self.frame.after(100, self.command_input)
        
    def command_input(self):
        try:
            e = gui_queue.get(block=True, timeout=0.05)
            print("GUI", e)
            if e['command'] == 'GUI_START':
                self.show_idle(True)
                self.show_error(False)
                self.show_success(False)
                self.show_pinlabel(False)
                self.show_keypad(False)
                 
            elif e['command'] == 'GUI_PIN':
                self.pin = ""
                self.show_idle(False)
                self.show_error(False)
                self.show_success(False)
                self.show_pinlabel(True)
                self.show_keypad(True)
                
            elif e['command'] == 'GUI_PINCANCEL':
                self.pin = ""
                self.show_idle(True)
                self.show_error(False)
                self.show_success(False)
                self.show_pinlabel(False)
                self.show_keypad(False)
 
                
            elif e['command'] == 'GUI_SUCCESS':
                self.pin = ""
                self.show_idle(False)
                self.show_error(False)
                self.show_success(True)
                self.show_pinlabel(False)
                self.show_keypad(False)

                
            elif e['command'] == 'GUI_ERROR':
                self.pin = ""
                self.show_idle(False)
                self.show_error(True)
                self.show_success(False)
                self.show_pinlabel(False)
                self.show_keypad(False)
                
            elif e['command'] == 'GUI_STATUS':
                self.statusbar.set_text(  e['message'])
            else:
                print("GUI", "UNKNOWN COMMAND")    
        except queue.Empty:
            
            return
        finally:
            self.frame.after(100, self.command_input)
            
    def show_idle(self, visible):
        if visible:
            if self.welcomeLabel is  None:
                self.welcomeLabel = ttk.Label(self.tk, text="WELCOME TO\nBANK OF ESCAPE KEMAH\nPLEASE INSERT CARD")
            self.welcomeLabel.config(font='size, 30 bold', justify='center', anchor='center',foreground="white", background="royalblue3")
            self.welcomeLabel.grid(column=1, sticky=tk.W+tk.E, pady=170)
        else:
            if self.welcomeLabel is not None:
                self.welcomeLabel.grid_forget()
    
    def show_pinlabel(self, visible):
        if visible:
            if self.enterPINlabel is None:
                self.enterPINlabel = ttk.Label(self.tk, text="Please enter your PIN:", font='size, 16', justify='center', anchor='center', foreground="white",background="royalblue3")
            self.enterPINlabel.config(text="Please enter your PIN:")
            self.enterPINlabel.grid(column=1, columnspan=1, sticky=tk.N+tk.S+tk.E+tk.W)
        else:
            if self.enterPINlabel is not None:
                self.enterPINlabel.grid_forget()
                                        
    def pin_entry_forget(self):
        tracker = 0
        ###self.validUser.grid_forget()
        ###self.photoLabel.grid_forget()
        ###self.enterPINlabel.destroy()
        #self.row4bg.grid_forget()
        count = 0
        try:
            while (count < 12):
                self.btn[count].destroy()
                count += 1
        except Exception:
            pass
        
    @deprecated    
    def openAtm_forget(self):
        tracker = 0
        self.openAtm.grid_forget()
    
    @deprecated    
    def closeAtm_forget(self):
        tracker = 0
        self.closeAtm.grid_forget()
        
    @deprecated    
    def returnToIdle_fromPINentry(self):
        tracker = 0
        self.pin_entry_forget()
        self.show_idle()
        
    @deprecated    
    def returnToIdle_fromopenAtm(self):
        tracker = 0
        self.openAtm_forget()
        self.show_idle()
        
    @deprecated    
    def returnToIdle_fromcloseAtm(self):
        tracker = 0
        self.closeAtm_forget()
        self.show_idle()
        
    @deprecated    
    def returnToIdle_fromPINentered(self):
        tracker = 0
        self.PINresultLabel.grid_forget()
        self.show_idle()
        
    def toggle_fullscreen(self, event=None):
        self.state = not self.state  # Just toggling the boolean
        ####### self.tk.attributes("-fullscreen", self.state)
        return "break"

    def end_fullscreen(self, event=None):
        self.state = False
        ####### self.tk.attributes("-fullscreen", False)
        return "break"
    
    @deprecated    
    def listen_rfid(self):
        global pin
        global accessLogId
        rfid_presented = ""
        while True:
            print("current rfid_presented",rfid_presented )
            r = sys.stdin.read(1)
            r = r.strip()
            print("char read '{r:s}'".format(r= r))
            if r == 'x':
                user = users.getUsersByRfid(rfid_presented )
                
                if user == None:
                    self.welcomeLabel.config(text="ACCESS DENIED")
                    
                    # Log access attempt
                    users.addAccessLog(rfid_presented )
                    
                    
                    time.sleep(3)
                    self.welcomeLabel.grid_forget()
                    self.show_idle()
                else:
                    tracker = 1
                    user_info = users.getUsersByRfid(rfid_presented)
                    userPin = user_info['pin']
                    self.welcomeLabel.grid_forget()
                    self.validUser = ttk.Label(self.tk, text="Welcome\n %s!" % (user_info['name']), font='size, 18', justify='center', anchor='center',foreground="white", background="royalblue3")
                    self.validUser.grid(column=1,columnspan=1, sticky=tk.N+tk.S+tk.E+tk.W)
                    
                    self.image = tk.PhotoImage(file=user_info['image'] + ".gif")
                    self.photoLabel = ttk.Label(self.tk, image=self.image, background="royalblue3", justify="center", anchor="center")
                    self.photoLabel.grid(column=1, columnspan=1,sticky=tk.N+tk.S+tk.E+tk.W)
                    
                    self.enterPINlabel = ttk.Label(self.tk, text="Please enter your PIN:", font='size, 16', justify='center', anchor='center', foreground="white",background="royalblue3")
                    self.enterPINlabel.grid(column=1, columnspan=1, sticky=tk.N+tk.S+tk.E+tk.W)
                    
                    self.row4bg = ttk.Label(self.tk, background="royalblue3")
                    self.row4bg.grid(column=1, columnspan=1,sticky=tk.N+tk.S+tk.E+tk.W)
                    
    
                    pin = ''
                    
    def show_keypad(self, visible): 
        if visible :           
            keypad = [
                '1', '2', '3',
                '4', '5', '6',
                '7', '8', '9',
                '*', '0', '#',
            ]
            
        
            
            # list(range()) needed for Python3
            #self.btn = list(range(len(keypad)))
            if len(self.btn) == 0:
                print("create new buttons")
                n = 0
                for label in keypad:
                    # partial takes care of function and argument
                    #cmd = partial(click, label)
                    # create the button
                    
                    self.btn.append( tk.Button(self.tk, 
                                            text=label, 
                                            font='size, 18',
                                            foreground="white",
                                            background="royalblue3", 
                                            width=4, 
                                            height=1, 
                                            command=lambda digitPressed=label:self.codeInput(digitPressed)) )
                    n += 1
            print( "length btn", len(self.btn) )
                    
            # position the button
            # create and position all buttons with a for-loop
            # r, c used for row, column grid values
            r = 1
            c = 8
            n = 0
            for label in keypad:
                print("label", "grid",  label, r, c)
                self.btn[n].grid(row=r, column=c, ipadx=10, ipady=20, pady=20)
                    
                # increment button index
                n += 1
                # update row/column position
                c += 1
                if c > 10:
                    c = 8
                    r += 1
    
                
            # Log access attempt
            users.addAccessLog(r)
        
        else:
            if len(self.btn) != 0:
                try:
                    # forget does not work multiple. So Just ignore errors 
                    for btn in self.btn:
                        print(btn)
                        btn.grid_forget()
                except Exception:
                    pass  
 
    def show_success(self, visible):
        if visible:
            if self.openAtm is None:
                self.openAtm = ttk.Label(self.tk, text="ACCESS GRANTED\nUNLOCKING ATM")
            self.openAtm.config(font='size, 30 bold', justify='center', anchor='center',foreground="white", background="green")
            self.openAtm.grid(column=1, sticky=tk.W+tk.E, pady=170)
        else:
            if self.openAtm is not None:
                self.openAtm.grid_forget()
                
    def show_error(self, visible):
        if visible:
            ##self.pin_entry_forget() # ????
            if self.closeAtm is not None:
                self.closeAtm = ttk.Label(self.tk, text="ACCESS DENIED\nLOCKING ATM")
            self.closeAtm.config(font='size, 30 bold', justify='center', anchor='center',foreground="white", background="firebrick")
            self.closeAtm.grid(column=1, sticky=tk.W+tk.E, pady=170)
        else:
            if self.closeAtm is not None:
                self.closeAtm.grid_forget()
            
    def codeInput(self, value):
        print("codeInput", value, self.pin )
        
        global accessLogId
        
        global smsCodeEntered
        self.pin += value
        pinLength = len( self.pin)
        
        self.enterPINlabel.config(text="Digits Entered: %d" % pinLength)
        
        if pinLength == 4: ################  4:
            ## self.PINentrytimeout.cancel()
            # self.pin_entry_forget()
            
            event_queue.put({
                    'command': "PIN",
                    'pin' : self.pin
                    })

            self.pin = ""
            
 

if __name__ == '__main__':
    w = Fullscreen_Window()
    w.tk.mainloop()

Return to “Python”