PythonでSuicaの残高を取得する(libpafe使用)
- 手元に中古で買ったFelicaリーダのRC-S320があったので,Pythonを使って動かせないか試してみた.
- ちょっとした備忘録的なメモです.
- そのうちRaspberry piとかで何かと組み合わせてみる予定.
動作環境
- OS: LMDE 2 Betsy
- FeliCaリーダ: Sony RC-S320
- Pythonのバージョン: 2.7.9
ライブラリ
- nfcpyの存在を知ったが,RC-S320には対応していない.
-
libpafeが対応していた.
- C言語のライブラリとして使える.
- Ruby上ならlibpafe-rubyが使える.
環境設定
-
libusbのインストール
$ sudo apt-get install libusb-dev
-
GitHubからlibpafeをcloneする
$ git clone https://github.com/rfujita/libpafe.git
-
コンパイル&インストール
$ cd libpafe $ ./configure $ make $ sudo make install
-
動作確認
$ cd libpafe $ ./tests/pasori_test PaSoRi (RC-S320) firmware version 1.40 Echo test... success EPROM test... success RAM test... success CPU test... success Polling test... success
- この時点でudevの設定をしていないので,多分sudoがいるかもしれない (2017/8/14 追記)
-
udevの設定
- 60-libpafe.rulesを作成
$ sudo vi /lib/udev/rules.d/60-libpafe.rules
- 以下の内容を記述
60-libpafe.rulesACTION!="add", GOTO="pasori_rules_end" SUBSYSTEM=="usb_device", GOTO="pasori_rules_start" SUBSYSTEM!="usb", GOTO="pasori_rules_end" LABEL="pasori_rules_start" ATTRS{idVendor}=="054c", ATTRS{idProduct}=="01bb", MODE="0664", GROUP="plugdev" ATTRS{idVendor}=="054c", ATTRS{idProduct}=="02e1", MODE="0664", GROUP="plugdev" LABEL="pasori_rules_end"
-
$ sudo udevadm control --reload-rules
を実行 -
$ sudo reboot
で再起動する.
- 60-libpafe.rulesを作成
ICカードのIDmを取得する
-
ひとまずICカードのIDmを取得してみる.
raspberrypiでFeliCaのIDmを読み取る(pasori RC-S320版)Raspberry Pi + libpafe + Python + ctypesで、FeliCaのIDmを読む
(ほぼこちらに載せられていたものを参考にしています)
read_idm.py
# -*- coding: utf-8 -*-
from __future__ import print_function
from ctypes import *
# libpafe.hの77行目で定義
FELICA_POLLING_ANY = 0xffff
if __name__ == '__main__':
libpafe = cdll.LoadLibrary("/usr/local/lib/libpafe.so")
libpafe.pasori_open.restype = c_void_p
pasori = libpafe.pasori_open()
libpafe.pasori_init(pasori)
libpafe.felica_polling.restype = c_void_p
felica = libpafe.felica_polling(pasori, FELICA_POLLING_ANY, 0, 0)
idm = c_ulonglong()
libpafe.felica_get_idm.restype = c_void_p
libpafe.felica_get_idm(felica, byref(idm))
# IDmは16進表記
print("IDm:", "%016X" % idm.value)
# READMEより、felica_polling()使用後はfree()を使う
# なお、freeは自動的にライブラリに入っているもよう
libpafe.free(felica)
libpafe.pasori_close(pasori)
- libpafeはC言語用のライブラリだが,Pythonのctypesを使うことでC言語の関数がPython上で使えるようになる.
- felica_get_idmを使う.
-
int felica_get_idm(felica *f, uint8 *idm);
- f : felica_pollingで取得したfelica型のポインタ
- idm : IDmを格納するためのポインタ
-
- felica_get_idmを使う.
Suicaの残高を取得する
-
Suicaの残高を表示するのはどうやるか?
- ICカード内の情報を取ってきて,その中から残高の情報を拾ってくる必要がある
- Suicaのデータ構造まとめ: suica - FeliCa Library Wiki - FeliCa Library - OSDN
- 10-11のあたりのデータを取ってくれば良さそう.
-
libpafeのfelica_readという関数で諸々の情報を取ってくることができるので,それを使う.
参考: 続けるブログ: ラズベリーパイがICカードの残高をしゃべるよ- ↑こちらはC言語で書かれているため,ctypesを使ってPython上でfelica_readを呼び出せるように書き換える
- 引数が構造体のポインタを示していたりするので,あらかじめ定義して調整する
read_balance.py
# -*- coding: utf-8 -*-
from __future__ import print_function
from ctypes import *
# libpafe.hの77行目で定義
FELICA_POLLING_ANY = 0xffff
# 構造体の代わりとなるクラスの定義
class felica_block_info(Structure):
_fields_ = [
("service", c_uint16),
("mode", c_uint8),
("block", c_uint16)
]
if __name__ == '__main__':
libpafe = cdll.LoadLibrary("/usr/local/lib/libpafe.so")
libpafe.pasori_open.restype = c_void_p
pasori = libpafe.pasori_open()
libpafe.pasori_init(pasori)
libpafe.felica_polling.restype = c_void_p
felica = libpafe.felica_polling(pasori, FELICA_POLLING_ANY, 0, 0)
# Cのint型配列の定義(長さ16)
int_array16 = c_uint8 * 16
# 応答データ
data = int_array16()
# サービスコードのリスト
info = felica_block_info(c_uint16(0x090f), c_uint8(0), c_uint16(0))
for i in range(0, 32):
c_i = c_int(i)
libpafe.felica_read(felica, byref(c_i), byref(info), byref(data))
if (data[1] > 0) or (data[2] > 0):
print("残高:", data[11] * 256 + data[10], "円")
break
libpafe.free(felica)
libpafe.pasori_close(pasori)
- 同じ構造になっているからか,ICOCAとtoicaでもちゃんと使えた.