如何让系统实现RFID卡二次读取退出?
How to make the system realize that the RFID card is read for 2nd time for sign out?
我是初学者,我需要一些help/guidance!
所以基本上我正在尝试使用 Raspberry Pi 4 和 RFID reader 和 writer 制作一个考勤系统。到目前为止,一切都运行良好,但我正在为 sign_out 发送数据而苦苦挣扎。现在,sign_in 中的相同时间戳也在数据库中的 signed_out 中标记,但在这里我想在第二次读取 RFID 卡时填充数据sign_out 列。
如果您有任何其他建议,我很乐意 hear/learn,谢谢。
编辑:"the whole code was deleted from this question"
您是否考虑过将 sign-in/sign-out 视为一个开关?默认状态是 sign-in
设置为 0 或 false,sign-out
设置为 1 或 true。然后,当读取卡时,它会检查登录值。如果它是 0/false,它会翻转为 1/true,并进行相反的翻转以注销。第二次读卡时,读取sign-out,如果为0/false,则设置为1/true,与sign-in相反。
为清楚起见:
current state:
sign-in = 0
sign-out = 1
---> card is read for the first time
sign-in = (sign-in + 1) % 2
sign-out = (sign-out + 1) %2
state now:
sign-in = 1
sign-out = 0
---> card is read for the second time, consider previous state
sign-in = (sign-i + 1) % 2
sign-out = (sign-out + 1) % 2
state:
sign-in = 0
sign-out = 1
这可以通过将 2 个状态减少为一个状态来进一步简化,signed-in
。
initial state:
signed-in = 0
---> card is read for entry
signed-in = (signed-in + 1) % 2
state:
signed-in = 1
---> card is read for exit
signed-out = (signed-in + 1) % 2
state:
signed-in = 0
简单地说,您想将其视为具有两个转换的简单状态机:从 In
到 Out
和从 Out
到 In
这是否有助于为您指明正确的方向?
时间戳问题
因此,您似乎在进入循环之前初始化了一次时间戳。
尝试移动
ts = time.time()
timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S'
在以下行之后:
id, text = reader.read()
这是否解决了您的问题?
一般风格评论
您可以简化以下内容:
if sign_in == 0:
sign_in = (sign_in + 1) % 2
sign_out = (sign_out + 1) % 2
#id, text = reader.read()
cursor.execute("INSERT INTO attendance (user_id, clock_in) VALUES (%s, %s)", (result[0], timestamp,) )
lcd.lcd_display_string("Sign in " + result[1])
elif sign_in == 1:
sign_out = (sign_out + 1) % 2
sign_in = (sign_in + 1) % 2
#id, text = reader.read()
cursor.execute("INSERT INTO attendance (user_id, clock_out) VALUES (%s, %s)", (result[0], timestamp,) )
lcd.lcd_display_string("Sign out " + result[1])
更像是
sign_in = (sign_in + 1) % 2
sign_out = (sign_out + 1) % 2
#id, text = reader.read()
field_in_or_out = 'in' if sign_in == 1 else 'out'
cursor.execute(f"INSERT INTO attendance (user_id, clock_{field_in_or_out}) VALUES (%s, %s)", (result[0], timestamp,) )
lcd.lcd_display_string(f"Sign {field_in_or_out} " + result[1])
我将如何进一步简化逻辑
#!/usr/bin/env python
import time
import datetime
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
import mysql.connector
import I2C_LCD_driver
db = mysql.connector.connect(
host="localhost",
user="admin",
passwd="*******",
database="attendancesystem"
)
cursor = db.cursor()
reader = SimpleMFRC522()
lcd = I2C_LCD_driver.lcd()
#redLED = 4
#yellowLED = 17
#greenLED = 27
#GPIO.setmode(GPIO.BCM)
signed_in = 0
try:
while True:
lcd.lcd_clear()
lcd.lcd_display_string('Place Card to')
lcd.lcd_display_string('record attendance', 2)
id, text = reader.read()
ts = time.time()
timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
cursor.execute("Select id, name FROM users WHERE rfid_uid="+str(id))
result = cursor.fetchone()
lcd.lcd_clear()
if cursor.rowcount >= 1:
lcd.lcd_display_string("Welcome")
lcd.lcd_display_string(""+ result[1], 2)
#GPIO.output(greenLED,GPIO.HIGH)
#time.sleep(3)
#GPIO.output(greenLED,GPIO.LOW)
cursor.execute("INSERT INTO attendance (user_id) VALUES (%s)", (result[0],) )
signed_in = (signed_in + 1) % 2
#id, text = reader.read()
cursor.execute(f"INSERT INTO attendance (user_id, read_at) VALUES (%s, %s)", (result[0], timestamp,) )
lcd.lcd_display_string(f"Card read " + result[1])
db.commit()
else:
lcd.lcd_display_string("User does not")
lcd.lcd_display_string("exist !!", 2)
#GPIO.output(yellowLED,GPIO.HIGH)
#time.sleep(3)
#GPIO.output(yellowLED,GPIO.LOW)
time.sleep(2)
finally:
GPIO.cleanup()
并更新数据库架构,使其只有一个 user_id
和一个 read_at
时间列用于读取卡片的时间。将您的 sign_in
/sign_out
逻辑更改为只有一个表示两种状态的 signed_in
字段,1 表示用户已登录,0 表示未登录。
代码中的另一个变化是将时间戳逻辑拉入 while
循环。
然后,您预期的数据库将在每次卡片被触及 reader 时记录一行,其中包含事件发生的时间,并且您不必更新已经存在的条目。
我是初学者,我需要一些help/guidance! 所以基本上我正在尝试使用 Raspberry Pi 4 和 RFID reader 和 writer 制作一个考勤系统。到目前为止,一切都运行良好,但我正在为 sign_out 发送数据而苦苦挣扎。现在,sign_in 中的相同时间戳也在数据库中的 signed_out 中标记,但在这里我想在第二次读取 RFID 卡时填充数据sign_out 列。 如果您有任何其他建议,我很乐意 hear/learn,谢谢。 编辑:"the whole code was deleted from this question"
您是否考虑过将 sign-in/sign-out 视为一个开关?默认状态是 sign-in
设置为 0 或 false,sign-out
设置为 1 或 true。然后,当读取卡时,它会检查登录值。如果它是 0/false,它会翻转为 1/true,并进行相反的翻转以注销。第二次读卡时,读取sign-out,如果为0/false,则设置为1/true,与sign-in相反。
为清楚起见:
current state:
sign-in = 0
sign-out = 1
---> card is read for the first time
sign-in = (sign-in + 1) % 2
sign-out = (sign-out + 1) %2
state now:
sign-in = 1
sign-out = 0
---> card is read for the second time, consider previous state
sign-in = (sign-i + 1) % 2
sign-out = (sign-out + 1) % 2
state:
sign-in = 0
sign-out = 1
这可以通过将 2 个状态减少为一个状态来进一步简化,signed-in
。
initial state:
signed-in = 0
---> card is read for entry
signed-in = (signed-in + 1) % 2
state:
signed-in = 1
---> card is read for exit
signed-out = (signed-in + 1) % 2
state:
signed-in = 0
简单地说,您想将其视为具有两个转换的简单状态机:从 In
到 Out
和从 Out
到 In
这是否有助于为您指明正确的方向?
时间戳问题
因此,您似乎在进入循环之前初始化了一次时间戳。 尝试移动
ts = time.time()
timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S'
在以下行之后:
id, text = reader.read()
这是否解决了您的问题?
一般风格评论
您可以简化以下内容:
if sign_in == 0:
sign_in = (sign_in + 1) % 2
sign_out = (sign_out + 1) % 2
#id, text = reader.read()
cursor.execute("INSERT INTO attendance (user_id, clock_in) VALUES (%s, %s)", (result[0], timestamp,) )
lcd.lcd_display_string("Sign in " + result[1])
elif sign_in == 1:
sign_out = (sign_out + 1) % 2
sign_in = (sign_in + 1) % 2
#id, text = reader.read()
cursor.execute("INSERT INTO attendance (user_id, clock_out) VALUES (%s, %s)", (result[0], timestamp,) )
lcd.lcd_display_string("Sign out " + result[1])
更像是
sign_in = (sign_in + 1) % 2
sign_out = (sign_out + 1) % 2
#id, text = reader.read()
field_in_or_out = 'in' if sign_in == 1 else 'out'
cursor.execute(f"INSERT INTO attendance (user_id, clock_{field_in_or_out}) VALUES (%s, %s)", (result[0], timestamp,) )
lcd.lcd_display_string(f"Sign {field_in_or_out} " + result[1])
我将如何进一步简化逻辑
#!/usr/bin/env python
import time
import datetime
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
import mysql.connector
import I2C_LCD_driver
db = mysql.connector.connect(
host="localhost",
user="admin",
passwd="*******",
database="attendancesystem"
)
cursor = db.cursor()
reader = SimpleMFRC522()
lcd = I2C_LCD_driver.lcd()
#redLED = 4
#yellowLED = 17
#greenLED = 27
#GPIO.setmode(GPIO.BCM)
signed_in = 0
try:
while True:
lcd.lcd_clear()
lcd.lcd_display_string('Place Card to')
lcd.lcd_display_string('record attendance', 2)
id, text = reader.read()
ts = time.time()
timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
cursor.execute("Select id, name FROM users WHERE rfid_uid="+str(id))
result = cursor.fetchone()
lcd.lcd_clear()
if cursor.rowcount >= 1:
lcd.lcd_display_string("Welcome")
lcd.lcd_display_string(""+ result[1], 2)
#GPIO.output(greenLED,GPIO.HIGH)
#time.sleep(3)
#GPIO.output(greenLED,GPIO.LOW)
cursor.execute("INSERT INTO attendance (user_id) VALUES (%s)", (result[0],) )
signed_in = (signed_in + 1) % 2
#id, text = reader.read()
cursor.execute(f"INSERT INTO attendance (user_id, read_at) VALUES (%s, %s)", (result[0], timestamp,) )
lcd.lcd_display_string(f"Card read " + result[1])
db.commit()
else:
lcd.lcd_display_string("User does not")
lcd.lcd_display_string("exist !!", 2)
#GPIO.output(yellowLED,GPIO.HIGH)
#time.sleep(3)
#GPIO.output(yellowLED,GPIO.LOW)
time.sleep(2)
finally:
GPIO.cleanup()
并更新数据库架构,使其只有一个 user_id
和一个 read_at
时间列用于读取卡片的时间。将您的 sign_in
/sign_out
逻辑更改为只有一个表示两种状态的 signed_in
字段,1 表示用户已登录,0 表示未登录。
代码中的另一个变化是将时间戳逻辑拉入 while
循环。
然后,您预期的数据库将在每次卡片被触及 reader 时记录一行,其中包含事件发生的时间,并且您不必更新已经存在的条目。