Python
NFC
RaspberryPi
suica

Raspberry PiにNFCリーダを接続してSuicaを読み取る

このエントリは「Raspberry Piでスマートロックつくった」の解説3つめになります。
スマートロックなのでカッコよくしたいです。なのでNFCリーダを使い、ドアの外からSuicaをタッチしたらカギを開閉できるようにします。このエントリではSONYのNFCリーダPaSoRi RC-S380をRaspberry Piに接続し、SuicaカードをタッチしてIDmを取り出すまでをやってみます。

準備

RC-S380はAmazonなどで3000円くらいで買えます。家電量販店でもたまに売ってます。
PythonでNFCリーダを取り扱うライブラリとしてnfcpyというのがあるのでインストールします。

$ sudo pip install nfcpy

また、Githubからサンプルコードも頂戴しておきます。
nfcpy | Github
それではさっそくRC-S380をRaspberry PiにUSB接続し、examples/tagtool.pyを実行してみます。なおnfcpyはPython2.xで動作します。

$ sudo python2 examples/tagtool.py

うまく行けば、「** waiting for a tag **」と表示されます。ここでSuica等のNFCタグをタッチすると、そのタグを読み込んだ結果が表示されます。Suicaに限らずPasmoやNanacoやマイナンバーカード等、身近にある色んなNFCタグをタッチしてみて下さい。

IDmを取り出す

SuicaやPasmo等のFeLiCaタグにはすべてIDmというユニークなIDが割り振られています。これはいわゆる製造番号のようなものだそうで、これを使えばタッチしたカードの個別な識別が可能になります。※ただしこのIDmはFeLiCaカードのエミュレーションにより偽装できてしまう点は留意しておくべきです。単なるパスワードとして考え厳重に管理し、それをタッチするだけで入力できるのがFeLiCaカード、と考えておくとよいでしょう。
さて、それではSuicaがタッチされた時にIDmを取り出すプログラムを動かしてみます。

suica.py
# -*- coding: utf-8 -*-
import binascii
import nfc
import time
from threading import Thread, Timer

# Suica待ち受けの1サイクル秒
TIME_cycle = 1.0
# Suica待ち受けの反応インターバル秒
TIME_interval = 0.2
# タッチされてから次の待ち受けを開始するまで無効化する秒
TIME_wait = 3

# NFC接続リクエストのための準備
# 212F(FeliCa)で設定
target_req_suica = nfc.clf.RemoteTarget("212F")
# 0003(Suica)
target_req_suica.sensf_req = bytearray.fromhex("0000030000")

print 'Suica waiting...'
while True:
    # USBに接続されたNFCリーダに接続してインスタンス化
    clf = nfc.ContactlessFrontend('usb')
    # Suica待ち受け開始
    # clf.sense( [リモートターゲット], [検索回数], [検索の間隔] )
    target_res = clf.sense(target_req_suica, iterations=int(TIME_cycle//TIME_interval)+1 , interval=TIME_interval)

    if target_res != None:

        #tag = nfc.tag.tt3.Type3Tag(clf, target_res)
        #なんか仕様変わったっぽい?↓なら動いた
        tag = nfc.tag.activate_tt3(clf, target_res)
        tag.sys = 3

        #IDmを取り出す
        idm = binascii.hexlify(tag.idm)
        print 'Suica detected. idm = ' + idm

        print 'sleep ' + TIME_wait + ' seconds'
        time.sleep(TIME_wait)
    #end if

    clf.close()

#end while

実行するには管理者権限が必要です。

sudo python2 suica.py

Suicaをタッチしてみて、IDmが表示されれば成功です。
自分が普段使うSuicaのIDmを覚えさせておき、次回以降同じカード=同じIDmがタッチされた時はサーボを回してカギを開ける、という風に実装すればいよいよスマートロックっぽくなってきます。



なお、nfcpyではよくconnect()メソッドを使ってタグ検知する手法が紹介されていますが、これではApple PayのExpress Cardに登録されたSuicaを検知できないようです。sense()を使うことでApple Pay内Suicaを検知できますが、今度は逆にconnect()で検知できていた各種NFCカードが検知できないようです。使用目的やお持ちのカードに合わせて選択すると良いかと思います。(参考:nfcpy で Apple Pay のエクスプレスカードを扱う - Qiita

管理者権限なしで動かす

実行する時にsudoしなくてもいいようにします。
まずlsusbコマンドを打って接続されているRC-S380のIDを調べます。

$ lsusb
Bus 001 Device 004: ID XXXX:YYYY Sony Corp.

上記のXXXX、YYYYという部分に表示されるIDを使って、下記のとおりコマンドを実行します。

$ sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"XXXX\", ATTRS{idProduct}==\"YYYY\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'

これでsudo無しでもRC-S380を使えるようになりました。
Next:Raspberry PiでHueを操作する