I have a system where the user swipes their badge on an RFID reader to login to the computer.
This is done with a screen, a text field, and the PropertyChange event. If the RFID input is ‘ABC’ then I trigger the PropertyChange event at least 3x. Once when ‘A’, once when ‘AB’, and once when ‘ABC’. I thought the system function ‘InvokeLater()’ might limit this but it seems to just delay all 3x propery change events. Given that the RFID might be a variable length what is the best way to go about triggering some script here without calling PropertyChange several times?
import time
def evaluateRFID():
fakeRFID = event.source.text
lenRFID = len(event.source.text)
padRFID = 10 - lenRFID
padZERO = ''
for x in range(padRFID):
padZERO = padZERO + '0'
trueRFID = "BD" + padZERO + fakeRFID
if len(trueRFID)==12:
if event.propertyName == 'text':
if valid:
#do some stuff
else:
#do some other stuff
system.util.invokeLater(evaluateRFID, 2500)
Does the text field have the Defer Updates property set? What keystrokes is the RFID reader sending, exactly? Generally speaking, this should be solved for you by the combination of those two - typically, barcode or RFID readers send the scanned input, then some ending delimiter (usually, an Enter keypress), which would then cause a single property change event.
Your idea with invokeLater could work - but you’d have to use the timing as a ‘debounce’ - so each new invokeLater that’s created would have to check if another invokeLater task had been created since it was, and decide not to run, until the final invokeLater times out and actually runs. This is pretty tricky to reason about, so I’d recommend playing with Defer Updates and the scanner’s settings, if at all possible, to avoid the headache.
I don’t see a ‘defer updates’ property available with the text field. The key strokes are sending ‘68452’ exactly. The customer doesn’t want a ‘Enter’ button. They just need to swipe their badge and some stuff happens around them.
If you are using a tag as a lock for client-side operations, you really should use a client-tag. Otherwise two clients swiping at the same time will clash. Also, consider using a timestamp as your lock tag, setting it just before invokeLater, and comparing inside the invokeLater . Skip if it has changed further.
A millisecond timestamp captured in the event, then both saved in the client tag and passed to the deferred function, will let the deferred function identify if it is the last one. If not last, the client tag would be overwritten with a newer timestamp by the time the function runs. Therefore, if saved timestamp doesn’t match the timestamp passed to the function, exit without doing anything.
Here is my final code… timestamps might be better but I’m not choosing that route today.
def evaluateRFID():
user_Lookup = system.db.runPrepQuery("SELECT * FROM OperatorTable WHERE BadgeID = ?", [event.source.text])
if len(user_Lookup) != 0:
if str(event.source.text) == str(user_Lookup[0][0]):
system.tag.write("[default]Base/RoleTags/badgeFullName",user_Lookup[0][1])
system.tag.write("_Gen_Sim_/BadgeId",(event.source.text))
system.nav.closeWindow('Main Windows/Login')
system.nav.openWindow('Main Windows/Overview')
system.tag.write("[Client]Memory/invokeLater", False)
invokeLaterStatus = system.tag.read("[Client]Memory/invokeLater").value
if invokeLaterStatus == False: #check if function has already been invoked by a property change.
system.tag.write("[Client]Memory/invokeLater", True)
system.util.invokeLater(evaluateRFID, 2500) #delay execution of function evaluateRFID for 2.5 seconds