これはなに?
Ubuntu 22.04、SONY Pasori RC-S380、nfcpy を使用して Suica を読み込もうとしたときのトラブルシュートメモです。
いきなりソースコード
とりあえず、こんなコードを動かしてみました。よくあるやつなので、スルーしていただいて大丈夫です。
実行には nfcpy が必要です。Poetry等を使用して環境を作るか、あるいは pip を使用するかして、nfcpy をインストールしてください。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import itertools
import nfc
from struct import unpack
from datetime import date, time, datetime
import csv
reader_id = 'usb:054c:06c1'
service_code_purchase = 0x090f
service_code_history = 0x108f
eki_code = {}
# 駅コード読み込み
with open("ekicode.csv") as csvfile:
reader = csv.DictReader(csvfile, fieldnames=[
'area', 'line', 'station', 'company_name', 'line_name', 'station_name'])
for row in reader:
area = int(row['area'], 16)
line = int(row['line'], 16)
station = int(row['station'], 16)
if not area in eki_code:
eki_code[area] = {}
if not line in eki_code[area]:
eki_code[area][line] = {}
eki_code[area][line][station] = row['station_name']
def resolve_station_name(area_code, line_code, station_code):
try:
return eki_code[area_code][line_code][station_code]
except KeyError:
return '不明'
def read_blocks(tag, sc):
for i in itertools.count():
try:
# 例外起きるまで読み出し
bc = nfc.tag.tt3.BlockCode(i, service=0)
yield tag.read_without_encryption([sc], [bc])
except nfc.tag.tt3.Type3TagCommandError:
break
def read_purchase(tag):
"""
支払い履歴
"""
print("### Reading purchase history.")
sc = nfc.tag.tt3.ServiceCode(
service_code_purchase >> 6, service_code_purchase & 0x1f)
for data in read_blocks(tag, sc):
# print("" . join(['%02x ' % s for s in data]))
# 0 B 機種種別
# 1 B 利用種別
# 2 B 支払い種別
# 3 B 入出場種別
# 4 H 出場日付
# 5 B 入場路線コード
# 6 B 入場駅順コード
# 7 B 出場路線コード
# 8 B 出場駅順コード
# 9 H 残額
# 10 B 不明
# 11 H 取引連番
# 12 地域コード等
be = unpack('>BBBBHBBBBHBHB', data)
le = unpack('<BBBBHBBBBHBHB', data)
# 鉄道のみ対応
if not be[1] in {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x14}:
next
p_date = date((be[4] >> 9) + 2000, (be[4] >> 5) & 0xf, be[4] & 0x1f)
p_dep_area_code = (be[12] >> 6) & 0x3
p_arr_area_code = (be[12] >> 4) & 0x3
dep_station_name = resolve_station_name(p_dep_area_code, be[5], be[6])
arr_station_name = resolve_station_name(p_arr_area_code, be[7], be[8])
print(p_date.strftime('%Y-%m-%d'),
f'{dep_station_name} -> {arr_station_name} {le[9]}円',
f'{p_dep_area_code} {be[5]} {be[6]} -> {p_dep_area_code} {be[7]} {be[8]}')
def read_history(tag):
"""
改札履歴
"""
print("### Reading gate history.")
sc = nfc.tag.tt3.ServiceCode(
service_code_history >> 6, service_code_history & 0x1f)
for data in read_blocks(tag, sc):
# print("" . join(['%02x ' % s for s in data]))
be = unpack('>BBBBHHBBHHBB', data)
h_line_code = be[2]
h_station_code = be[3]
h_time = datetime((be[5] >> 9) + 2000, (be[5] >> 5) & 0xf,
be[5] & 0x1f, int(hex(be[6])[2:]), int(hex(be[7])[2:]), 0)
print(h_time.strftime('%Y-%m-%dT%H:%M:%S'), h_station_code)
def connected(tag):
print(tag)
if not isinstance(tag, nfc.tag.tt3.Type3Tag):
print("error: tag isn't Type3Tag")
return
read_purchase(tag)
read_history(tag)
# 接続開始
clf = nfc.ContactlessFrontend(reader_id)
try:
clf.connect(rdwr={'on-connect': connected})
finally:
clf.close()
Pasori に Suica をかざすと、なにか出力されるはずです。
トラブルシュート
ここからが本題です。
NO SUCH DEVICE と言われる
プログラムの中で定義しているreader_id
usb:054c:06c1 が間違っているのかもしれません。
lsusb
コマンドで確認してください。
下記は、自分の環境の場合です。
% lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 046d:c52b Logitech, Inc. Unifying Receiver
Bus 001 Device 002: ID 17ef:6009 Lenovo ThinkPad Keyboard with TrackPoint
Bus 001 Device 007: ID 054c:06c1 Sony Corp. RC-S380/S
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
パーミッションがなさそう?
自分自身を plugdev
グループへ追加し、ログインし直してください。
gpasswd -a `whoami` plugdev
Pasori を刺して、/dev/bus/usb
の下にあるデバイスを確認してみてください。plugdev
グループに読み書き権限があればOKです。
下記は、自分の環境の場合です。
% ls -l /dev/bus/usb/001/007
crw-rw----+ 1 root plugdev 189, 6 3月 13 13:02 007
/dev/bus/usb 配下の 001/007 は、lsusb
コマンドで確認できます。
RESOURCE BUSY と言われる
デフォルトで読み込まれる port100
モジュールと衝突しているのかもしれません。
いったん Pasori を抜き、以下の内容のファイルを /etc/modprobe.d/blacklist-nfc.conf
として作成してください。
# Conflict with nfcpy
blacklist port100
作成したら、Pasori を刺してください。
以下のコマンドを実行し、モジュールがロードされていないことがわかればOKです。
lsmod | grep port100
駅名が見つからない
どういう理屈かわかりませんが、出場駅が 0 0 0 となっていることがあります。
探求中です。
リンク集