Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
天刷到了一個這樣的短視頻,我尋思我是不是也可以寫一個類似的上課點名程序,想法經不起等待,說寫就寫~
私信小編01即可獲取大量Python學習資源
Tkinter 是 python 內置的 TK GUI 工具集。TK 是 Tcl 語言的原生 GUI 庫。作為 python 的圖形設計工具,它所使用的 Tcl 語言環境已經完全嵌入到了 python 解釋器中。
我們使用Tkinter開發GUI界面。
PIL(Python Image Library)庫是Python語言的第三方庫,需要通過pip工具安裝。安裝PIL庫的方法如下,需要注意,安裝庫的名字是pillow。
PIL庫支持圖像儲存、顯示和處理,他能夠處理幾乎所有圖片格式,可以完成對圖像的縮放、剪裁、疊加以及向圖像添加線條、圖像和文字等操作。
使用PIL中的Image,ImageTk處理、引入一張圖片,可以使用下面代碼安裝一下。
pip install pillow
雙擊打開后,進入軟件主界面,所有功能一目了然。程序會自動識別軟件目錄下的names.txt,將里面的名字導入。
選擇順序點名后,點擊開始,屏幕上就開始滾動出現人名,人名出現的概率是相同的,點擊停止,人名就停止滾動,點名結束。
點擊隨機點名,程序就會進行隨機點名,人名出現的概率是隨機的。
可以自己手動選擇人名單,前提是人名單格式為txt,且每個名字占一行。
用Pyqt5也寫了一個版本,實現邏輯與TK版本相同,界面可能更好看了一些,但是文件大了許多,大家可以在后面總結部分自取。
import random
import re
import time
import threading
from tkinter import *
from tkinter import ttk
from base64 import b64decode
from PIL import Image,ImageTk
from tkinter import messagebox
from tkinter.filedialog import askopenfilename
""""
2021-11-10點名/抽獎程序
主要亮點:
1.兩種模式:
①順序點名
②隨機點名
2.自動識別人名單
3.支持手動導入人名單
4.人名單導入校驗
5.人名顯示位置自動矯正
6.最多顯示五個大字
"""
imgs=['./point_name.png']
class APP:
def __init__(self):
self.root = Tk()
self.running_flag=False #開始標志
self.time_span=0.05 #名字顯示間隔
self.root.title('Point_name-V1.0')
width = 680
height = 350
left = (self.root.winfo_screenwidth() - width) / 2
top = (self.root.winfo_screenheight() - height) / 2
self.root.geometry("%dx%d+%d+%d" % (width, height, left, top))
self.root.resizable(0,0)
self.create_widget()
self.set_widget()
self.place_widget()
self.root.mainloop()
def create_widget(self):
self.label_show_name_var=StringVar()
self.label_show_name=ttk.Label(self.root,textvariable=self.label_show_name_var,font=('Arial', 100,"bold"),foreground = '#1E90FF')
self.btn_start=ttk.Button(self.root,text="開始",)
self.btn_load_names=ttk.Button(self.root,text="手動加載人名單",)
self.lf1=ttk.LabelFrame(self.root,text="點名方式")
self.radioBtn_var=IntVar()
self.radioBtn_var.set(1)
self.radioBtn_sequence=ttk.Radiobutton(self.lf1,text="順序點名",variable=self.radioBtn_var, value=1)
self.radioBtn_random=ttk.Radiobutton(self.lf1,text="隨機點名",variable=self.radioBtn_var, value=2)
self.label_show_name_num=ttk.Label(self.root,font=('Arial', 20),foreground = '#FF7F50')
paned = PanedWindow(self.root)
self.img = imgs
img_=b'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'
the_img = b64decode(img_)#將圖片硬編碼到GUI
paned.image = ImageTk.PhotoImage(data=the_img)
self._img = Label(self.root, image=paned.image,background='black')
def set_widget(self):
default_name_="會是誰?"
self.label_show_name_var.set(default_name_)
self.label_show_name_adjust(default_name_)
self.btn_start.config(command=lambda :self.thread_it(self.start_point_name))
self.btn_load_names.config(command=self.load_names)
init_names=self.load_names_txt("./names.txt")
self.root.protocol('WM_DELETE_WINDOW',self.quit_window)
self.root.bind('<Escape>',self.quit_window)
if init_names:
self.default_names=init_names #1.文件存在但是無內容。2.文件不存在
self.label_show_name_num.config(text=f"一共加載了{len(self.default_names)}個姓名")
else:
self.btn_start.config(state=DISABLED)
self.label_show_name_num.config(text=f"請先手動導入人名單!")
def place_widget(self):
self.lf1.place(x=300,y=160,width=250,height=50)
self.radioBtn_sequence.place(x=20,y=0)
self.radioBtn_random.place(x=150,y=0)
self.btn_start.place(x=300,y=220,width=100,height=30)
self.btn_load_names.place(x=450,y=220,width=100,height=30)
self._img.place(x=90, y=165, height=120, width=180)
self.label_show_name_num.place(x=300,y=260)
def label_show_name_adjust(self,the_name):
if len (the_name)==1:
self.label_show_name.place(x=280, y=10)
elif len(the_name) == 2:
self.label_show_name.place(x=180, y=10)
elif len(the_name) == 3:
self.label_show_name.place(x=120, y=10)
elif len(the_name) == 4:
self.label_show_name.place(x=80, y=10)
else:
self.label_show_name.place(x=0, y=10)
def start_point_name(self):
"""
啟動之前進行判斷,獲取點名模式
:return:
"""
if len(self.default_names)==1:
messagebox.showinfo("提示",'人名單就一個人,不用選了!')
self.label_show_name_var.set(self.default_names[0])
self.label_show_name_adjust(self.default_names[0])
return
if self.btn_start["text"]=="開始":
self.btn_load_names.config(state=DISABLED)
self.running_flag=True
if isinstance(self.default_names,list):
self.btn_start.config(text="就你了")
if self.radioBtn_var.get()==1:
mode="sequence"
elif self.radioBtn_var.get()==2:
mode="random"
else:
pass
self.thread_it(self.point_name_begin(mode))
else:
messagebox.showwarning("警告","請先導入人名單!")
else:
self.running_flag=False
self.btn_load_names.config(state=NORMAL)
self.btn_start.config(text="開始")
def point_name_begin(self,mode):
"""
開始點名,點名主函數
:param mode:
:return:
"""
if mode == "sequence":
if self.running_flag:
self.always_ergodic()
elif mode=="random":
while True:
if self.running_flag:
random_choice_name=random.choice(self.default_names)
self.label_show_name_var.set(random_choice_name)
self.label_show_name_adjust(random_choice_name)
time.sleep(self.time_span)
else:
break
def always_ergodic(self):
"""
一直遍歷此列表,使用死循環會造成線程阻塞
:return:
"""
for i in self.default_names:
if self.running_flag:
self.label_show_name_var.set(i)
self.label_show_name_adjust(i)
time.sleep(self.time_span)
if i==self.default_names[-1]:
self.always_ergodic()
else:
break
def load_names(self):
"""
手動加載txt格式人名單
:return:
"""
filename = askopenfilename(
filetypes = [('文本文件', '.TXT'), ],
title = "選擇一個文本文件",
initialdir="./"
)
if filename:
names=self.load_names_txt(filename)
if names:
self.default_names=names
no_Chinese_name_num=len([n for n in names if not self.load_name_check(n)])
if no_Chinese_name_num==0:
pass
else:
messagebox.showwarning("請注意",f'導入名單有{no_Chinese_name_num}個不是中文名字')
self.label_show_name_num.config(text=f"一共加載了{len(self.default_names)}個姓名")
default_name_ = "會是誰?"
self.label_show_name_var.set(default_name_)
self.label_show_name_adjust(default_name_)
self.btn_start.config(state=NORMAL)
else:
messagebox.showwarning("警告","導入失敗,請檢查!")
def load_names_txt(self,txt_file):
"""
讀取txt格式的人名單
:param txt_file:
:return:
"""
try:
with open(txt_file,'r',encoding="utf-8")as f:
names=[name.strip() for name in f.readlines()]
if len(names)==0:
return False
else:
return names
except:
return False
def load_name_check(self,name):
"""
對txt文本中的人名進行校驗
中文漢字->True
非中文漢字->False
:param name:
:return:
"""
regex = r'[\u4e00-\u9fa5]+'
if re.match(regex,name):
return True
else:
return False
def thread_it(self,func,*args):
t=threading.Thread(target=func,args=args)
t.setDaemon(True)
t.start()
def quit_window(self,*args):
"""
程序退出觸發此函數
:param args:
:return:
"""
ret=messagebox.askyesno('退出','確定要退出?')
if ret:
self.root.destroy()
if __name__ == '__main__':
a=APP()
本次使用Tkinter開發了一款上課點名程序,此程序可以用于點名、抽獎…代碼不到200行,程序簡單又實用,主要有以下六個亮點:
1.兩種模式:
2.自動識別人名單
3.支持手動導入人名單
4.人名單導入校驗
5.人名顯示位置自動矯正
6.最多顯示五個大字
微信小程序考勤簽到管理系統+后臺管理系統》該項目含有源碼、論文等資料、配套開發軟件、軟件安裝教程、項目發布教程等
本系統包含微信小程序做的考勤前臺和Java做的后臺管理系統:
微信小程序——考勤前臺涉及技術:WXML 和 WXSS、JavaScript
Java——考勤后臺涉及技術:
前端使用技術:JSP,HTML5,CSS3、JavaScript、jQuery、bootstrap等
后臺使用技術:Spring、SpringMvc、Mybatis(SSM)等
數據庫:Mysql數據庫
前臺功能介紹:查看并搜索所有的學生信息,查看請假信息、簽到打卡、修改個人信息、登錄、注冊
后臺管理:登錄、請假的增刪改查、請假審核、匯報的增刪改查、簽到的增刪改查、學生的查詢刪除、 用戶的添加刪除修改、角色的添加刪除修改、菜單的添加刪除修改。
系統功能完整,適合作為畢業設計、課程設計、數據庫大作業。
下面是資料信息截圖:
下面是系統運行起來后的一些截圖:
這個Raspberry Pi RFID考勤系統項目中,詳細記錄了如何利用RC522 RFID閱讀器搭建一個考勤打卡系統。
首先,展示如何將這些電路連接到Raspberry Pi的GPIO引腳,還將展示如何測試每個電路,使其正常工作。
然后,引導您完成建立數據庫的所有步驟,還將編寫Python腳本,與數據庫通信,為個人的RFID卡標記考勤。
最后,設置一個簡單的PHP腳本,讓你直觀地看到RFID考勤系統產生的數據。
在本教程中,有相當多的工作要做,但一旦你完成了這個考勤系統,你會非常有成就感。
要完成這個項目,你需要以下設備,點擊鏈接可直達特別優惠購買。
1. 開始時,首先要確保Raspbian安裝的所有東西都是最新的,在Raspberry Pi上運行以下兩個命令。
sudo apt-get update
sudo apt-get upgrade
2. 現在,將安裝接下來幾節要依賴的所有包。
先運行下面的命令安裝build-essential、git、python3-dev、python3-pip和python3-smbus。
sudo apt-get install build-essential git python3-dev python3-pip python3-smbus
1. 首先開始設置16×2的LCD,將快速運行這一切的設置過程。如果你想了解更多的內容,可以查看我的16×2液晶顯示器教程。
開始本教程之前,請確保已經準備好了以下元件。
2. 一旦有了所有所需的零件,就可以觀察下面的圖和步驟開始組裝電路。
如果按照我的指南將LCD連接到Raspberry Pi是一個非常簡單的過程,每個連接的物理引腳號我都標注了出來。
首先,把各種元件與面包板連接起來。
3. 現在開始將液晶顯示器連接到樹莓派上。
RFID考勤系統LCD布線圖
1. 現在電路已經設置好了,讓去測試一下,以確保一切接線正確。
首先,克隆Adafruit CharLCD庫,將利用這個項目。如果顯示板使用的是HD44780控制器,那么它的工作就不會有問題。
要將庫到你的Raspberry Pi上,運行以下命令。
git clone https://github.com/pimylifeup/Adafruit_Python_CharLCD.git
2. 現在將庫克隆到Raspberry Pi上,需要運行安裝腳本。這個腳本將安裝這個庫,這樣任何Python腳本都可以利用它。
運行以下兩個命令移動到新克隆的目錄中,并運行setup.py腳本。
cd ./Adafruit_Python_CharLCD
sudo python3 setup.py install
3. 在Raspberry Pi上安裝好庫后,需要編輯一個示例文件。需要這樣做來測試電路,因為使用的引腳和例子中的不同。
通過運行以下命令開始編輯文件。
nano ~/Adafruit_Python_CharLCD/examples/char_lcd.py
4. 在這個文件中,找到 "# Raspberry Pi引腳配置: "部分,并修改它,使其與我們下面的值一致。
# Raspberry Pi pin configuration:
lcd_rs = 4
lcd_en = 24
lcd_d4 = 23
lcd_d5 = 17
lcd_d6 = 18
lcd_d7 = 22
一旦做了修改,按CTRL + X,然后按Y,再按ENTER鍵保存文件。
5. 現在,在繼續運行新修改的例子之前,需要安裝Raspberry Pi的GPIO Python庫。
要安裝所需的庫,請運行以下命令。
sudo pip3 install RPi.GPIO
6. 為了測試一切是否正常,現在讓我們運行下面的命令來運行那個python腳本。如果一切正常,你現在應該可以看到LCD上顯示的文字。
python3 ~/Adafruit_Python_CharLCD/examples/char_lcd.py
1. 現在已經設置好了16×2的LCD顯示屏,現在將把RFID閱讀器添加到這個電路中。
對于本節RFID RC522的電路布線,需要準備以下設備。
2. 一旦有了RFID電路所需的一切,就可以繼續進行布線了,由于LCD電路已經設置好了,所以會稍微復雜一些。
請注意,這個電路圖是假設您已經按照上一節中的步驟來使用LCD顯示器。如果您沒有利用LCD,請確保您將Raspberry Pi上的物理引腳6連接到面包板上的地軌。
按照下面的圖示和步驟將RFID電路連接到樹莓派上。
RC522 RFID考勤系統接線圖譜
1. 現在RFID已經連接到Raspberry Pi上,需要進入raspi-config工具來啟用SPI接口。這個接口是必需的,這樣就可以和RC522模塊進行通信。
要做到這一點,首先運行以下命令來啟動 raspi-config 工具。
sudo raspi-config
2. 運行該命令后,會看到一個屏幕,顯示了可以配置的各種選項。
目前,我只對激活SPI接口感興趣。如果你想了解更多,可以查看我們的Raspi-Config工具的終極指南。
在這個屏幕上使用方向鍵向下選擇 "5個接口選項",然后按ENTER鍵。
3. 在下一個屏幕上,你要用方向鍵選擇 "P4 SPI "選項,一旦選擇,按ENTER鍵。
4. 現在您需要確認是否要啟用SPI接口。為此,您需要使用方向鍵選擇 "Yes",然后在選擇后按回車鍵。
5. 現在SPI接口應該已經成功啟用,您現在應該看到屏幕上出現 "The SPI interface is enabled "的文字。
現在在SPI接口完全啟用之前,我們需要重新啟動Raspberry Pi。我們可以通過按ENTER鍵再按ESC鍵回到終端來實現。
輸入以下命令重新啟動Raspberry Pi。
sudo reboot
6. 一旦Raspberry Pi完成重啟,您可以通過運行以下命令來驗證SPI接口是否已經啟用。
該命令將檢索已啟用的內核模塊列表,并從該列表中抓取任何包含 "spi "文字的模塊。
lsmod | grep spi
如果你看到命令行中出現了 "spi_bcm2835 "的文字,那么你現在就可以繼續測試電路是否正常工作了。完成后,我們就可以設置我們的RFID供電考勤系統了。
如果沒有出現,那么我們建議您查看我們的RFID RC522設置指南,了解其他啟用正確內核模塊的方法。
1. 現在使用下面的 "pip "命令將spidev庫安裝到Raspberry Pi上。
依靠spidev庫與RFID閱讀器接口進行交互。
sudo pip3 install spidev
2. 現在已經將spidev庫安裝到Raspberry Pi上,需要使用 "pip "命令來下載MFRC522庫。
這個庫將處理我們的RFID考勤系統的繁瑣工作。
sudo pip3 install mfrc522
3. 現在我們已經將MFRC522庫和spidev庫安裝到了Raspberry Pi上,讓我們繼續制作一個目錄來保存我們的測試腳本。
mkdir ~/pi-rfid
4. 現在我們需要寫一個簡短的腳本來測試我們的RC522是否真的能夠讀取RFID卡,以及所有的東西是否都正確地連接。
首先,讓我們通過運行下面的命令來打開我們的新腳本,這將在我們最近創建的目錄中創建一個名為 "read.py "的文件。
nano ~/pi-rfid/read.py
5. 在這個文件中輸入以下幾行代碼。如果你想了解這里的所有內容,那么我們建議查看我們關于RFID RC522的完整指南。
#!/usr/bin/env python
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
reader = SimpleMFRC522()
try:
id, text = reader.read()
print(id)
print(text)
finally:
GPIO.cleanup()
完成后,按CTRL + X然后按Y和ENTER鍵保存文件。
6. 現在,通過運行以下腳本,并在閱讀器上點擊您的RFID芯片來測試RFID RC522。
python3 ~/pi-rfid/read.py
1. 現在設置了兩個電路,仔細檢查一切都在正常工作。通過運行我們在前面幾節中快速整理的測試腳本進行測試。
如果您有問題,您可以將您的最終電路與下面的圖表進行比較。這些圖是為了讓您了解最終的電路應該是怎樣的。
RFID考勤系統電路原理圖
RFID考勤系統GPIO引腳的使用情況
1. 現在,在對RFID考勤系統進行編程之前,必須首先準備和建立MYSQL數據庫。這個數據庫是我們記錄每張RFID卡考勤情況以及誰擁有該RFID卡的地方。
您可以通過我們的MySQL教程和PHPMyAdmin指南來深入了解MYSQL的設置。我們的RFID考勤系統將引導您完成大部分的基礎知識,但額外的指南將教您如何設置有用的工具,如PHPMyAdmin。
首先,通過在Pi上運行以下命令將MYSQL安裝到Raspberry Pi上。
sudo apt-get install mysql-server -y
2. 接下來,我們需要運行MYSQL自帶的 "安全安裝 "腳本。這個腳本將通過一些程序運行,讓你的MYSQL服務器更加安全。
在Raspberry Pi的終端中運行以下命令來運行這個腳本。
sudo mysql_secure_installation
當出現提示時,請確保你為MYSQL服務器根目錄設置了一個新的密碼。此外,你應該對大多數提示回答 "y",比如禁止root登錄訪問你的MYSQL服務器。
3. 現在讓我們通過運行下面的命令加載到MYSQL命令行工具中。系統會提示你輸入上一步設置的密碼。
由于MariaDB在安裝時默認使用UNIX_SOCKET作為認證方式,所以我們需要使用超級用戶登錄,使用sudo來完成。
sudo mysql -u root -p
4. 讓我們先建立一個數據庫,我們將在這里存儲所有數據,我們的RFID考勤系統將利用這些數據。
我們將把這個數據庫命名為" attendancesystem"。要創建這個數據庫,請運行以下命令。
CREATE DATABASE attendancesystem;
5. 我們創建了數據庫,現在讓我們創建一個名為 "考勤管理員 "的用戶,我們將在Python腳本中利用這個用戶從我們新創建的數據庫中讀取數據。
確保你設置的密碼是獨特的和難以猜測的。在我們的例子中,我們將使用 "pimylifeup "作為密碼。
CREATE USER 'attendanceadmin'@'localhost' IDENTIFIED BY 'pimylifeup';
6. 現在我們已經創建了我們的用戶,我們需要給它訪問 "考勤系統 "數據庫的權限。
我們可以通過運行以下命令來實現。這條命令將賦予我們的 "考勤管理員 "用戶在數據庫中任何表上的全部權限。
GRANT ALL PRIVILEGES ON attendancesystem.* TO 'attendanceadmin'@'localhost';
7. 在創建表之前,我們需要利用 "使用 "命令,這樣我們就可以直接與 "endanceystem "數據庫進行交互。
通過運行以下命令開始與數據庫進行交互。
use attendancesystem;
8. 現在我們直接與我們想要利用的數據庫打交道,我們現在可以開始創建存儲所有數據的表。
運行下面的兩個命令將創建我們將依賴的表來存儲數據。我們將在創建完這些表后解釋這些表的字段。
create table attendance(
id INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
user_id INT UNSIGNED NOT NULL,
clock_in TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ( id )
);
create table users(
id INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
rfid_uid VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ( id )
);
可以輸入exit離開MYSQL工具
現在已經創建了表,來看看將存儲的數據,以及如何在我們的腳本中使用它們。
對于考勤表,我們對每一個記錄的RFID tap都持有三條數據。
對于用戶表,我們為每一個添加的用戶保留四條數據。
1. 在開始編寫考勤系統腳本之前,我們首先需要用pip安裝Python "MYSQL連接器"。
在您的Pi上運行以下命令來安裝連接器庫。
sudo pip3 install mysql-connector-python
2. 現在讓我們創建一個文件夾來保存這個項目的所有內容。
mkdir ~/attendancesystem
3. 是時候開始為我們的考勤系統編寫第一個Python腳本了。這第一個腳本將允許你基于一個拍打的RFID卡來創建一個用戶。
點開RFID卡后,Python腳本會要求你輸入一個用戶名,將此卡注冊給一個人。
運行以下命令,開始編寫我們考勤系統的第一部分。
nano ~/attendancesystem/save_user.py
4. 在這個新文件中寫下以下幾行代碼。我們將解釋每段代碼的作用,以及為什么我們要利用這些代碼。
#!/usr/bin/env python
我們添加這一行是為了讓操作系統知道這個文件應該使用Python來執行。
import time
我們導入時間庫,這樣就可以讓腳本進入睡眠狀態,所以事情不會瞬間發生。
import RPi.GPIO as GPIO
我們需要GPIO庫,這樣我們就可以在腳本結束時運行清理功能。
from mfrc522 import SimpleMFRC522
SimpleMFRC522庫用于使其與我們的RFID閱讀器輕松對話。
import mysql.connector
我們利用MySQL連接器,這樣我們就可以和前面設置的數據庫對話。
import Adafruit_CharLCD as LCD
最后,我們載入Adafruit與LCD對話的庫。這個庫大大簡化了我們與16×2顯示器的通信過程。
db = mysql.connector.connect(
host="localhost",
user="attendanceadmin",
passwd="pimylifeup",
database="attendancesystem"
)
在這部分代碼中,我們創建了與MYSQL服務器的連接。在這個函數中,我們傳遞了建立連接所需的所有信息,如主機、用戶、數據庫名稱和密碼。
連接器創建的對象存儲在db變量中,這樣我們就可以方便地與數據庫進行交互。
在輸入該代碼時,請確保將密碼替換為本指南前面為 "考勤管理員 "SQL用戶設置的密碼。
cursor = db.cursor()
在這里,我們從數據庫連接中實例化一個游標對象的副本。我們利用這個對象與數據庫進行交互,并執行SQL查詢。
reader = SimpleMFRC522()
現在我們準備SimpleMFRC522庫,將它實例化到我們的閱讀器對象中。這個庫將允許我們在稍后的腳本中輕松地與RC522對話,以讀取來自閱讀器的輸入。
lcd = LCD.Adafruit_CharLCD(4, 24, 23, 17, 18, 22, 16, 2, 4);
我們最后的設置行,這一行為CharLCD庫準備處理16×2的顯示器。在這個函數中,我們輸入了所有需要的引腳數,行數等。
try:
while True:
lcd.clear()
lcd.message('Place Card to\nregister')
id, text = reader.read()
這塊代碼是我們用戶創建邏輯的開始。我們將先用try:語句將整個邏輯包裝起來,我們將在后面的指南中解釋為什么。
我們還將我們的邏輯包裹在一個while True循環中。這個循環將確保下面的代碼會無限期地運行,這樣最終用戶就可以連續注冊多個用戶。
接下來,在屏幕上寫下 "Place card to register"(放卡注冊)之前,我們要清除每一個循環的LCD,以確保我們處理的是一個干凈的顯示器。這段文字提示用戶將他們的RFID卡放在閱讀器上。
最后,我們利用SimpleMFRC522庫來讀取閱讀器的輸入。這個函數會等到用戶將他們的RFID讀寫器放置好后才返回卡的id和存儲在卡上的文本。
cursor.execute("SELECT id FROM users WHERE rfid_uid="+str(id))
cursor.fetchone()
在本節中,我們使用游標來執行第一條SQL語句。在這條SQL語句中,我們只是簡單的搜索 "用戶 "表,看看是否有任何行的RFID UID與我們讀取RFID卡時的ID相匹配。
為了抓取我們檢索到的數據,我們利用游標對象的另一個函數,特別是fetchone()函數。這個函數將從返回的結果中抓取一條記錄。
if cursor.rowcount >= 1:
lcd.clear()
lcd.message("Overwrite\nexisting user?")
overwrite = input("Overwite (Y/N)? ")
if overwrite[0] == 'Y' or overwrite[0] == 'y':
lcd.clear()
lcd.message("Overwriting user.")
time.sleep(1)
sql_insert = "UPDATE users SET name = %s WHERE rfid_uid=%s"
else:
continue;
else:
sql_insert = "INSERT INTO users (name, rfid_uid) VALUES (%s, %s)"
在本節中,我們首先檢查上次SQL調用返回了多少條記錄。
如果SQL調用返回任何行,我們需要提示用戶是否要覆蓋已經存在的用戶。
在if語句里面,我們繼續清除LCD屏幕,并顯示 "覆蓋現有用戶?"的信息,并在命令行中提供一個提示,讓用戶回復Y來覆蓋或其他任何東西來取消。
當輸入函數收到輸入后,我們再檢查返回數據的第一個字符是否等于'Y'或'y'。
如果第一個字符與我們預期的相同,我們就再次清除LCD。接下來,我們會顯示 "覆蓋用戶 "的信息一秒鐘。
最后,我們建立SQL查詢,用我們在下一步指定的新名稱更新現有條目。我們做這個過程,而不是刪除舊條目并重新添加。
如果用戶除了 "Y "和 "y "之外,對輸入函數沒有任何反應,我們就使用 "continue "跳回循環的開始。
如果這不是一個重復的條目,我們建立一個不同的SQL查詢,在 "用戶 "表中創建一個新條目。這個新條目將包含我們在下一個代碼塊中指定的新名稱和用戶拍卡時獲得的RFID ID。
lcd.clear()
lcd.message('Enter new name')
new_name = input("Name: ")
cursor.execute(sql_insert, (new_name, id))
db.commit()
lcd.clear()
lcd.message("User " + new_name + "\nSaved")
time.sleep(2)
finally:
GPIO.cleanup()
我們的最后一段代碼很簡單,把所有的事情都包了下來。我們首先再次清除LCD,并在LCD上提示用戶需要輸入一個新的名字。
同時在控制臺上,應出現文字 "Name: "應該會出現,因為我們利用輸入來等待用戶的輸入。
當用戶在控制臺中輸入一個名字并按下回車鍵后,我們就開始利用游標對象來執行我們在上一節代碼中形成的查詢。
我們還創建了一個元組,傳遞給執行函數。這個元組包含新的名稱和RFID卡的id。這兩個值將在執行時自動傳遞到我們的查詢字符串中。
最后,我們通過調用db對象的.commit()函數將更改提交到數據庫中。如果我們不調用這個函數,我們的INSERT和UPDATE查詢將不會發生。
我們通過再次清除LCD并顯示新用戶已保存的消息來結束我們的主代碼邏輯。在重啟循環之前,我們快速運行2秒的睡眠,讓用戶有足夠的時間看到信息。
最后,我們有我們的 finally:語句,這是我們 try:語句的另一部分。這段代碼確保無論發生什么事情,我們都會運行GPIO.cleanup函數。例如,如果我們在腳本運行時按CTRL + C,它應該仍然會清理GPIO狀態。
6. 希望此時,你已經完成了將腳本寫進文件的工作。
然而,如果你想檢查并確保一切正確,那么你可以在下面找到完整版本的代碼。
一旦你對一切都滿意,按CTRL + X然后Y,最后按ENTER鍵保存文件。
#!/usr/bin/env python
import time
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
import mysql.connector
import Adafruit_CharLCD as LCD
db = mysql.connector.connect(
host="localhost",
user="attendanceadmin",
passwd="pimylifeup",
database="attendancesystem"
)
cursor = db.cursor()
reader = SimpleMFRC522()
lcd = LCD.Adafruit_CharLCD(4, 24, 23, 17, 18, 22, 16, 2, 4);
try:
while True:
lcd.clear()
lcd.message('Place Card to\nregister')
id, text = reader.read()
cursor.execute("SELECT id FROM users WHERE rfid_uid="+str(id))
cursor.fetchone()
if cursor.rowcount >= 1:
lcd.clear()
lcd.message("Overwrite\nexisting user?")
overwrite = input("Overwite (Y/N)? ")
if overwrite[0] == 'Y' or overwrite[0] == 'y':
lcd.clear()
lcd.message("Overwriting user.")
time.sleep(1)
sql_insert = "UPDATE users SET name = %s WHERE rfid_uid=%s"
else:
continue;
else:
sql_insert = "INSERT INTO users (name, rfid_uid) VALUES (%s, %s)"
lcd.clear()
lcd.message('Enter new name')
new_name = input("Name: ")
cursor.execute(sql_insert, (new_name, id))
db.commit()
lcd.clear()
lcd.message("User " + new_name + "\nSaved")
time.sleep(2)
finally:
GPIO.cleanup()
7. 保存了save_user腳本后,讓我們先來轉一轉,以確保一切操作正常,不會因為復制代碼而出現錯誤。
運行以下命令來運行該腳本。
python3 ~/attendancesystem/save_user.py
8. 輕點你的RFID卡,看看一切是否正常工作,如果不是,請仔細檢查你的代碼和布線。如果你看到 "User Saved",那么一切都應該正常工作。
1. 現在已經寫好了save_user腳本,并確保它能正常工作,來看看的check_attendance腳本。
這個腳本將無限循環運行,檢查是否有RFID芯片被點擊。當有人敲擊他們的RFID芯片時,我們將在數據庫中檢查該芯片的ID。
如果它找到了一個用戶,我們就設置一個歡迎信息,并在考勤表中插入一個有當前日期和時間的條目。
讓我們使用下面的命令開始編寫腳本的過程。
nano ~/attendancesystem/check_attendance.py
2. 輸入以下幾行代碼。我們將對每一段新的代碼進行解釋,你會熟悉其中的一些代碼,因為我們在上一節的保存用戶腳本中使用了它。
#!/usr/bin/env python
import time
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
import mysql.connector
import Adafruit_CharLCD as LCD
db = mysql.connector.connect(
host="localhost",
user="attendanceadmin",
passwd="pimylifeup",
database="attendancesystem"
)
cursor = db.cursor()
reader = SimpleMFRC522()
lcd = LCD.Adafruit_CharLCD(4, 24, 23, 17, 18, 22, 16, 2, 4);
try:
while True:
我們就不多說這段代碼了,因為這段代碼都是重用了我們在這個Raspberry Pi RFID考勤系統教程上一節寫的第一個save_user.py腳本。
最主要的是,你需要記住的是替換 "passwd "旁邊指定的數據庫密碼,因為默認是我們的例子密碼 "pimylifeup"。
lcd.clear()
lcd.message('Place Card to\nrecord attendance')
id, text = reader.read()
在這段代碼中,我們清除LCD屏幕,并顯示一條信息,提示用戶放卡記錄考勤。然后我們等待RFID閱讀器的響應。
cursor.execute("SELECT id, name FROM users WHERE rfid_uid="+str(id))
result = cursor.fetchone()
lcd.clear()
在這里,我們執行第一條SQL語句。這條SQL語句從 "用戶 "表中抓取 "id "和 "name",其中用戶的RFID ID與讀卡器上的卡相同。
然后我們抓取SQL查詢返回的記錄,并將其結果存儲到我們的 "結果 "變量中供以后使用。
最后,我們清除LCD屏幕,這樣就可以在下一節代碼中打印新的信息了。
cursor.execute("SELECT id, name FROM users WHERE rfid_uid="+str(id))
result = cursor.fetchone()
lcd.clear()
在本節中,我們首先檢查上次的SQL請求是否返回了任何行。如果返回0,那么我們就在16×2的顯示屏上顯示一條 "用戶不存在 "的消息。
如果我們確實有一條記錄,我們就會顯示一條歡迎用戶的消息。我們使用從數據庫中檢索到的用戶名稱作為結果[1]。
之后,我們做一條SQL語句,在考勤表中插入一條記錄。我們需要傳入我們從之前的SQL調用中獲取的用戶ID,并存儲在result[0]中。
最后,我們提交對數據庫的修改。
time.sleep(2)
finally:
GPIO.cleanup()
我們的最后一段代碼很簡單。我們讓腳本休眠兩秒,讓用戶有時間閱讀我們在16×2顯示屏上顯示的信息,并取出RFID卡。
"finally: "語句確保我們在腳本完成后清理GPIO。
3. 輸入完所有代碼后,你可以對照下面的完整版進行檢查。
在輸入所有代碼的時候,主要是要注意保證所有的縮進都是一樣的。每層之間要有兩個空格隔開。
一旦設置完成后,按CTRL + X,然后按Y,最后按ENTER鍵保存文件。
#!/usr/bin/env python
import time
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
import mysql.connector
import Adafruit_CharLCD as LCD
db = mysql.connector.connect(
host="localhost",
user="attendanceadmin",
passwd="pimylifeup",
database="attendancesystem"
)
cursor = db.cursor()
reader = SimpleMFRC522()
lcd = LCD.Adafruit_CharLCD(4, 24, 23, 17, 18, 22, 16, 2, 4);
try:
while True:
lcd.clear()
lcd.message('Place Card to\nrecord attendance')
id, text = reader.read()
cursor.execute("Select id, name FROM users WHERE rfid_uid="+str(id))
result = cursor.fetchone()
lcd.clear()
if cursor.rowcount >= 1:
lcd.message("Welcome " + result[1])
cursor.execute("INSERT INTO attendance (user_id) VALUES (%s)", (result[0],) )
db.commit()
else:
lcd.message("User does not exist.")
time.sleep(2)
finally:
GPIO.cleanup()
4. 保存好腳本后,繼續運行它,檢查一切是否正常。
輸入以下命令運行腳本,并按照16×2顯示屏上顯示的提示操作。
python3 ~/attendancesystem/check_attendance.py
如果你遇到任何錯誤,請確保你仔細檢查所有的代碼已經正確輸入。
1. 現在已經寫好并測試了保存用戶腳本和檢查考勤腳本,來看看數據庫,看看新的條目。
通過運行以下命令啟動MYSQL命令行工具。在繼續之前,你會被提示輸入你為root用戶輸入的密碼。
由于MariaDB默認使用UNIX_SOCKET進行身份驗證,所以我們利用sudo來執行這個命令。
sudo mysql -u root -p
2. 一旦你連接到MYSQL命令行,我們需要利用 "使用 "命令。我們需要使用這個命令,這樣我們就可以和我們的 "考勤系統 "數據庫進行交互。
運行以下命令與 "endanceystem "數據庫進行交互。
use attendancesystem;
3. 現在我們直接與我們的 "考勤系統 "數據庫進行交互,讓我們開始檢查我們的腳本所創建的所有用戶。
我們可以通過運行一個簡單的SELECT SQL調用,指定我們的 "用戶 "表來實現。下面的查詢中使用的星號(*)表示我們要抓取所有的列。
鍵入以下命令來抓取 "用戶 "表中的所有可用用戶。
SELECT * FROM users;
從這個命令中,你應該看到類似于我們下面的東西。
+--+------------------+---------+------------------------+
| id | rfid_uid | name | created |
+--+------------------+---------+------------------------+
| 1 | 160747764001 | Emmet | 2019-01-31 11:28:04 |
+--+------------------+---------+------------------------+
4. 現在我們已經檢查了 "用戶 "表,讓我們繼續看看 "考勤 "表。就像之前的查詢一樣,我們只是選擇 "考勤 "表中的所有列。
輸入以下命令來抓取所有數據。
SELECT * FROM attendance;
從這個命令中,你應該可以看到類似下面的命令行。你可以將 "user_id "引用到 "user "表 "id "中,查看哪個用戶打卡了。
+----+---------+---------------------+
| id | user_id | clock_in |
+----+---------+---------------------+
| 6 | 1 | 2019-02-01 03:23:30 |
| 7 | 1 | 2019-02-01 03:35:36 |
| 8 | 1 | 2019-02-01 03:36:51 |
+----+---------+---------------------+
你可以通過輸入exit離開MYSQL工具。
1. 在開始本節之前,我們要求你已經設置好了NGINX與PHP一起使用。你可以按照我們的Raspberry Pi NGINX指南來了解如何做到這一點。
當你把NGINX和PHP運行起來之后,我們現在就可以開始給我們的考勤系統寫一點前端了。這個前端是為了讓你可以直觀的看到當前用戶的情況,以及他們什么時候點了閱讀器。
首先在默認的NGINX文件夾中建立一個目錄來保存我們的腳本。
sudo mkdir /var/www/html/attendance
2. 你應該已經在Raspberry Pi上安裝了GIT,所以現在是時候將我們的前端腳本克隆到第一步創建的文件夾中了。
通過運行以下命令從我們的GitHub倉庫中克隆代碼。該命令將使用git將代碼克隆到考勤文件夾中。
sudo git clone https://github.com/pimylifeup/attendance-system-frontend.git /var/www/html/attendance
3. 現在腳本已經克隆好了,我們需要對 "common.php "文件做一個修改,這樣我們就可以利用你在本指南中設置的數據庫登錄。
通過運行以下一行開始修改腳本。
sudo nano /var/www/html/attendance/common.php
4. 在這個腳本中,找到下面的部分,并確保用你自己的密碼代替。
找。
'password' => 'pimylifeup'
一旦你改變了這一行,按CTRL + X然后按Y和ENTER鍵保存文件。
5. 對于我們的前端腳本,我們利用 "Medoo "和 "bootstrap"。Medoo是一個處理數據庫的輕量級框架,比如我們為考勤系統建立的數據庫。
另一方面,Bootstrap是一個前端框架,它可以讓你更容易地開發出外觀簡潔的前端,而不用擔心編寫大量的CSS。
現在腳本已經被克隆到了目錄中,你現在應該可以通過訪問你的樹莓派的IP地址并在URL的結尾添加/attendance來檢查前端,如下所示。
http://192.168.160/attendance
6. 進入網站后,你會看到下面的網頁,從這里你可以通過點擊 "用戶 "查看當前的用戶,也可以通過點擊 "考勤 "按鈕查看用戶的考勤情況。
如果你已經走到了這一步,那么所有的工作都是應該的,你現在應該有一個基本的RFID和樹莓皮驅動的考勤系統了。
歡迎頁
考勤系統用戶頁
考勤頁
整體系統比較基本,但涵蓋了一個好的考勤系統所需要的一切。您可以進一步擴展后端和前端,實現新的功能,更好的用戶界面等等。
我希望到現在,你已經擁有一個完整的工作的Raspberry Pi RFID考勤系統。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。