WindowsでNFCタグを扱うには? (Windows nfcpy FeliCa)【8/5 更新】

概要

PythonでNFCタグを読み書きするためにnfcpyというライブラリを使う手法がよく使われているようです。この記事では、Windowsでnfcpyを扱うために行う手順とタイムアウト処理について説明します。

nfcpyに関する記事は多く見つかりますが、Windowsでnfcpyを扱うための手順がまとめられている日本語のものは少なく、不要なライブラリをインストールしている場合もあります。そこで、シンプルにまとめたものを作成します。
また、番外編としてNFCタグの読み込みにタイムアウト処理を実装することで、他のイベントと柔軟に組み合わすことができるようにします。

環境

  • Windows10 64bit
  • Python 2.7.16
  • nfcpy 0.13.5
  • PaSoRi RC-S380

Windows環境でnfcpyを扱う

nfcpyは現在Python2系でのみ動作するライブラリです。そのため、Python2.7環境を構築する必要があります。Python installerを利用する方法とAnacondaを利用する方法がありますが、今回はPython installerを利用します。

  • Python2.7パッケージのダウンロード

公式サイト https://www.python.jp/install/windows/install_py2.7.html を参考にPython 2.7 パッケージをインストールします。インストール途中の設定を変更することで、環境変数を設定できます。なお、同サイト内でMicrosoft Visual C++ Compiler for Python 2.7 をインストールする案内がありますが、今回は必要ありません。

Microsoft Visual C++ Compiler for Python 2.7
Python の環境変数を追加する

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をクリックすることでプルダウンにデバイス一覧が表示されます。

Zadig

デバイスリストを表示する

表示されたデバイスからNFCリーダーを選択します。そして、矢印の右側にある青枠の切り替え部分が WinUSB になっていることを確認して「Replace Driver」を押します。 「Replace Driver」をクリックすると数秒固まったのちインストールが開始します。

「The driver was Installed successfully.」とダイアログが出ると成功です。

Install Driver using Zadig
  • libusbの設定

こちら(http://libusb.info/)からDownload > Latest Windows Binariesをクリックしてダウンロードします。今回は、「libusb-1.0.22.7z」がダウンロードされました。7z形式で圧縮されているので、7zip(https://www.7-zip.org/download.html)などのソフトを使って解凍します。

使用している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:
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読み込み処理を強引に抜ける仕組みです。

%d人のブロガーが「いいね」をつけました。