2021年8月19日木曜日

RFID的商品マスタの持ち方を考えてみた

RFIDを使って在庫管理をしようと思ったとき、在庫データの持たせ方は大きく2つに分類されると考えています。すなわち、

  • ユニークなタグIDに品番や品名などの商品の情報を紐づけて管理する方法
  • システムに商品マスタを持ち、タグIDの一部を使って商品マスタとマッチングして管理する方法
前者は、たとえばMANICAモバイル棚卸パッケージで採用している方法です。今回は後者の方法について考えてみたいと思います。

標準的な方法(SGTIN-96)

RFIDを使って商品の在庫管理を行う場合、JANコードベースのSGTIN-96を使った方法が一つ考えられます。このとき商品マスタはこんな感じになっていると思います。

商品マスタ(商品コード, 商品名, JANコード, 仕様, ...)

ICタグを読んで商品コード、商品名やそのほか仕様等を取得する場合は、下記のような変換を行う感じになると思います。

SGTIN-96 → JANコード → JANコードで商品マスタを検索 → 商品コードなどを取得

標準的でない方法(独自コード)

さまざまな理由で独自コードを採用するケースも考えられます。このとき商品マスタはこんな感じになっていると思います。

商品マスタ(商品コード, 商品名, バーコード, 仕様, ...)

標準的な方法のJANコードがバーコードに変わっただけですね。もしかすると、商品コードとバーコードが一致しているかもしれません。標準的な方法と同じように商品コード、商品名やそのほか仕様等を取得する場合を考えてみます。ICタグのEPCのなかに商品コードが含まれているとします。

EPC → 商品コード → 商品コードで商品マスタを検索 → 商品コードなどを取得

標準的な方法とほとんど変わらないですね。ただ、独自コードですので、EPCから商品コードへの変換は独自コードごとに対応(=カスタマイズ)が必要となります。

統一した方法(SGTIN-96、独自コード)

SGTIN-96も独自コードも統一して管理できる方法を考えてみます。まず、商品マスタはこんな形で持たせてみます。

商品マスタ(商品コード, 商品名, バーコード, 検索キー, 仕様, ...)

ここで新たに追加した検索キーには、シリアルを0として当該商品コードをEPCにエンコードした場合の値を保持しておきます。他にMaskをシステムで一つ保持しておきます。Maskはシステムで採用したタグID長のByte配列とし、EPCのうち商品コードを特定するための部分に1を立てておきます。EPCから商品コードを取得するにはこんな感じになると思います。

EPC → 検索キー(EPCとMaskをAnd) → 検索キーで商品マスタを検索 → 商品コードなどを取得

SGTIN-96、JANコードが4573228900149の場合はこんな感じになると思います。

Mask: FFFF FFFF FFFF FFC0 0000 0000
商品マスタ(商品コード1, 商品名1, 4573228900149, 302DB42318A0038000000000, 仕様1, ...)

たとえば、EPC: 302DB42318A0038000001231 を読み取ったら、Maskして、302DB42318A0038000000000 となるので、商品マスタを検索して、商品コード1などが取得できます。

一方で、独自コードの場合はこんな感じになると思います。タグIDの0~15 bit目と32~47 bit目に分かれて、商品コード相当の値が入っていたとします。

Mask: FFFF 0000 FFFF 0000 0000 0000
商品マスタ(商品コード2, 商品名2, A123B456, A1230000B456000000000000, 仕様2, ...)

たとえば、EPC: A1230000B456000000004567 を読み取ったら、MaskしてA1230000B456000000000000 となるので、商品コード2などが取得できます。

あと考える必要があるのは商品マスタの連携方法だと思います。当然検索キーに相当する列は存在しないので、連携の際にエンコードルールに基づいて変換して登録することになると思います。

商品マスタ連携部分は都度対応が求められる箇所かと思いますので、そこに修正を押し込められるのはこの持ち方のメリットかなと思います。こんなケースはどうするのか、など考慮不足などあれば、コメントでお知らせください。

2021年8月11日水曜日

DRAGINO の LoRaWAN ゲートウェイと Azure IoT Hub を接続する

 最近 LoRaWAN を触ることになったんですが、通常は The Things Network を LoRaWANサーバとして利用しますが今回は The Things Network を経由せずに Microsoft Azure IoT Hub に接続したいという特殊な状況になってしまったためいろいろやってたんですが、これがえらいハマってしまったので記録として残しておこうと思いました。

使用する LoRaWANゲートウェイは DRAGINO の LPS8 です。

設定画面をいろいろ見ていると、Azureとかの設定もあるしこれは簡単にできそうだなーと思ったら全く違っていろいろ大変でした。

まずは端末の認証ですが、ゲートウェイ単体では OTAA(Over-the-Air Activation)はできませんので、ABP(Activation by Personalization)を使うことにします。ABPの設定は端末ごとに DevADDR、APP Session Key、Network Session Key の3つを設定画面で設定して、同じ値を端末に設定すればOKです。

以降、設定画面のキャプチャ掲載しますがファームの更新が結構頻繁にあるようなので実際とは異なる可能性あります。掲載時点でのファームのバージョンは lgw-5.4.1628078462 です。

ABPの設定をしたら、LoRaWAN Configuration の画面に移ります。Service Provider のところに、Built-in for ABP Decode to MQTT というまさしくそれな的なのがあるので選んで保存します。


次にMQTTの設定です。Azure IoT Hub にMQTTで接続するには、SASと呼ばれるセキュリティトークンを使用する方法と、X.509証明書を利用する方法があるようです。

https://www.dragino.com/downloads/downloads/LoRa_Gateway/LPS8/Firmware/Application_Note/MQTT_WebUserInterface-v0.3.pdf

この辺のマニュアルを読んでみると、Azureへの接続にはSASを利用しているように見えます。ただSASには有効期限があって、できるだけ短く(1時間とか)にするのがお作法のようで、設定しても1時間で繋がらなくなるなどになってしまうのでそれでは困るなーというわけでX.509証明書の方でやってみることにします(証明書も有効期限ありますがこちらは長く設定できるので)。

X.509証明書で接続するためにいろいろやんないといけないんですが、こちらのチュートリアルが比較的簡単に実行できました。

https://docs.microsoft.com/ja-jp/azure/iot-hub/tutorial-x509-scripts

上記チュートリアルを実行した前提で話を進めます。

接続には3つのファイルが必要になります。Azure の CA認証ファイル(ゲートウェイにデフォルトでインストールされている Azure.cer です)と、上記のチュートリアルで作成したデバイスの認証ファイル2つ(cert/new-device.cert.pem と private/new-device.key.pem)です。デバイスの認証ファイルはあらかじめゲートウェイにアップロードしておきます。

Azure設定画面を見てみると、CA認証ファイルの設定しかありません。やはりSASを利用する前提のようです。


ということで MQTT Server Profile を General に変更します。


ファイルは画面の設定のように選択しますが、User IDのところは {IoT hub name}.azure-devices.net/{device id} を設定します。

ここまでで設定は完璧です。完璧なんですが…

飛ばない… データ… いくら送っても… Azureまで飛んでこない… あう・・・

何で?特にエラー出るわけでもなく Azure のログにも大した情報は出ていない。ダメか、詰んだか。そういえば上のマニュアルで mqtt のサンプルコマンドが載ってたな。そうか、それを試すのだ。

ゲートウェイに SSH で接続して、コマンドで MQTT 送信してみます。

mosquitto_pub -d -h XXXX.azure-devices.net 
      -p 8883 -u XXXX.azure-devices.net/H0001 
      --cafile /etc/iot/cert/Azure.cer 
      --cert /etc/iot/cert/new-device.cert.pem 
      --key /etc/iot/cert/new-device.key.pem 
      -i H0001 
      -t devices/H0001/messages/events/ 
      -m "{ Hello }"

するとあれ?飛ぶぞ?えっ?えっ?
何が起きてるんだろう(まぁ、こんなことはよくあるけど)。マニュアルでは MQTT の処理は mqtt_process.sh がやってるとか書いてあった。じゃ何やってるかちょっと覗いてみるか。送信部分を抜粋。

# ------------------------------------------
# Call MQTT Publish command

# 1. Case with User, Password and Client ID present  (e.g. Azure)
if [ ! -z "$pass" ] && [ ! -z "$user" ] && [ ! -z "$clientID" ]; then
	case="1"  
	mosquitto_pub $D -h $server -p $port -q $pub_qos -i $clientID -t $pub_topic -u $user -P "$pass" $C $cafile $PUB_FLAG "$mqtt_data"
	
# 2. Case with Certificate, Key and ClientID present (e.g. AWS)
elif [ ! -z "$certfile" ] && [ ! -z "$key" ] && [ ! -z "$clientID" ]; then
	case="2"  
	mosquitto_pub $D -h $server -p $port -q $pub_qos -i $clientID -t $pub_topic --cert $cert --key $key $C $cafile $PUB_FLAG "$mqtt_data"
	
# 3. Case with no User, Certificate or ClientID present
elif [ -z "$user" ] && [ -z "$certfile" ] && [ -z "$clientID" ]; then
	case="3"  
	mosquitto_pub $D -h $server -p $port -q $pub_qos -t $pub_topic $PUB_FLAG "$mqtt_data" 
	
# 4. Case with no User, Certificate, but with ClientID present
elif [ -z "$user" ] && [ -z "$certfile" ] && [ ! -z "$clientID" ]; then
	case="4"  
	mosquitto_pub $D -h $server -p $port -q $pub_qos -i $clientID -t $pub_topic $PUB_FLAG "$mqtt_data"
	
# 5. Case with User and ClientID present, but no Password and no Certificate present
elif [ -z "$pass" ] && [ -z "$certfile" ] && [ ! -z "$user" ] && [ ! -z "$clientID" ]; then
	case="5"  
	mosquitto_pub $D -h $server -p $port -q $pub_qos -i $clientID -t $pub_topic -u $user $PUB_FLAG "$mqtt_data"
	
# 6. Case with User and Password present, but no ClientID and no Certificate present
elif [ ! -z "$user" ] && [ ! -z "$pass" ] && [ -z "$clientID" ] && [ -z "$certfile" ]; then
	case="6"  
	mosquitto_pub $D -h $server -p $port -q $pub_qos  -t $pub_topic -u $user -P "$pass" $PUB_FLAG "$mqtt_data"
	
# 0. Else - invalid parameters, just log
else
	case="Invalid parameters"  
	logger "[IoT.MQTT]:Invalid Parameters - mosquitto_pub not called."
fi
  
設定で処理が別れている様子。ログを見ると General の設定は case 2 にあたるようだ。よくみるとあれ? User IDの設定(-u)が無い! あー、それでかー、そんなことかー、ようやく原因がわかったー。おもむろに -u の設定を追加して保存。

これでようやく無事に送信はできるようになりました。

※注意 今回はアップリンクの話だけで、ダウンリンクはまだこれから試します。