2016年8月24日水曜日

MQTT理解(publisher/subscriber: ruby利用、broker: Bluemixサービス)


◆ 目的
IoTやM2Mで使われるpublisherとsubscriberモデルの軽量なメッセージプロトコルであるMQTTの動作をrubyクライアントを使い確認する。rubyのmqttライブラリはこちらを使う。

brokerとなるサーバは構築の手間を省くため、IBM Bluemix上にあるサービス、Internet of Things Platform を利用する。



◆ publisher接続仕様
IBMが提供するIoTのbrokerの作法の詳細はこちら
以下ではコードを書く上で必要なところを抽出してまとめる。

(フォーマット)
● 認証(ユーザ)     : use-token-auth(固定値)
     (パスワード)   : デバイス登録時に払い出されるトークン

● Client ID      : d:{org_id}:{device_type}:{device_id}

● Topic(event)   : iot-2/evt/{event_id}/fmt/{format}
       (command) : iot-2/cmd/{command_id}/fmt/{format}
                   今回はeventトピック(commandではない)のフォーマットを利用する

{}の各変数はそれぞれ以下の意味である。
org_id           : brokerが払い出し(接続先エンドポイントのURIに付与される)
device_type      : 任意のものを作成
                   ここではラズベリーパイを使うことを想定しraspiとする
device_id        : デバイス単位で固有の値を任意に作成

event_id         : 任意のものを作成(ここではtype01とする)
command_id       : 任意のものを作成
format           : jsonとする

下記変数部分は文字列ワイルドカード文字(+)を使用することができる。
device_type、device_id、event_id、format



◆ subscriber接続仕様
(フォーマット)
● 認証(ユーザ)      : APIキー(broker管理画面で作成)
     (パスワード)    : APIトークン(broker管理画面で作成)

● Client ID       : a:{org_id}:{app_id}

● Topic(event)    : iot-2/type/{device_type}/id/{device_id}/evt/{event_id}/fmt/{format}
     (command)    : iot-2/type/{device_type}/id/{device_id}/cmd/{command_id}/fmt/{format}

{}の各変数はそれぞれ以下の意味である。
app_id            : 任意のものを作成(ここではapp01とする)

下記変数部分は文字列ワイルドカード文字(+)を使用することができる。
device_type、device_id、cmd_id、format



◆ publisherコード
#!/usr/bin/ruby
require 'mqtt'
require 'json'
org_id = "*****"
mqtt_host = "#{org_id}.messaging.internetofthings.ibmcloud.com"
mqtt_port = 1883
device_type = "raspi"
device_id = "12345"
client_id = "d:#{org_id}:#{device_type}:#{device_id}"
device_user = "use-token-auth"
device_token = "*****"
client = MQTT::Client.connect(
:host => mqtt_host,
:port => mqtt_port,
:username => device_user,
:password => device_token,
:client_id => client_id
)
msg = JSON.generate({
"d" => {
"test_data" => 10
}
})
event_id = "type01"
format = "json"
#EVENT TOPIC
topic = "iot-2/evt/#{event_id}/fmt/#{format}"
#COMMAND TOPIC
#topic = "iot-2/cmd/#{command_id}/fmt/#{format}"
client.publish(topic, msg)
client.disconnect
view raw publisher.rb hosted with ❤ by GitHub



◆ subscriberコード
#!/usr/bin/ruby
require 'mqtt'
require 'json'
org_id = "*****"
mqtt_host = "#{org_id}.messaging.internetofthings.ibmcloud.com"
mqtt_port = 1883
service_api_key = "*****"
service_token = "*****"
device_type = "raspi"
device_id = "12345"
app_id = "app01"
client_id = "a:#{org_id}:#{app_id}"
client = MQTT::Client.connect(
:host => mqtt_host,
:port => mqtt_port,
:username => service_api_key,
:password => service_token,
:client_id => client_id
)
event_id = "type01"
format = "json"
# EVENT TOPIC
topic = "iot-2/type/#{device_type}/id/#{device_id}/evt/#{event_id}/fmt/#{format}"
#topic = "iot-2/type/#{device_type}/id/+/evt/#{event_id}/fmt/#{format}"
#COMMAND TOPIC
#topic = "iot-2/type/#{device_type}/id/#{device_id}/cmd/#{command_id}/fmt/#{format}"
client.subscribe(topic)
client.get do |topic,message|
# Block is executed for every message received
p topic
p message
end
view raw subscriber.rb hosted with ❤ by GitHub



◆ 試験
1.
$ ./subscriber.rb
待ち

2.
$ ./publisher.rb

3.
subscriber.rbのプロンプトへ以下が出力される。
"iot-2/type/android/id/12345/evt/type01/fmt/json"
"{\"d\":{\"test_data\":10}}"