You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将MFRC522 RFID与Adafruit指纹扫描Python脚本合并?

问题描述

我写了两个Python脚本,分别用于MFRC522 RFID扫描仪和Adafruit 4651指纹扫描仪:

  • RFID脚本负责验证标签ID与数据,通过后执行SSH命令,还支持主标签授权新标签的功能
  • 指纹脚本验证指纹通过后执行相同的SSH命令

现在想把两个脚本合并成一个,让程序自动检测是RFID标签还是指纹被触发。之前试过用指纹扫描仪的感应触发,但不行,因为它会在循环开始时检查状态,之后就一直等标签出现。

硬件信息:

  • RFID模块:普通MFRC522
  • 指纹传感器:Adafruit 4651

以下是原脚本:

原指纹脚本(finger.py)

import time
import board
import adafruit_fingerprint
import serial
import subprocess

uart = serial.Serial("/dev/ttyS0", baudrate=57600, timeout=1)
finger = adafruit_fingerprint.Adafruit_Fingerprint(uart)

def get_fingerprint():
    while finger.get_image() != adafruit_fingerprint.OK:
        pass
    if finger.image_2_tz(1) != adafruit_fingerprint.OK:
        return False
    if finger.finger_search() != adafruit_fingerprint.OK:
        return False
    return True

try:
    finger.set_led(1,4,0,0)
    while True:
        finger.set_led(1,4,0,0)
        if get_fingerprint():
            finger.set_led(2,1,200,0)
            subprocess.call('ssh pi@192.168.2.3 sudo python3 /home/pi/pirfid/actor.py',shell=True)
        else:
            finger.set_led(1,2,10,5)
            time.sleep(1)
            finger.set_led(1,2,10,5)
            time.sleep(1)
            finger.set_led(1,2,10,5)
            time.sleep(1)

except KeyboardInterrupt:
    print("Aborted by User")
    uart.close()
finally:
    uart.close()

原RFID脚本(rfid.py)

from mfrc522 import SimpleMFRC522
from time import sleep
import subprocess
import os
import secrets

#Create object for RFID module
scan = SimpleMFRC522()

#Master Tag present
def masterPresent(file_pathUID,id,file_pathPIN,pin):
        with open(file_pathUID, 'r') as fileUID:
                content = fileUID.readline()
                if str(id) in content:
                        masterID = 1
                else:
                        masterID = 0
        with open(file_pathPIN, 'r') as filePIN:
                content = filePIN.readline()
                pin = pin.strip()
                content = content.strip()
                if pin in content:
                        masterPIN = 1
                else:
                        masterPIN = 0
        if masterID == 1 and masterPIN == 1:
                tagAuth("/home/pi/pi-rfid/known_UID","/home/pi/pi-rfid/known_PIN")
        else:
                pass

#Authorise new Tag
def tagAuth(file_pathUID,file_pathPIN):
        # Read Tag UID and write to file
        print("----------------")
        print("Master Tag detected")
        print("----------------")
        sleep(2)
        print("Place Tag to authorise")
        id,data = scan.read()
        id = str(id)
        pin = data.strip()
        with open(file_pathUID, 'r') as fileUID:
                contentID = fileUID.read()
        with open(file_pathPIN, 'r') as filePIN:
                contentPIN = filePIN.read()
                if id in contentID or pin in contentPIN:
                        print("----------------")
                        print("Tag already in use")
                        print("----------------")
                        sleep(3)

                else:
                        with open (file_pathUID,'a+') as fileUID:
                                fileUID.write("\n")
                                fileUID.write(id)
                                #Create random hex sring and write to tag and file
                                newPIN = secrets.token_hex(16)
                                scan.write(newPIN)
                                with open (file_pathPIN,'a+') as filePIN:
                                        filePIN.write("\n")
                                        filePIN.write(newPIN)
                                print("----------------")
                                print("New Tag sucessfully authorised")
                                print("----------------")
                                sleep (3)

#Search UID in file
def searchUID(file_pathUID,id):
        global idInList
        with open(file_pathUID, 'r') as fileUID:
                content = fileUID.read()
                if id in content:
                        idInList = 1
                else:
                        idInList = 0

#Search PIN in file
def searchPIN(file_pathPIN,pin):
        global pinInList
        with open(file_pathPIN, 'r') as filePIN:
                content = filePIN.read()
                pin = pin.strip()
                if pin in content:
                        pinInList = 1
                else:
                        pinInList = 0

#Unlock over SSH
def unlockSSH():
        subprocess.call('ssh pi@192.168.2.3 sudo python3 /home/pi/pirfid/actor.py',shell=True)

#Check for Access
def checkAccess():
        global pinMatch,idInLiist
        if idInList == 1 and pinInList == 1:
                print("Access granted")
                print("----------------")
                unlockSSH()
        else:
                print("Access denied")
                print("----------------")

#Loop

try:
        while True:
                print("Place your Tag")
                id,data = scan.read()
                printData()
                masterPresent("/home/pi/pi-rfid/known_UID",id,"/home/pi/pi-rfid/known_PIN",data)
                searchUID("/home/pi/pi-rfid/known_UID",str(id))
                searchPIN("/home/pi/pi-rfid/known_PIN",data)
                checkAccess()

except KeyboardInterrupt:
        print("Aborted by User")
        GPIO.cleanup()
finally:
        GPIO.cleanup()
解决方案

核心思路是将两个设备的检测改为非阻塞模式,在主循环中轮流检查RFID和指纹的触发状态,避免某一个设备的阻塞操作导致另一个设备无法响应。

关键改进点

  1. 把指纹检测从阻塞循环改为单次非阻塞检查
  2. 给RFID读取设置短超时,避免卡住主循环
  3. 统一封装重复逻辑(比如SSH解锁命令)
  4. 添加防重复触发的休眠机制

合并后的完整代码

import time
import board
import adafruit_fingerprint
import serial
import subprocess
from mfrc522 import SimpleMFRC522
import secrets
import RPi.GPIO as GPIO

# 初始化指纹传感器(设置短超时实现非阻塞)
uart = serial.Serial("/dev/ttyS0", baudrate=57600, timeout=0.1)
finger = adafruit_fingerprint.Adafruit_Fingerprint(uart)

# 初始化RFID模块
rfid_scanner = SimpleMFRC522()

# 全局变量(兼容原脚本逻辑)
idInList = 0
pinInList = 0

# 统一SSH解锁命令
UNLOCK_CMD = 'ssh pi@192.168.2.3 sudo python3 /home/pi/pirfid/actor.py'

def unlock_via_ssh():
    subprocess.call(UNLOCK_CMD, shell=True)

# -------------------------- 指纹相关函数 --------------------------
def check_fingerprint():
    """非阻塞检查指纹是否匹配"""
    # 单次尝试获取指纹图像,不循环等待
    if finger.get_image() != adafruit_fingerprint.OK:
        return False
    if finger.image_2_tz(1) != adafruit_fingerprint.OK:
        return False
    if finger.finger_search() != adafruit_fingerprint.OK:
        return False
    return True

# -------------------------- RFID相关函数 --------------------------
def masterPresent(file_pathUID, uid, file_pathPIN, pin):
    masterID = 0
    masterPIN = 0
    with open(file_pathUID, 'r') as fileUID:
        content = fileUID.readline()
        if str(uid) in content:
            masterID = 1
    with open(file_pathPIN, 'r') as filePIN:
        content = filePIN.readline().strip()
        pin = pin.strip()
        if pin == content:
            masterPIN = 1
    if masterID == 1 and masterPIN == 1:
        tagAuth(file_pathUID, file_pathPIN)

def tagAuth(file_pathUID, file_pathPIN):
    print("----------------")
    print("检测到主标签")
    print("----------------")
    time.sleep(2)
    print("请放置待授权的标签")
    # 授权流程需要用户配合,这里用阻塞读取
    uid, data = rfid_scanner.read()
    uid_str = str(uid)
    pin = data.strip()
    
    with open(file_pathUID, 'r') as fileUID:
        contentID = fileUID.read()
    with open(file_pathPIN, 'r') as filePIN:
        contentPIN = filePIN.read()
        
    if uid_str in contentID or pin in contentPIN:
        print("----------------")
        print("该标签已被授权")
        print("----------------")
        time.sleep(3)
    else:
        with open(file_pathUID, 'a+') as fileUID:
            fileUID.write("\n")
            fileUID.write(uid_str)
        newPIN = secrets.token_hex(16)
        rfid_scanner.write(newPIN)
        with open(file_pathPIN, 'a+') as filePIN:
            filePIN.write("\n")
            filePIN.write(newPIN)
        print("----------------")
        print("新标签授权成功")
        print("----------------")
        time.sleep(3)

def searchUID(file_pathUID, uid):
    global idInList
    with open(file_pathUID, 'r') as fileUID:
        content = fileUID.read()
        idInList = 1 if str(uid) in content else 0

def searchPIN(file_pathPIN, pin):
    global pinInList
    with open(file_pathPIN, 'r') as filePIN:
        content = filePIN.read()
        pin = pin.strip()
        pinInList = 1 if pin in content else 0

def check_rfid_access(uid, pin):
    searchUID("/home/pi/pi-rfid/known_UID", uid)
    searchPIN("/home/pi/pi-rfid/known_PIN", pin)
    if idInList == 1 and pinInList == 1:
        print("Access granted")
        print("----------------")
        unlock_via_ssh()
    else:
        print("Access denied")
        print("----------------")

# -------------------------- 主循环 --------------------------
try:
    # 初始化指纹LED
    finger.set_led(1,4,0,0)
    print("等待指纹或RFID标签...")
    
    while True:
        # 检查指纹
        if check_fingerprint():
            print("指纹验证通过")
            finger.set_led(2,1,200,0)
            unlock_via_ssh()
            time.sleep(2)  # 防止重复触发
            finger.set_led(1,4,0,0)
        
        # 检查RFID(0.1秒超时,非阻塞)
        start_time = time.time()
        rfid_detected = False
        uid = None
        pin_data = None
        
        while time.time() - start_time < 0.1:
            try:
                uid, pin_data = rfid_scanner.read()
                rfid_detected = True
                break
            except:
                pass
        
        if rfid_detected:
            print(f"检测到RFID标签: UID={uid}, PIN={pin_data.strip()}")
            masterPresent("/home/pi/pi-rfid/known_UID", uid, "/home/pi/pi-rfid/known_PIN", pin_data)
            check_rfid_access(uid, pin_data)
            time.sleep(2)  # 防止重复触发
        
        # 降低CPU占用
        time.sleep(0.05)
        
except KeyboardInterrupt:
    print("用户终止程序")
    uart.close()
    GPIO.cleanup()
finally:
    uart.close()
    GPIO.cleanup()

使用说明

  • 脚本启动后会同时监听指纹和RFID设备,任意一个触发都会执行对应验证逻辑
  • 指纹验证通过或RFID授权成功后,会短暂休眠避免重复触发
  • 若CPU占用过高,可适当延长主循环最后的休眠时间(比如改为0.1秒)

内容的提问来源于stack exchange,提问作者walwei88

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 03:47:08