search
LoginSignup
42

More than 5 years have passed since last update.

posted at

updated at

PythonでSuicaの残高を取得する(libpafe使用)

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が使える.

環境設定

  1. libusbのインストール
    • $ sudo apt-get install libusb-dev
  2. GitHubからlibpafeをcloneする
    • $ git clone https://github.com/rfujita/libpafe.git
  3. コンパイル&インストール

    $ cd libpafe
    $ ./configure
    $ make
    $ sudo make install
    
  4. 動作確認

    $ 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 追記)
  5. udevの設定

    • 60-libpafe.rulesを作成
      • $ sudo vi /lib/udev/rules.d/60-libpafe.rules
    • 以下の内容を記述
    60-libpafe.rules
    ACTION!="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で再起動する.

ICカードの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を格納するためのポインタ

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でもちゃんと使えた.

参考

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
42