如何让系统实现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

简单地说,您想将其视为具有两个转换的简单状态机:从 InOut 和从 OutIn

这是否有助于为您指明正确的方向?

时间戳问题

因此,您似乎在进入循环之前初始化了一次时间戳。 尝试移动

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 时记录一行,其中包含事件发生的时间,并且您不必更新已经存在的条目。