1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

FelicaのIDmを読み取ってSQLite3で管理する

Posted at

前の記事

この記事の続きになります。

Python3 でFelicaのIDmを読み取って記録する

実現したいこと

入退室管理のようなことをしたいと思っています。

前回FelicaからIDmを読み取ることができたので、今回はFelicaを事前に登録し、タッチを繰り返すことでonlineとofflineを切り替えるようなものを作ります。

##SQLite3を使ってみる

全く知識がなかったので以下の記事を参考にしました。SQLの文法は随時検索して学びました。

【python】データベースの入門としてSQLiteを使ってみた

テーブルを生成する

テーブル名はFelica、カラムは name、 IDm、 time、 statusにしました。型が適当になってしまったのは改善したいと思っています。textで良かったんでしょうか。

import sqlite3

con = sqlite3.connect('./idm_list.db')
c = con.cursor()
# 生成する
sql = """
create table Felica (name varchar(64), IDm varchar(200), time varchar(32), status varchar(32))
"""
c.execute(sql)
con.commit()

レコードを追加する

import sqlite3

con = sqlite3.connect('./idm_list.db')
c = con.cursor()

sql = 'insert into Felica (name, IDm, time, status) values (?,?,?,?)'
user1 = ('tanaka', '01010a10d9243d05', '20:37', 'offline')
user2 = ('suzuki', '012f2d178b4d6f8a', '10:21', 'offline')
c.execute(sql,user1)
c.execute(sql,user2)
con.commit()

テーブルの中身を確認する

import sqlite3
import datetime

# 確認
con = sqlite3.connect('./idm_list.db')
c = con.cursor()
select_sql = 'select * from Felica'
for row in c.execute(select_sql):
    print(row)
con.close()

実装

  • 事前にテーブルを作って、カードのレコードを登録しておく
  • カードをタッチするとstatusとtimeを更新する
  • statusはonline,offline
  • Ctrl-Cで終了するまで待機し続ける
import binascii
import nfc
import signal
import datetime
import sqlite3

class MyCardReader(object):

    def on_connect(self, tag):
        print ("読み取り中")
        self.idm = binascii.hexlify(tag.idm)
        return True

    def read_idm(self):
        clf = nfc.ContactlessFrontend('usb')
        try:
            clf.connect(rdwr = {'on-connect': self.on_connect})
        finally:
            clf.close()


class DatabaseEdit:

    def updatetime(self,idm):
        dt_now = datetime.datetime.now()
        now = dt_now.strftime('%H:%M')
        con = sqlite3.connect('./idm_list.db')
        c = con.cursor()
        # 前回の時間とステータスを取得
        select_sql = "select * from Felica where IDm='%s'" % idm
        for row in c.execute(select_sql):
            lasttime = row[2]
            status = row[3]
            name = row[0]
        print(name + "さん")
        # 前回と時間が同じならステータスを更新
        if (lasttime == now):
            print("タッチ重複のため更新しません")
            con.commit()
        else:
            c.execute("update Felica set time='%s' where IDm='%s'" % (now, idm))
            if status == "offline":
                c.execute("update Felica set status='%s' where IDm='%s'" % ("online", idm))
                print("onlineになりました")
            else:
                c.execute("update Felica set status='%s' where IDm='%s'" % ("offline", idm))
                 print("offlineになりました")
            con.commit()


if __name__ == '__main__':
    cr = MyCardReader()
    de = DatabaseEdit()

    while True:
        print ("カードをタッチしてください")
        cr.read_idm()
        #16進数16桁の文字列にする
        new_idm = str(cr.idm)
        new_idm = new_idm[2:-1]

        # print ("カードのID: ",end='')
        # print (new_idm)

       # 更新
        de.updatetime(new_idm)
        # Ctrl-Cで終了するまで待機し続ける
        signal.signal(signal.SIGINT,signal.SIG_DFL)

実行結果

カードをタッチしてください
読み取り中
tanakaさん
onlineになりました
カードをタッチしてください
読み取り中
suzukiさん
offlineになりました
カードをタッチしてください
読み取り中
suzukiさん
タッチ重複のため更新しません

工夫したこと

連続でタッチしてしまったとき、statusが書き換わってしまいます。そこで、time(12:20などの文字列)が一致しているときは書き換えないようにしました。

課題

  • SQLiteの理解

    もう少しスッキリした書き方ができそう。型はちゃんと見直すつもりです。

  • 連続タッチ回避

    ちょうど1日経ったときや、ちょうど分が変わるときにタッチしてしまうと意図しない結果になります。30秒たったらという処理にしようかと思いましたが面倒でした。より良い方法があれば直したいです。

1
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?