環境
- raspberryPi 3 Model B
- Raspbian 10(buster)
- Python3
CPU(ラズパイのモデル)、OS、pythonの環境は以下の通り
$ cat cat /proc/cpuinfo | grep Revision
Revision : a22082
$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description: Raspbian GNU/Linux 10 (buster)
Release: 10
Codename: buster
$ python3 --version
Python 3.7.3
$ pip3 --version
pip 18.1 from /usr/lib/python3/dist-packages/pip (python 3.7)
NFCリーダーの接続確認
$ lsusb | grep Sony
Bus 001 Device 007: ID 054c:06c3 Sony Corp. RC-S380
PaSoRi は Sony 製品なのでSony でgrep
nfcpyのインストール
$ sudo pip3 install -U nfcpy
...
$ pip3 list | grep nfcpy
nfcpy 1.0.3
-U オプションは不要かもしれない
プログラムからのNFCリーダーの認識
import nfc
clf = nfc.ContactlessFrontend("usb")
print(clf)
上記プログラムを試しに実行。
$ python3 index.py
Traceback (most recent call last):
File "index.py", line 3, in <module>
clf = nfc.ContactlessFrontend("usb")
File "/usr/local/lib/python3.7/dist-packages/nfc/clf/__init__.py", line 76, in __init__
raise IOError(errno.ENODEV, os.strerror(errno.ENODEV))
OSError: [Errno 19] No such device
$ sudo python3 index.py
SONY RC-S380/P on usb:001:007
sudo しないとデバイスを見つけられない。
しかし、この方法は非推奨。
解決方法は様々なところで述べられているが、以下の通り。
$ python3 -m nfc
This is the 1.0.3 version of nfcpy run in Python 3.7.3
on Linux-4.19.57-v7+-armv7l-with-debian-10.0
I'm now searching your system for contactless devices
** found usb:054c:06c3 at usb:001:007 but access is denied
-- the device is owned by 'root' but you are 'pi'
-- also members of the 'root' group would be permitted
-- you could use 'sudo' but this is not recommended
-- better assign the device to the 'plugdev' group
sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'
sudo udevadm control -R # then re-attach device
I'm not trying serial devices because you haven't told me
-- add the option '--search-tty' to have me looking
-- but beware that this may break other serial devs
Sorry, but I couldn't find any contactless device
python3 -m nfc
を実行すると、やらなければならないことを教えてくれるので、
$ sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'
$ cat /etc/udev/rules.d/nfcdev.rules
SUBSYSTEM=="usb", ACTION=="add", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="06c3", GROUP="plugdev"
$ sudo udevadm control -R
実行して再起動。すると、
$ python3 index.py
SONY RC-S380/P on usb:001:006
$ python3 -m nfc
This is the 1.0.3 version of nfcpy run in Python 3.7.3
on Linux-4.19.57-v7+-armv7l-with-debian-10.0
I'm now searching your system for contactless devices
** found SONY RC-S380/P NFC Port-100 v1.11 at usb:001:006
I'm not trying serial devices because you haven't told me
-- add the option '--search-tty' to have me looking
-- but beware that this may break other serial devs
sudo が不要になった。
タグ情報の取得
import nfc
def on_startup(targets):
for target in targets:
# nanaco
# target.sensf_req = bytearray.fromhex("0004c70000")
# pasmo
target.sensf_req = bytearray.fromhex("0000030000")
return targets
def on_connect(tag):
print(tag)
return True # カードが離れるまでに1回のみ
while True:
with nfc.ContactlessFrontend("usb") as clf:
rdwr = {
'targets': ['212F'], # Type3Tag
'on-startup': on_startup,
'on-connect': on_connect
}
clf.connect(rdwr=rdwr)
上記プログラムでタグ情報を出力する。
いくつかコメントをつけているが、
- rdwrのtargets
Felicaのみ認識するようにしている。
デフォルトだと、on_startupに渡されるtargetsは['212F','106A','106B']
- 免許証はType4BTag
- nanaco, pasmoはType3Tag
それぞれに対応する値が決まっている(通信速度帯?)
- on_startupで指定している数値
事業者ごとに割り振られているらしい。
指定することで、反応するカードを制限できる- pasmo(交通系IC):0003
- nanaco:04c7
- on_connectのreturn値
falseにすると、連続でイベントを起こし続ける。
実行してみる
$ python3 index.py
Type3Tag 'FeliCa Standard (RC-S???)' ID=XXXXXXXX PMM=100B4B428485D0FF SYS=FFFF
IDのみ、一応隠した。
PMMは製造コードらしい。手元の2枚のPASMOで同じ値だったのでそのまま。作った場所が同じとか?
なお、on_startup関数においてtarget.sensf_reqを設定すると、
それまで0003と表示されていたSYS
の値がFFFFになってしまう。
何故かご存じの方居ましたら教えてください...
FeliCaの仕様についてはこちらの記事に詳しく書いてあった。
ななめ読みしかしていないので後で詳しく読む。
tag情報からIDmを抜き出す
on_connect関数を下記のように変更
import binascii
def on_connect(tag):
print(tag)
idm = binascii.hexlify(tag.identifier).upper().decode('utf-8')
print(idm)
return True
tag情報で表示されるIDと同じ値が取得できることを確認。
ID以外のデータの取得方法はこちらに書いてあった内容でいけそう。
ななめ読みしか以下略
コード全体
import nfc
import binascii
def on_startup(targets):
for target in targets:
# nanaco
# target.sensf_req = bytearray.fromhex("0004c70000")
# pasmo
target.sensf_req = bytearray.fromhex("0000030000")
return targets
def on_connect(tag):
idm = binascii.hexlify(tag.identifier).upper().decode('utf-8')
print(idm)
return True
while True:
with nfc.ContactlessFrontend("usb") as clf:
rdwr = {
'targets': ['212F'],
'on-startup': on_startup,
'on-connect': on_connect
}
clf.connect(rdwr=rdwr)