WindowsでNFCタグを扱うには? (nfcpy FeliCa)【Python3.x系対応】
概要
PythonでNFCタグを読み書きするためにnfcpyというライブラリを使う手法がよく使われているようです。この記事では、Windowsでnfcpyを扱うために行う手順とタイムアウト処理について説明します。
nfcpyに関する記事は多く見つかりますが、Windowsでnfcpyを扱うための手順がまとめられている日本語のものは少なく、不要なライブラリをインストールしている場合もあります。そこで、シンプルにまとめたものを作成します。
また、番外編としてNFCタグの読み込みにタイムアウト処理を実装することで、他のイベントと柔軟に組み合わすことができるようにします。
(追記)
nfcpy が Python3.x 系に対応しました。ドライバの導入等は本記事の内容で可能ですが、タイムアウト処理については次の記事をご覧ください。
Python3でnfcpyのタイムアウト処理を扱う (Windows対応)
環境
- Windows10 64bit
- Python 2.7.16 -> 3.7.3
- nfcpy 0.13.5 -> 1.0.3
- PaSoRi RC-S380
Windows環境でnfcpyを扱う
nfcpyは現在Python2系でのみ動作するライブラリです。そのため、Python2.7環境を構築する必要があります。Python installerを利用する方法とAnacondaを利用する方法がありますが、今回はPython installerを利用します。
- Python2.7パッケージのダウンロード
公式サイトを参考にPython 2.7 パッケージをインストールします。インストール途中の設定を変更することで、環境変数を設定できます。なお、同サイト内でMicrosoft Visual C++ Compiler for Python 2.7 をインストールする案内がありますが、今回は必要ありません。
NFCPyのインストール
公式ドキュメントは https://nfcpy.readthedocs.io/en/latest/topics/get-started.html にあります。(以降のWindowsでnfcpyを使う説明は公式ドキュメントと同じです。)コマンドプロンプトを起動し、Pythonのパッケージ管理ツールであるpipでnfcpyをインストールします。ちなみに公式名称はNFCPyとなっていました。
> pip install nfcpy
libusbのインストール
- WinUSBの設定
こちら(http://zadig.akeo.ie/) からZadigをダウンロードし、実行します。
NFCリーダーをPCに接続後、Options > List All Devicesをクリックすることでプルダウンにデバイス一覧が表示されます。
なお、NFCリーダーはこの後で行う Zadig でドライバをインストールした USBポート以外では動作しないため、ご注意ください。別ポートで動作させるためには、都度 「Replace Driver」 の操作が必要です。
表示されたデバイスからNFCリーダーを選択します。そして、矢印の右側にある青枠の切り替え部分が WinUSB になっていることを確認して「Replace Driver」を押します。 「Replace Driver」をクリックすると数秒固まったのちインストールが開始します。
「The driver was Installed successfully.」とダイアログが出ると成功です。
- libusbの設定
こちらからDownload > Latest Windows Binaries をクリックして libusb をダウンロードします。今回は、「libusb-1.0.22.7z」がダウンロードされました。7z形式で圧縮されているので、7zipなどのソフトを使って解凍します。
使用しているWindowsが32bitの場合
- MS32dlllibusb-1.0.dll を c:WindowsSystem32 にコピー
使用しているWindowsが64bitの場合
- MS64dlllibusb-1.0.dll を c:WindowsSystem32 にコピー
- MS32dlllibusb-1.0.dll を c:WindowsSysWowtem64 にコピー
64bit版の場合、うっかり32bit用のdllデータを System32 にコピーしないように注意してください。なお、今回の内容は32bit版の libusb-1.0.dll を SysWowtem64 にコピーせずとも動作しました。
ここまで一通り行うことで、デバイスマネージャーでNFCリーダーの存在が確認できるようになります。
- テストプログラムの実行
早速構築した環境で動作テストしてみます。ここでは、nfcReader.pyとしてファイルを保存しています。
テストコード
# coding:utf-8
import nfc
import binascii
clf = nfc.ContactlessFrontend('usb')
print('touch card:')
try:
tag = clf.connect(rdwr={'on-connect': lambda tag: False})
finally:
clf.close()
idm = binascii.hexlify(tag.idm)
print(idm)
print('please released card')
それでは、サンプルコードを実行してNFCタグをかざしてみます。
> python nfcReader.py
touch card:
1234567890abcdef
please released card
実行するとNFCタグがかざされるまで待機し、かざすとタグのIDmが表示されます。
プログラム内容としては、まず nfc.ContactlessFrontend(‘usb’) でUSB接続のNFCリーダーと接続し、通信できるようにします。次に clf.connect でタグの情報を読み取り、binascii.hexlify(tag.idm) でタグに含まれるIDm情報を抜き出しています。
*実行時に下記のエラーが出る場合は、ZadigでNFCリーダーのドライバーを置き換える部分が失敗している可能性があります。
(略) raise __STATUS_TO_EXCEPTION_DICT.get(value, __USBError)(value)
usb1.USBErrorNotSupported: LIBUSB_ERROR_NOT_SUPPORTED [-12]
(番外編)タイムアウト処理を実装する
NFCタグからIDmを読み込むことができるようになりましたが、コードを実行するとNFCタグがかざされるまで常に待機するため、その後の処理ができません。
そこで、読み込みを待機する時間を制限するタイムアウト処理を実装することで他のイベントとの組み合わせの幅を広げます。例えばパスワード入力直後のみカードタッチを受け付けることが可能です。また、原理上python2系のコードを読み取り部分のみで限定して使うこともできます。
ただし、下記内容はコマンドライン実行とsubprocessによる例外処理を使ったアンチパターンの実装であることに注意してください。より良い書き方を募集中です。
subprocessモジュールのインストール
下記 公式ドキュメント の案内に従って、subprocess32モジュールをインストールします。
POSIX (Linux, BSD など) ユーザは Python 2.7 にバンドルされているバージョンよりも遥かに新しい subprocess32 モジュールをインストールして使うことを強くお勧めします。これは多くの状況においてより良い振る舞いをする差し替えです。
pip install subprocess32
次に、先ほど作成した nfcReader.py と同じディレクトリに以下コードを保存します。
# coding: utf-8
import subprocess32 as subprocess
try:
subprocess.check_call(['python', 'nfcReader.py'], timeout = 3)
except subprocess.TimeoutExpired:
print('** TIME out **')
timeout = 3
の部分で時間[秒]を指定してコマンドライン実行を行い、指定秒を超えた場合に発生する例外 TimeoutExpired
によってNFC読み込み処理を強引に抜ける仕組みとなっています。