raspberry piでSuicaの履歴の表示

RC-S380 非接触ICカードリーダー/ライター PaSoRi(パソリ)を購入したので、raspberry piに接続して、Suicaを読ませてみました(RC-S380をPCに接続する方法)。プログラムを記述するのにいろいろネットで調べましたが、USBとの接続が簡単で、ネット上に情報がたくさんあるpythonにしました。

まず、pythonからUSBを使用するために、USB通信用の汎用ライブラリpython-usbを導入します。

~/nfcpy $ sudo apt-get install python-usb

Raspberry PiでNFCデータを読み取るために、pythonのライブラリnfcpyをインストールします。ちなみに,bzrはバージョン管理システムBazzarのコマンドラインツールです。root権限で実行します。

~/nfcpy $ sudo apt-get install bzr
~/nfcpy $ bzr branch lp:nfcpy

sudoなしで動作させるために、nfcdev.rulesにRC-S380を登録し、rebootします。

~/nfcpy/nfcpy $ sudo vi /etc/udev/rules.d/nfcdev.rules
SUBSYSTEM==”usb”, ACTION==”add”, ATTRS{idVendor}==”054c”, \
ATTRS{idProduct}==”06c3″, GROUP=”plugdev” # Sony RC-S380/P

ちなみに、sudo しないで Python を実行すると、リーダーが見つからないので、上述のように nfcdev.rules にリーダー情報を書き込んで使うか、毎回 sudo で実行する。RC-S380が見つからない場合に表示されるエラーメッセージを次に示します。
>>> clf = nfc.ContactlessFrontend(‘usb’)
File ““, line 1
clf = nfc.ContactlessFrontend(‘usb’)
^
SyntaxError: invalid syntax

システムが立ち上がると、ディレクトリを「~/nfcpy/nfcpy」に移動し、pythonをインタプリタで起動して、プログラムを実行していくと、PaSoRiが認識されていることが確認できました。

~/nfcpy/nfcpy $ python
Python 2.7.3 (default, Mar 18 2014, 05:13:23)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import nfc
>>> clf = nfc.ContactlessFrontend('usb')
>>> print(clf)
SONY RC-S380/P on usb:001:006
>>>

それでは実際に、Suicaを読み込む簡単なプログラムを、pythonで作ってみました。Suicaの場合,サービスコード「0x090f」ブロック番号「0-19」が利用履歴に割り当てられています。1つのブロックが1件の利用履歴に対応しているので,最大20個の利用履歴が記録されていることになります。最新の利用履歴に対応するブロックを読み出すコードは,nfcpyを使うと次のように実装できます。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import binascii
import nfc
 
service_code = 0x090f
 
def connected(tag):
  # タグのIDなどを出力する
  print tag
 
  if isinstance(tag, nfc.tag.tt3.Type3Tag):
    try:
      # ブロック0番の内容を16進数で出力する
      print "block: %s" % binascii.hexlify(tag.read([0], service_code))
    except Exception as e:
      print "error: %s" % e
  else:
    print "error: tag isn't Type3Tag"
 
# タッチ時のハンドラを設定して待機する
clf = nfc.ContactlessFrontend('usb')
clf.connect(rdwr={'on-connect': connected})

nfcpy のバージョンが 0.11.0 (2016-04-21)にバージョンアップされたため、上記の構文ではエラーになります。15,16行目の内容を次のように変更します。

# ブロック0番の内容を16進数で出力する
sc = nfc.tag.tt3.ServiceCode(service_code >> 6, service_code & 0x3f)
bc = nfc.tag.tt3.BlockCode(0, service=0)
print "block: %s" % binascii.hexlify(tag.read_without_encryption([sc], [bc]))

実行すると、次のようなデータが表示されます。

~/nfcpy/nfcpy $ python suica.py
Type3Tag IDm=010103128e143f07 PMm=100b4b428485d0ff SYS=0003
block: 150300001d9b992c0000b50800007400