COMPANY SERVICE STAFF BLOG NEWS CONTACT

STAFF BLOG

スタッフブログ

TECHNICAL

テクログ

2020.04.13

【nfcpyでLINE通知】ちょうど目の前にICカードリーダーとNFCチップが転がっていたので

テクログpython

こんにちはじゅんすです。

私は実家暮らしで兄弟がいるのですが、どうも兄が家に帰ってきても手を洗っていないっぽいのです。

時期が時期なのでちゃんと手洗いうがいはしてほしいのですが、、。

こりゃどうしたもんか、、、と思ったその時、

ちょうど目の前にICカードリーダーとNFCチップが転がっていたので「手を洗ったらICカードリーダーにピッてしてLINEのトークルームに通知を送るシステム」を作っちゃいました。

Pythonだと参考資料が多かったのでPythonで開発しました。

触ったことないですけどね、、資料が多かったもんで、。

なのでコードに至らない部分は多くあると思いますがご了承ください。

以下にざっくりと処理の流れを記載しておきます。

  • ICカードリーダーでNFCチップのIDm(固有ID)を取得。
  • 取得したIDmでDBからユーザー名を取得。
  • 「〇〇〇(ユーザー名)は手を洗ったよ」という内容でLINE通知。

開発環境

■各バージョン

  • Windows 10 Home 64-bit
  • Python 3.8.2
  • libusb 1.0.23
  • Zadig 2.5
  • nfcpy 1.0.3
  • MySQL 8.0.19

■DBクライアント

  • MySQL Workbench

■USBドライバ

  • Zadig

■ICカードリーダー

  • 非接触型ICカードリーダー / ライター RC-S380(SONY製)

■NFCチップ

  • NTAG213(NXP製)

下準備

ただICカードリーダー差してコードを書いただけじゃ動かないので以下の準備をしておきます。

■libusbのインストール

公式サイト(https://libusb.info/)からダウンロードできます(私の時はlibusb-1.0.23.7zでした)。

ダウンロードしたファイルを解凍したら以下の操作をします。

  • 64ビット版Windowsの場合
  • MS64dlllibusb-1.0.dllC:WindowsSystem32にコピー
  • MS32dlllibusb-1.0.dllC:WindowsSysWOW64にコピー
  • 32ビット版Windowsの場合
  • MS32dlllibusb-1.0.dllC:WindowsSystem32にコピー

■ドライバの適用

公式サイト(https://zadig.akeo.ie/)からダウンロードできます(私の時はZadig 2.5でした)。

ダウンロードしたらZadigアプリケーションを実行する前にPCにRC-S380を差します。

ドライバが自動適用されたらZadigアプリケーションを実行します。

表示されたウィンドウの上にあるリストボックスからNFC Port/PaSoRi 100 USBを選択します(ない場合はOptions ⇒ List All Devicesで表示されます)。

Driverの項目はWinUSBにします。

Replace Driverをクリックしたら完了です。

■LINE Notify アクセストークンの発行

公式サイト(https://notify-bot.line.me/ja/)にログインして、右上のアカウントからマイページに行きます。

マイページの下部にトークンを発行するがあるのでトークン名の入力と通知したいトークルームを選択して発行します。

※発行されたトークンは1度しか表示されないので注意。

■DBの設定

まずhand_washingという名前でDBを作成します。

CREATE DATABASE hand_washing
 CHARACTER SET utf8
 COLLATE utf8_general_ci;

続いてNFCチップのデータを入れるnfc_tipsと、それを使うユーザーのデータを入れるusersテーブルを作成します。

CREATE TABLE `hand_washing`.`nfc_tips` (
 `id` INT NOT NULL AUTO_INCREMENT,
 `idm` VARCHAR(50) NOT NULL COMMENT "NFCチップの固有ID",
 `user_id` INT NOT NULL COMMENT "NFCチップを使用するユーザーのID",
 `created_at` DATETIME NOT NULL,
 `updated_at` DATETIME NOT NULL,
 PRIMARY KEY (`id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COMMENT = "NFCチップデータ用のテーブル";

CREATE TABLE `hand_washing`.`users` (
 `id` INT NOT NULL AUTO_INCREMENT,
 `name` VARCHAR(10) NOT NULL COMMENT "ユーザー名",
 `created_at` DATETIME NOT NULL,
 `updated_at` DATETIME NOT NULL,
 PRIMARY KEY (`id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COMMENT = "NFCチップを使用するユーザー用テーブル";

テーブル作成も無事終わったらそれぞれのテーブルにデータを登録しておきます。

nfc_tipsのidmには後述するnfc_reader.pyで取得したidmを登録します(ちょっと手間ですが、、登録機能を先に作っといた方がよかったなぁ)。

動作確認

■パッケージのインストール

nfcpyとrequestsをpipでインストールします。

pip install nfcpy
pip install requests

■ファイルの作成

以下3つのファイルを全て同階層に作成します。

DBに接続してNFCチップのIDmからユーザー名を取得する処理を書いたdb_crud.py。

import MySQLdb



# データベース接続
connection = MySQLdb.connect(
 host = "ホスト名もしくはIP",
 user = "ユーザー名",
 passwd = "パスワード",
 db = "hand_washing",
 charset="utf8"
)

# カーソル生成
cursor = connection.cursor()

# NFCのIDmからユーザー名を取得
def getUserNameByIdm(idm):
 cursor.execute("SELECT users.name FROM nfc_tips JOIN users ON nfc_tips.user_id = users.id WHERE idm = "%s"" % idm.decode())

 return cursor.fetchone()[0]

LINEに通知を送る処理を書いたline_notify.py。

import requests



# LINE Notifyの情報
line_notify_token = "アクセストークン"
line_notify_api = "https://notify-api.line.me/api/notify"

# LINEでメッセージを送る
def sendMessage(person):
 message = str(person) + "は手を洗ったよ"

 payload = {"message": message}
 headers = {"Authorization": "Bearer " + line_notify_token}

 # 送信
 requests.post(line_notify_api, data = payload, headers = headers)

NFCチップのデータを読み込む処理を書いたnfc_reader.py。

import nfc
import binascii
import time

# 外部ファイル
import db_crud
import line_notify



# タッチ待ち受けの1サイクル秒
TIME_CYCLE = 2.0

# タッチ待ち受けの反応インターバル秒
TIME_INTERVAL = 2.0

# タッチされてから次の待ち受けを開始するまで無効化する秒
TIME_WAIT = 5


# NFC接続リクエストのための準備
# NXP製のNFCチップのため106A(通信規格TypeA)で設定(Suicaで試したい人は212F)
remoteTarget = nfc.clf.RemoteTarget("106A")

print("カードをかざしてください")

while True:

 # USBに接続されたNFCリーダに接続してインスタンス化
 with nfc.ContactlessFrontend("usb") as clf:

  # タッチ待ち受け開始
  # clf.sense( [リモートターゲット], [検索回数], [検索の間隔] )
  target = clf.sense(remoteTarget, iterations = int(TIME_CYCLE//TIME_INTERVAL) + 1, interval = TIME_INTERVAL)

  while target:

   tag = nfc.tag.activate(clf, target)

   if tag != None:

    #固有のIDmを取り出す
    idm = binascii.hexlify(tag.identifier).upper()

    # ユーザー名取得
    person = db_crud.getUserNameByIdm(idm)

    print("読み込み成功?")
    print("タグ情報:" + str(tag))
    print("IDm:" + idm.decode())
    print("ユーザー名:" + person + "?")
    print("カードをかざしてください")

    # LINEに通知する
    line_notify.sendMessage(person)

   else:

    print("読み込みに失敗しました")

   time.sleep(TIME_WAIT)

   break

各ファイルが用意出来たらターミナルでnfc_reader.pyのある階層までいきます。

以下のコマンドでnfc_reader.pyの処理を実行します。

python nfc_reader.py

すると以下のように表示されるのでNFCチップをICカードリーダーに2秒ほどかざします。

python nfc_reader.py
カードをかざしてください

NFCチップのデータとユーザー名が表示されると同時にLINEに通知が送られます。

python nfc_reader.py
カードをかざしてください

タグ情報:〇〇〇〇〇〇
IDm:〇〇〇〇〇〇
ユーザー名:〇〇〇〇〇〇

カードをかざしてください

とまぁ、こんな感じで通知システムを作ってみたってお話です。

ただ、これだけじゃ手を洗ったふりしてICカードリーダーにピッてする不正行為ができてしまうので、手の汚れをブラックライトで可視化してカメラで読み込む機能等と組み合わせるなどしたほうが良いかなとか思ったり思わなかったりって感じですね、、(Raspberry Piが欲しい)。

皆さんも目の前に転がっていたら色々作ってみてください!

ではでは!

この記事を書いた人

やまじゅん

入社年2018年

出身地東京都

業務内容web制作

特技・趣味サイクリング、読書、料理

テクログに関する記事一覧

TOP