PythonのTkinterとSuica(NFC)で出退勤(その3-打刻画面)

2021年3月22日

こんにちは

今回は打刻の画面(超シンプル)作成します。

前回までの記事は以下の通りです。

1回目:PythonのTkinterとSuica(NFC)で出退勤(その1-イントロダクションとDB)

2回目:PythonのTkinterとSuica(NFC)で出退勤(その2-管理画面)

では画面を作成しましょう

import tkinter
import nfc
import winsound #Windowsオーディオ用
from tkinter import messagebox
import sqlite3
import datetime

class TimecardForWindows(tkinter.Frame):

    def __init__(self,master):
        super().__init__(master)
        self.pack()
        master.title("出退勤")
        master.geometry("800x600")

        # 適当に色を付けてます
        canvas = tkinter.Canvas(master, width=800, height=600, bg="skyblue")
        canvas.place(x=0, y=0)
        
        attendance_button = tkinter.Button(master, text="出勤", height=0, width=10, bg="#f08cc5", font=("Times New Roman", 24), command=self.click_attendance)
        attendance_button.place(x=200, y=250)

        leaveWork_button = tkinter.Button(master, text="退勤", height=0, width=10, bg="#8cf0b1", font=("Times New Roman", 24), command=self.click_leaveWork)
        leaveWork_button.place(x=400, y=250)

        self.dbname = 'database.db'
        self.conn = sqlite3.connect(self.dbname, isolation_level = None)
        # 外部キー制約の使用を有効にする
        self.conn.execute("PRAGMA foreign_keys = 1")

    # 出勤時
    def click_attendance(self):
        
        try:
            clf = nfc.ContactlessFrontend('usb')
            tag = clf.connect(rdwr={'on-connect': lambda tag: False})
            idm = tag.idm.hex()

            dt_now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            self.conn.execute("INSERT INTO timeCard(idm, attendanceTime) VALUES (?, ?)", (idm, dt_now))
            self.conn.commit
            # 出勤時の音(音を出さない場合は以下3行をコメントアウトする)
            with open('hello.wav', 'rb') as f:
                data = f.read()
            winsound.PlaySound(data, winsound.SND_MEMORY)

            # メッセージボックスを表示させる場合はコメントを外す
            # messagebox.showinfo('出勤', 'おはようございます!')
        except sqlite3.IntegrityError:
            messagebox.showerror('登録できません!', 'このNFCは登録されていません!')
        finally:
            self.conn.close
            clf.close()

    # 退勤時
    def click_leaveWork(self):
        try:
            clf = nfc.ContactlessFrontend('usb')
            tag = clf.connect(rdwr={'on-connect': lambda tag: False})
            idm = tag.idm.hex()

            dt_now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            num = self.conn.execute("UPDATE timeCard SET leaveWorkTime=? WHERE idm=?", (dt_now, idm))
            self.conn.commit

            if num.rowcount > 0:
                # 退勤時の音(音を出さない場合は以下3行をコメントアウトする)
                with open('otukare.wav', 'rb') as f:
                    data = f.read()
                winsound.PlaySound(data, winsound.SND_MEMORY)
                # メッセージボックスを表示させる場合はコメントを外す
                # messagebox.showinfo('退勤', 'おつかれさまでした!')
            else:
                # メッセージボックスを表示させる場合はコメントを外す
                messagebox.showerror('更新されていません!', 'NFCが未登録か、出勤を押していません!')
        finally:
            self.conn.close
            clf.close()

def main():
    root = tkinter.Tk()
    root = TimecardForWindows(master=root)
    root.mainloop()

if __name__ == "__main__":
    main()

「出勤」・「退勤」ボタンを押した際に、「hallo.wav」・「otukare.wav」という音声ファイルが流れるようになっています。

私のPCでは「おはようございます」、「おつかれさまでした」と鷹の爪の吉田君の音声ファイルが流れるようにしています。

これは「winsound」というwindowsの機能を使っていますので、WindowsOS以外をお使いの場合は別のサウンドモジュールに差し替えてください。

(Winsoundのまま使用するとエラーになります。)

Raspberry pi(Rasbian)の場合は以下で音が鳴ることを確認しました。

subprocess.call("aplay hello.wav", shell=True)

Windowsの場合はまた、管理者権限のPowerShellで起動してください。

Raspberry pi(Rasbian)の場合はsudoで実行しましょう。

■打刻方法

PaSoRiの上にSuicaを置いて、「出勤」または「退勤」を押す

3秒くらいで「おはようございます」、「おつかれさまでした」が流れます。

意外と反応が遅い…

■出退勤履歴の検索

前回作成した管理画面にて検索ができるようになっております。

次回は登録したnfcや出退勤情報の変更(update)をおこないます。