IBM Watson IoT Platform の準備と MQTT pub/sub (ブラウザ Javascript)

# 目標
IBM Watson IoT Platform を MQTT Broker として準備し、
ブラウザの Javascript で pub/sub できるようになる。

# 知識材料 
## Watson IoT Platform ドキュメント
- [Watson IoT Platform について](https://console.bluemix.net/docs/services/IoT/iotplatform_overview.html#about_iotplatform)
- [Watson IoT Platform チュートリアル](https://console.bluemix.net/docs/services/IoT/getting-started.html)
- [アプリケーション、デバイス、ゲートウェイの接続](https://console.bluemix.net/docs/services/IoT/reference/security/connect_devices_apps_gw.html)
- [デバイスの MQTT 接続](https://console.bluemix.net/docs/services/IoT/devices/mqtt.html)
- [アプリケーションの MQTT 接続](https://console.bluemix.net/docs/services/IoT/applications/mqtt.html?locale=ja)

# 利用環境
- [IBM Watson IoT Platform (ライト・アカウント)](https://www.ibm.com/cloud-computing/jp/ja/lite-account/)
- [mqtt.js](https://www.npmjs.com/package/mqtt)

# 今回のゴール
ブラウザでJavascript を実行し、MQTT メッセージが送受信されることを確認する

# 実践
## Watson IoT Platform上のデバイスの準備
### 0.デバイスメニュー表示
Watson IoT Platform にログイン後、画面左のメニューから `[Devices]` をクリック。
![メニュー](https://dl.dropboxusercontent.com/s/ncs68c55hs52jaa/181210-00.png)

### 1.デバイスタイプの作成
#### 1-1.デバイスタイプ作成画面へ
画面上部 `Device Types` タブをクリック後、画面右上の `[+ Add Device Type]` ボタンをクリック。
![](https://dl.dropboxusercontent.com/s/1pogaqye4250tr4/181210-01.png)

#### 1-2.タイプ作成 (Add Type - Identity)
Type は `[Device]` を選択。（デフォルトで選択されている）
Name には、任意の文字列を入力する。
上記２つを設定したら、画面右の `[Next]` ボタンをクリック。
![](https://dl.dropboxusercontent.com/s/st6hmlx1f76bi1d/181210-02.png)

#### 1-3.タイプ作成 (Add Type - Device Information)
未入力のままで、画面右の `[Done]` ボタンをクリック。
![](https://dl.dropboxusercontent.com/s/ervivq7fwf44d5l/181210-03.png)

#### 1-4.タイプ作成完了 (You added the new device type : xxxx )
画面左側の `[Register Devices]` ボタンをクリック。
![](https://dl.dropboxusercontent.com/s/9pknz3emb0ug1ot/181210-04.png)

### 2.デバイスの作成
#### 2-1.デバイスID 設定 (Add Device - Identity)
Device Type は `1-2.タイプ作成` で入力したデバイスタイプが選択されていることを確認。
Device ID に `デバイスを識別する任意の文字列` を入力する。
上記２つを設定したら、画面右の `[Next]` ボタンをクリック。
![](https://dl.dropboxusercontent.com/s/0kkgmzy5we659z0/181210-05.png)

#### 2-2.デバイス情報 設定 (Add Device - DeviceInformation)
未入力のままで、画面右の `[Next]` ボタンをクリック。
![](https://dl.dropboxusercontent.com/s/o732qw0pvn27u8m/181210-06.png)

#### 2-3.トークン設定 (Add Device - Security)
MQTT 接続のパスワードとなるトークンを設定する。
`Authentication Token` について、

- 未入力の場合、トークンは、自動生成される。
- 任意の文字列を入力した場合、その文字列がトークンとして登録される。

設定したら、画面右の `[Next]` ボタンをクリック。
![](https://dl.dropboxusercontent.com/s/yd4pqooate20jdt/181210-07.png)

#### 2-4.デバイス情報 確認 (Add Device - Summary)
画面左側に今で入力した情報が表示されるので、確認後、画面右の `[Done]` ボタンをクリック。
![](https://dl.dropboxusercontent.com/s/9ek8gmf92rnb6kc/181210-08.png)

#### 2-5.デバイス情報 最終確認 (Device Credentials)
`2-3.トークン設定` でトークンが未入力だった場合、自動生成されたトークンがここで表示されるので、必ず控えておく。
この画面を閉じてしまうと、二度とトークンを確認できなくなるので注意。
![](https://dl.dropboxusercontent.com/s/97r8of2g7d57fnp/181210-09.png)


### 3.アプリケーションの作成
#### 3-1.アプリケーションメニュー表示
画面左のメニューから `[Apps]` をクリック。
![](https://dl.dropboxusercontent.com/s/ygzjr7gjxferuon/181210-10.png)

#### 3-2.アプリケーション作成画面へ
画面右上の `[+ Generate API Key]` ボタンをクリック。
![](https://dl.dropboxusercontent.com/s/p5upxa1cyo7e6tv/181210-11.png)

#### 3-3.アプリケーション 概要設定 (Generate API Key - Information)
必要であれば、`Description` に、アプリケーションの概要を入力。（未設定でも大丈夫）
設定したら、画面右の `[Next]`　ボタンをクリック。
![](https://dl.dropboxusercontent.com/s/cl97ek3f841ht9t/181210-12.png)

#### 3-4.アプリケーション 権限設定 (Generate API Key - Permissions)
Role を `[StandardApplication]` に設定する。
設定したら、画面右の `[Generate Key]`　ボタンをクリック。
![](https://dl.dropboxusercontent.com/s/y6yfzzpzbe7q1sv/181210-13.png)

#### 3-5.アプリケーション 最終確認 (The API key has been added.)
自動生成されたトークンがここで表示されるので、必ず控えておく。
設定したら、画面右の `[Close]`　ボタンをクリック。
![](https://dl.dropboxusercontent.com/s/fp45o809z69kfra/181210-14.png)

## プログラム作成
```html:index.html
<html>
    <head>
        <title>websocket</title>
    </head>
    <body>
        <!-- MQTT Client 
        // https://www.npmjs.com/package/mqtt
        -->
        <script src="https://unpkg.com/mqtt@2.15.1/dist/mqtt.min.js"></script>
        <script>
        //
        // デバイス情報
        //  TODO:// (2-5.デバイス情報 最終確認 を参照)
        var C_OrganizationID = "";
        var C_DeviceType = "";
        var C_DeviceID = "";

        var C_AuthenticationToken = "";

        //
        // アプリケーション情報
        //  TODO:// (3-5.アプリケーション 最終確認 を参照)
        var A_API_Key = "";
        var A_AuthenticationToken = "";

        var A_ApplicationID = "test001"; // ここは任意の文字列

        //
        // 今回使用するコマンドやフォーマット
        var msgCmd = "cmdTest";
        var msgFmt = "text";
        var msgPayload = "qiita=Love";

        // 接続先ホスト
        var hostname = `${C_OrganizationID}.messaging.internetofthings.ibmcloud.com`;

        //
        // アプリケーション側の配信
        function appClient_publish()
        {
            //
            // アプリケーション側のクライアントID
            var appclientId = `a:${C_OrganizationID}:${A_ApplicationID}`;

            // アプリケーションパブリッシュのトピックフォーマット
            var appTopic = `iot-2/type/${C_DeviceType}/id/${C_DeviceID}/cmd/${msgCmd}/fmt/${msgFmt}`;

            const appClient = mqtt.connect(`wss://${hostname}`, {
                'keepalive' : 120,
                'clientId' : appclientId, // 自分を示すＩＤ
                'username' : A_API_Key, 
                'password' : A_AuthenticationToken
            });
            // まず、セッションが確立できるかどうか
            appClient.on("connect", (connack) => {
                console.log("APP: connect success"); 
                // ブローカに接続できたら、パブリッシュ！
                appClient.publish(appTopic, msgPayload);
            });
        }


        //
        // デバイス側のクライアントID
        var devclientId = `d:${C_OrganizationID}:${C_DeviceType}:${C_DeviceID}`;

        // デバイスサブクライブのトピックフォーマット
        var devTopic = `iot-2/cmd/${msgCmd}/fmt/${msgFmt}`;

		// websockets SSL で接続します。
        const devClient = mqtt.connect(`wss://${hostname}`, {
            'keepalive' : 120,
            'clientId' : devclientId, // 自分を示すＩＤ
            'username' : "use-token-auth", // デバイスのusername は固定
            'password' : C_AuthenticationToken     
        });
		// まず、セッションが確立できるかどうか
        devClient.on("connect", (connack) => {
            console.log("DEV: connect success"); 
			// ブローカに接続できたら、サブスクライブ
            devClient.subscribe(devTopic, (err) => 
            {
                if( err ) {
					// なぜか購読できないとき（認証エラーとか？
                    console.log("DEV: ERROR: Subscribed!! ", err);
				}
                else {
                    console.log("DEV: Subscribed!! ");
                    // 購読の準備ができたら、自分でメッセージを一回、発行しちゃう
                    appClient_publish();
                }
            });
        });
			
		// publish されたメッセージを受け取るところ
        devClient.on("message", (topic, payload) => {
            // メッセージ受信できたよログ
            console.log( `DEV: MSG-Recv!! : ${payload}`);
        });

        </script>
    </body>
</html>
```

# 実行と結果
ブラウザのデバッグコンソールに以下のログが出力され、メッセージが送受信されていることを確認できる。
![](https://dl.dropboxusercontent.com/s/j782qxvud4cuuge/181210-15.png)

# まとめ
Topic や ClientID のフォーマットにルールがあることを理解できておらず、 IoT Platform の MQTT Broker に接続するまでに時間が掛かりましたが
Javascript でメッセージを送受信できることを確認できてよかった。

とうぜん、Javascript 以外の言語や、IoT デバイスとの通信も可能なので、活用していきたい。

# 参考にさせていただきました
[Watson IoT PlatformにDeviceを接続する際の設定 - Qiita](https://qiita.com/kuraoka/items/5380f6b5e97e8cd1ad98)