作ってみた!ラズパイガジェット達はこちら

NFCに書込みとこれまでの修正——Raspberry Pi × RC-S380 NFCタグ

NFC-read-Write 作ってみた!

先日、3回に分けてSONY製カードリーダーRS-S380とキャラクタLCDを使いLCDにIDを表示することができました。

SONY非接触型カードリーダーRC-S380とraspberry pi(読み取り編)
Raspberry Pi にRaspbianを入れて、SONY非接触型カードリーダーRC-S380を使えるところまでご紹介します。 次にDisplay-O-Tron HATを繋いで結果を表示させ...
SONY非接触型カードリーダーRC-S380とraspberry pi(LCD表示編)
前回のSONY非接触型カードリーダーRC-S380とraspberry pi(読み取り編)で最低限のセットアップをしました。 カードリーダーと連携させるつもりでDisplay-O-Tron HATを...
SONY非接触型カードリーダーRC-S380とraspberry pi(実装編)NFCを読み込んでLCDにID表示まで
SONY非接触型カードリーダーRC-S380とraspberry piの連携記事も3回目です。 集めたコードを利用してNFCタグを読み込んで、そのIDをLCDに表示させます。 前回までの記...

今回は、NFCへの書き込みをしてみたいと思います。全てにおいて簡単にできるよう考えていますけど、分からない、間違えている箇所はお気軽にコメント欄にお知らせください。出来る範囲でご対応しています。

今回の環境
  • Raspbian Stretch Lite
  • SSH接続でモニターレス
  今回利用したパーツ一覧
Raspberry Pi Zero WHRaspberry Pi Zero WH
SONY 非接触ICカードリーダー/ライター PaSoRi RC-S380
電子キットOSOYOO 初心者スターター電子キット
サンワサプライNFCタグサンワサプライ NFCタグ(10枚入り) 白

書き込み用Pythonコード

単純に書き込みは、

record = nfc.ndef.TextRecord("Coffee")

というカタチで書き込みます。この場合はCoffeeというテキストです。

ネットの諸氏から集めたコードやサンプルを参考にして、これで書き込めたのでヨシとしています。突っ込まれると思うので、先にごめんなさい。適時直してくださいね。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import nfc
import nfc.ndef

def startup(targets):
print "waiting for new NFC tags..."
return targets


def connected(tag):
if not tag.ndef or not tag.ndef.is_writeable:
print("not a writeable nfc tag")
return False
print("old message:")
print(tag.ndef.message.pretty())

if tag.ndef:
record = nfc.ndef.TextRecord("Coffee")
new_message = nfc.ndef.Message(record)
print str(record.pretty())
#return true

if len(str(new_message)) > tag.ndef.capacity:
print "too long message"
return True

if tag.ndef.message == new_message:
print "already same record"
return True

tag.ndef.message = new_message
print("new message:")
print(tag.ndef.message.pretty())

return True

def released(tag):
print("released:")
if tag.ndef:
print(tag.ndef.message.pretty())


clf = nfc.ContactlessFrontend('usb')
print(clf)
if clf:
while clf.connect(rdwr={
'on-startup': startup,
'on-connect': connected,
'on-release': released,
}):
pass

※インデント無視なので、コピペの際は気をつけてください。すみません(いずれ対応します・・・)

(Pythonではどうかまだ知りませんけど)書き込む文字列はインプット形式で入力待ちにして、都度入力した方が実用的でしょう。同じ物を書き込むなら1回作れば何回でもコマンドで実行できます。

読み込んでみると正しく表示されない?

前回のコードではそのままだとエラーが出るかも知れません。LCDへの表示もおかしな文字が出るかも知れません。

SONY非接触型カードリーダーRC-S380とraspberry pi(読み取り編)
Raspberry Pi にRaspbianを入れて、SONY非接触型カードリーダーRC-S380を使えるところまでご紹介します。 次にDisplay-O-Tron HATを繋いで結果を表示させ...

読み込んでみると、以下のように文字列などが表示されました。

LCDにも正しく表示されません。ひとつは文字コードの問題もあるでしょう。見直しました。他にもありました。

x02en

Print文でTag type、IDなど5つ表示させています。

下から2行目の「? TenCoffee」がCoffeeというテキストです。しかし、おかしいですよね? その一つ上にをご覧ください。レコードの項目のdata=部分が実際の文字列です。

\x02enCoffee

これはテキストに付随するヘッダーと書き込んだテキストが繋がっている状態です。これ、LCDに表示させるのに、テキストだけにしたいと思っても、最初はどういう理由か分かりませんでした。

 

私と同じように分からなくて質問している人をなんとか1人見付けました! 居るもんですねー。(結構、探した!)

Reading and Parsing NFC tag on iOS 11

For the plain text tag, typeNameFormat isnfcWellKnown. Let’s assume identifier, payload and type are all UTF-8 string. After we convert Data to string and print them out, we will see identifier is empty, type is “T”, payload is “enhello”. Obviously “T” means Text. But why is there “en” before “hello”?

(意訳)プレーンテキストタグの場合、NFCのtypeNameFormatは周知されています。識別子、ペイロード、および型式がすべてUTF-8文字列であるとしましょう。 Dataを文字列に変換して印刷した後、識別子が空、typeが“ T”、payloadが“ enhello”になります。 明らかに「T」はテキストを意味します。 しかし、なぜ「こんにちは」の前に「en」があるのでしょうか?

同じ環境ではないのですけど、同じNFCについての記述がありました。

恐らくプログラマーの人は当たり前ですけど、データにヘッダーが付いていることで色々と操作できるので、フォーマットって決まっていますよね。バーコードとかプリンター制御もそうだし、何かのデータセットだと何byteかは意味がありますよね。

詳しくは以下のサイトをご覧ください。結構詳しく書いてありました。

NFC P2P NDEF Basics

取り出し方を変えた

結局、どうやってうまく表示させたのかというと、データの取り出し方を変えました。nfcpyのリファレンスともにらめっこでした。

しかし、以下の記事が正解でしたね・・・。遠回りしたぞ。

PaSoRiでNFCタグとFeliCaを読み込んで出力 - Qiita
# はじめに NFCタグ、FeliCaで読み取りを行った時の備忘です。 ndefのデータ読み取りがpretty()での例が多かったので、登録したままのテキストだけを取り出すがゴールです。 Raspberry Piへの設定とnfcpyの...
# NFCタグに埋めたtextを読む
records = tag.ndef.records

ほぼ、こちらの記事から修正し直しました! @nofrmmさん、記事をありがとう! 私の記事よりも参考になります。というか、コードはそのままでOKだと思います。

修正したコード

先の3つの記事では、メインのmymain.py、書き込むWite2tag.py、そしてLCD表示用にi2clcda.pyの3つのファイルと、nfcpyのファイル群で構成しています。

nfc_all_file

修正したmymain.py

#!/usr/bin/env python
# coding:UTF-8

import nfc
import binascii
import time
from threading import Thread, Timer
import smbus
import sys

# 読み取り待ち受けの1サイクル秒
TIME_cycle = 3.0
# 待ち受けの反応インターバル秒
TIME_interval = 0.2
# タッチされてから次の待ち受けを開始するまで無効化する秒
TIME_wait = 3

# NFC接続リクエストのための準備
# 212F(FeliCa)で設定
target_req_felica = nfc.clf.RemoteTarget("212F")
# 106A(NFC type A)で設定
target_req_nfc = nfc.clf.RemoteTarget("106A")


# Define some device parameters
I2C_ADDR = 0x27 # I2C device address, if any error, change this address to 0x3f
LCD_WIDTH = 16 # Maximum characters per line

# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command

LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line

LCD_BACKLIGHT = 0x08 # On
#LCD_BACKLIGHT = 0x00 # Off

ENABLE = 0b00000100 # Enable bit

# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005

#Open I2C interface
#bus = smbus.SMBus(0) # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1

def lcd_init():
# Initialise display
lcd_byte(0x33,LCD_CMD) # 110011 Initialise
lcd_byte(0x32,LCD_CMD) # 110010 Initialise
lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
lcd_byte(0x01,LCD_CMD) # 000001 Clear display

def lcd_byte(bits, mode):
# Send byte to data pins
# bits = the data
# mode = 1 for data
# 0 for command

bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT

# High bits
bus.write_byte(I2C_ADDR, bits_high)
lcd_toggle_enable(bits_high)

# Low bits
bus.write_byte(I2C_ADDR, bits_low)
lcd_toggle_enable(bits_low)

def lcd_toggle_enable(bits):
# Toggle enable
time.sleep(E_DELAY)
bus.write_byte(I2C_ADDR, (bits | ENABLE))
time.sleep(E_PULSE)
bus.write_byte(I2C_ADDR,(bits & ~ENABLE))
time.sleep(E_DELAY)

def lcd_string(message,line):
# Send string to display
message = message.ljust(LCD_WIDTH," ")
lcd_byte(line, LCD_CMD)

for i in range(LCD_WIDTH):
lcd_byte(ord(message[i]),LCD_CHR)

# Main program block
def main():
# Initialise display
lcd_init()

print 'NFC waiting...'
msg0 = "...scan?"
#LCDに表示
lcd_string(msg0,LCD_LINE_1)

# USBに接続されたNFCリーダに接続してインスタンス化
clf = nfc.ContactlessFrontend('usb')

mydict = {}
while True:
target_res = clf.sense(target_req_nfc,target_req_felica, iterations=int(TIME_cycle//TIME_interval)+1 , interval=TIME_interval)

if not target_res is None:
tag = nfc.tag.activate(clf, target_res)
print 'TAG type: ' + tag.type

records = tag.ndef.records
for record in records :
print 'record.text = ' + record.text
key = str(record.text)
mydict[key] = key

msg1 = str(tag.identifier).encode('hex').upper()
msg2 = key

#LCDに表示
lcd_string(msg1,LCD_LINE_1)
lcd_string(msg2,LCD_LINE_2)

print 'sleep ' + str(TIME_wait) + ' seconds'
time.sleep(TIME_wait)

clf.close()

if __name__ == '__main__':

try:
main()
except KeyboardInterrupt:
pass
finally:
# LCD_BACKLIGHT = 0x00
lcd_byte(0x01, LCD_CMD)
sys.exit(0)

コード類は参考程度にご利用ください。

次は別に価格表を作り、ID毎にデータを取り出してみます。
最終的にNFCタグを物に貼って、オママゴトのレジに出来たらと思っています! 子供ってレジが好きですよねー。

NFCタグの読み込み

作ってみた!ラズパイガジェット達
Raspberry Pi (2/3B/3B+/zero/zero W/zero WH)で作ってみたガジェットをご紹介します。 あんまり監視しないカメラ カメラモジュールv1.3で作りました...

コメント