毎年冬になるとつらいのが冷え性です。
今までは身体が冷えてるような気がするから冷え性だろうと思っていました。しかし、「推測するな計測せよ」という言葉を思い出しました。
そこで記録が手軽に残せる体温計を探してみました。すると、NFCでデータを転送し、専用アプリでデータを管理できる体温計がありました。
WOMAN℃ テルモ女性体温計W525DZ|女性体温計 |テルモ 一般のお客様向け情報
目的が違うような気もしますが、データを残しておきたい気持ちが勝ったため、入手しました。
残念なのは専用アプリがWindows向けであり、Macでは使えないことです。
もしかしたら nfcpy
を使えばデータを読めるのではないかと思い、試してみることにしました。
nfcpy/nfcpy: A Python module to read/write NFC tags or communicate with another NFC device.
結論からすると、Macでもデータは読み込めたものの、データのフォーマットが公開されていない、もしくは、暗号化された領域にデータを保存しているため、うまくいきませんでした。
とはいえ、せっかくなので、読み込んだデータなどをメモしておきます。
目次
環境
なお、nfcpyはPython3対応を進めているようです。進捗状況は以下のissueにありました。
Support Python 3 · Issue #47 · nfcpy/nfcpy
実装内容
NFCタグとの対話をハンドリングする
NFCタグとの対話をハンドリングする方法は、以下にありました。
Read and write tags | Getting started — nfcpy 0.13.4 documentation
ContactlessFrontend
は使い終わったら close()
する必要がありますが、Pythonのwith文に対応しているため、以下のように書けます。
with nfc.ContactlessFrontend('usb') as clf: clf.connect(rdwr={'on-connect': connected})
あとは、 connected()
コールバック関数を定義し、その中にNFCタグとの通信を記載すれば良さそうです。
コールバック関数には引数tagが渡されてくるため、その中身を見てみました。IDやPMMはボカしていますが、こんな感じでした。
def connected(tag): print tag # => Type3Tag 'FeliCa Plug (RC-S926)' ID=03xxxxxxxxxxxxxx PMM=01xxxxxxxxxxxxxx SYS=FEE1 print type(tag) # => <class 'nfc.tag.tt3_sony.FelicaPlug'> print dir(tag) # => # ['IC_CODE_MAP', 'NDEF', 'TYPE', '__class__', '__delattr__', '__dict__', '__doc__', # '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', # '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', # '__subclasshook__', '__weakref__', '_authenticated', '_clf', '_format', '_is_present', # '_ndef', '_nfcid', '_product', '_target', 'authenticate', 'clf', 'dump', 'dump_service', # 'format', 'identifier', 'idm', 'is_authenticated', 'is_present', 'ndef', 'pmm', 'polling', # 'product', 'protect', 'read_from_ndef_service', 'read_without_encryption', # 'send_cmd_recv_rsp', 'sys', 'target', 'type', 'write_to_ndef_service', # 'write_without_encryption']
この結果より、
- システムコードが
FEE1
- 引数tagが
FelicaPlug
であることから、普通のFeliCaではなく、W525DZではFeliCa Plug を使っているようでした。
Polling
続いて、pollingを試してみます。
nfcpyの関数 polling()
の引数 system_code
にはシステムコードが必要そうです。
システムコードは tag.sys
に設定されていることから、それを使います。
def connected(tag): print tag.polling(tag.sys) # => (bytearray(b'\x03\xxx\xxx\xxx\xxx\xxx\xxx\xxx'), # bytearray(b'\x01\xxx\xxx\xxx\xxx\xxx\xxx\xxx'))
先ほど tagをprintしたときに出てきた値を、bytearrayのタプルとして取得できました。
Read Without Encryption
さらに、暗号化されていない部分からデータを読み込んでみます。
今回は、tagオブジェクトの read_without_encryption()
を使えば良さそうでした。
引数は2つあり、サービスコードのリストとブロックコードのリストでした。
サービスコードは nfc.tag.tt3.ServiceCode
クラスのインスタンスを渡せば良さそうでした。
必要な値は、FeliCa Plug ユーザーズマニュアル v1.14の
と推定したため、
sc = nfc.tag.tt3.ServiceCode(0, 0x0b)
の1要素を持つリストとしました(とはいえ、第一引数 number
がサービスコードリスト順番なのかは自信がないですが...)。
ブロックコードについては nfc.tag.tt3.BlockCode
クラスのインスタンスを使います。
コンストラクタの引数については、
- number : ブロック番号
- service : サービスコードリストのindex (今回は1つしかないので
0
)
を指定したのを2つ用意しました。
bc1 = nfc.tag.tt3.BlockCode(0, service=0) bc2 = nfc.tag.tt3.BlockCode(1, service=0)
あとはそれらを read_without_encryption()
メソッドに渡し、取得したデータを binascii.hexlify()
で16進数表記したのをprintしてみました。
data = tag.read_without_encryption([sc], [bc1, bc2]) print '{}'.format(binascii.hexlify(data)) # => 02fd8c73947acef9742874c2b8429cc1d7dab10accf72bd5318863f862dc0371
何らかの値は取れているようですが、どの位置の数字が何を意味しているのか分からないため、解読できませんでした。
dump()
他にメソッドがないかを探したところ、 dump()
があったため試してみました。
print tag.dump() # => ['This is not an NFC Forum Tag.']
残念ながら、FeliCa Plugでは使えないようです。
dump_service()
他にもダンプできそうなメソッドとして dump_service()
があったため、試してみました。
引数にはサービスコードが必要そうでしたが、先ほど作成したサービスコードを流用しました。
sc = nfc.tag.tt3.ServiceCode(0, 0x0b) print tag.dump_service(sc) # => # ['0000: 02 fd 8c 73 94 7a ce f9 74 28 74 c2 b8 42 9c c1 |...s.z..t(t..B..|', # '* 02 fd 8c 73 94 7a ce f9 74 28 74 c2 b8 42 9c c1 |...s.z..t(t..B..|', # '6962: 02 fd 8c 73 94 7a ce f9 74 28 74 c2 b8 42 9c c1 |...s.z..t(t..B..|']
dump_service()
はサービスに対応する全データブロックをダンプするとのことで、実行が終わるまで少々待ちました。
データは出力されたものの、こちらもフォーマットが不明なため、解読できませんでした。
ここまでで、フォーマットが分からないことには解読できなさそうと考え、これ以上の追求はやめました。
参考
- Sony Japan | FeliCa | 法人のお客様 | ダウンロード
- FeliCaに関する技術情報はこちらにまとまっていました
- その他FeliCaに関する資料
また、ユーザーズマニュアル中の数値については、ユーザーズマニュアル(v1.14)のp3に記載がありました。
ソースコード
GitHubに上げました。 felica_plug/read_w525.py
が今回のソースコードです。
https://github.com/thinkAmi-sandbox/nfcpy-sample