VMを使ってUSB経由でNFCを読み取る話
こんにちは。
現在、私の加入しているサークルでは、チーム開発の一つとして、
PaSoRiを使った出席管理システムを作成中です。
このシステムは、Python3で開発しています。
学生証をPaSoRiにタッチすると、サークルの活動に参加したことになり、その日の議事録に名前が載るシステムです(※開発中)。
NFCタグの読み取りのために、nfcpyのモジュールを使用しています。
現状、開発環境はWindows10となっています。
しかし、Windows10での開発は、正直言って面倒です。
今回、開発環境の構築までの手間を比較するために、
VirtualBoxで仮想マシンを作成し、PaSoRiを使用するための設定を行いました。
Windowsでの開発
Windowsで開発を行うためには、下の作業が必要です。
- WinUSB(またはZadig)とlibusbの手動インストール
- nfcpyをpipでインストール
今回、私のチームでは、Zadigとlibusbを手動インストールしました。
ダウンロードしてきたDLLファイルを、手動で C:\Windows\System32 や、C:\Windows\SysWOW64 にCopyすることは、置き間違えなどのリスクがあります。
VirtualBoxでの開発
- Linuxでは、libusbは通常インストール済み
- VM上でUSBデバイスを使うための設定を行う必要がある
- 権限や、ドライバーの設定のために、少しコマンドを叩く必要がある
- nfcpyをpipでインストール
Windows版と違い、手動でCopyするようなものはありません。
仮想マシンでUSBを認識するための設定や、一般ユーザが使用する際の権限の設定などをする必要があります。
環境
今回、動作確認のために用意したものは以下の通りです。
- ホストOS : Windows10 Pro 1909
- ゲストOS : ArchLinux ( Kernel 4.19.88-1-lts x86_64)
- NFCデバイス : Sony PaSoRi RC-S380
- Python 3.8.0
今回、新しいものが使いたいという理由と、約一年前に友人から布教を受けたこともあり、ArchLinuxを使いましたが、Ubuntuなどでも動くと思います。
設定の流れ
設定の流れは、次のようになります。
- 仮想マシンの用意
- VirtualBoxの仮想マシンの設定でUSBの設定
- PaSoRiの認識確認
- nfcpyのインストール
- PaSoRiの接続設定
ここでは、2以降の手順を記述します。
VirtualBoxの仮想マシンのUSB設定
まず、手元のVirtualBoxに設定済みの仮想マシンを用意します。
そして、仮想マシンの状態が電源オフであることを確認します。次に、PaSoRiをUSBポートに挿します。
使用する仮想マシンの設定から、USBを選択、USB2.0コントローラーを有効にします。次に、右にある新規のUSBフィルターの追加から、目的の物(今回の場合はSONY RC-S380/P)を選択します。
nfcpyのインストール
venvを使用し、仮想環境内にインストールします。
venvを使用する理由
venvとは、軽量な仮想環境の作成をサポートしてくれるものです。Python3の標準の機能の一つです。
メリット
- 仮想環境の中に、パッケージ群を独立してインストールできる
- 仮想環境ごとに、使用するパッケージ群のバージョンを分けられる
- それぞれの仮想環境は独立しているため、仮想環境間では競合しない
nfcpyは、現在のプロジェクトでのみ使用し、頻繁に使用するものではないため、仮想環境の中で使用します。
nfcpyのインストールの流れ
$ python -V Python 3.8.0
$ cd [WORKDIR] # 作業ディレクトリへ移動 $ python -m venv [ENV_DIR] # 環境の作成 (ENV_DIRをvenvとする例が多いらしい) $ source [ENV_DIR]/bin/activate (venv)$ pip install nfcpy (venv)$ pip freeze # インストールしたパッケージの確認
PaSoRiの接続設定
接続確認のために、下のコマンドを実行します。
(venv)$ python -m nfc
いくつかエラーが出ることがあるので、確認したものについて順に対処していきます。
This is the 1.0.3 version of nfcpy run in Python 3.8.0 on Linux-5.4.2-arch1-1-x86_64-with-glibc2.2.5 I'm now searching your system for contactless devices ** found usb:054c:06c3 at usb:002:004 but access is denied -- the device is owned by 'root' but you are 'amakuchi' -- also members of the 'root' group would be permitted -- you could use 'sudo' but this is not recommended -- it's better to adjust the device permissions sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", MODE=\"0666\" >> /etc/udev/rules.d/nfcdev.rules' sudo udevadm control -R # then re-attach device I'm not trying serial devices because you haven't told me -- add the option '--search-tty' to have me looking -- but beware that this may break other serial devs Sorry, but I couldn't find any contactless device
このように出ることがあります。
要するに、デバイスを "plugdev" というグループへ追加することを推奨しています。
言われた通りに作業を行います。
$ sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", MODE=\"0666\" >> /etc/udev/rules.d/nfcdev.rules' $ sudo udevadm control -R
PaSoRiの再接続を行い、もう一度、実行します。
(venv)$ python -m nfc
This is the 1.0.3 version of nfcpy run in Python 3.8.0 on Linux-5.4.2-arch1-1-x86_64-with-glibc2.2.5 I'm now searching your system for contactless devices ** found usb:054c:06c3 at usb:002:005 but it's already used -- scan sysfs entry at '/sys/bus/usb/devices/2-2:1.0/' -- the device is used by the 'port100' kernel driver -- this kernel driver belongs to the linux nfc subsystem -- you can remove it to free the device for this session sudo modprobe -r port100 -- and blacklist the driver to prevent loading next time sudo sh -c 'echo blacklist port100 >> /etc/modprobe.d/blacklist-nfc.conf' I'm not trying serial devices because you haven't told me -- add the option '--search-tty' to have me looking -- but beware that this may break other serial devs Sorry, but I couldn't find any contactless device
今度は、デバイスのport100は、既に使われているというメッセージが出ました。
そのため、port100のカーネルドライバを取り外します。
$ sudo modprobe -r port100
また、今後も停止させ続けておきたい場合は、ブラックリストに入れます。
$ sudo sh -c 'echo blacklist port100 >> /etc/modprobe.d/blacklist-nfc.conf'
もう一度、実行します。
(venv)$ python -m nfc
This is the 1.0.3 version of nfcpy run in Python 3.8.0 on Linux-4.19.88-1-lts-x86_64-with-glibc2.2.5 I'm now searching your system for contactless devices ** found SONY RC-S380/P NFC Port-100 v1.11 at usb:002:003 I'm not trying serial devices because you haven't told me -- add the option '--search-tty' to have me looking -- but beware that this may break other serial devs
このように出たら、成功です!最後に、きちんと終了させます。
(venv)$ deactivate # 仮想環境から出る
おわり!
仮想マシンのUSBデバイスフィルターの設定は、GUIでしましたが、操作ミスの起こりにくい場所であり、ファイルの手動コピーよりは心理的安全性がありました。また、仮想マシン内での操作は、コマンドをぽちぽち貼り付けるだけなので、個人的には、Windows版でやるより、仮想マシンの中でやるほうが楽だと感じました。
それから、やはりWindowsの方のドライバはあまり触りたくないなーという気持ちがあります。libusbの導入と、Zadigのインストールをしなくて良いというだけで、仮想マシンでの開発を選ぶメリットがある気がします。
なお、今回一番時間がかかったのは、ArchLinuxの設定です……。しばらく環境を壊さないように気を付けたいです……。また、ArchLinuxのデスクトップ環境は作っていません。Webアプリケーション以外のGUIアプリケーションを作る予定がない間は、デスクトップ環境は作らないと思います。作ったらまたブログに書くと思います。
それから、昨年の誕生日プレゼントにPaSoRiをくださった先輩、ありがとうございました☺