【今日から始めるAWS】AWS IoT Coreでpub/subする

#はじめに
30代未経験からエンジニアを目指して勉強中のYNと申します。
IoTの場面では、多対多の双方向通信が必要となります。これはWeb開発で一般的に使われる素のHTTP通信で実現することはできず、

* MQTT
* WebSocket
* MQTT over WebSocket

といった双方向通信プロトコルを使う必要があります。
[詳しくはコチラにまとめました。](https://qiita.com/theFirstPenguin/items/55dd1daa9313f6b90e2f)

今回は **AWS IoT CoreによるMQTTブローカーのマネージドサービス**使って2つのクライアント間でMQTTメッセージのやり取りを行います。
![Server architecture-Page-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/63c7b4b7-a022-dd3e-535f-75eacc714242.png)


#AWSコンソールで「モノ」を作成する
AWS IoT Coreのコンソール画面で「モノ」を登録します。

##証明書の種類の選択
このとき、「**新しい証明書を自動生成 (推奨)**」を選択します。
これが一番簡単です。他の選択肢について[こちらの動画の説明](https://youtu.be/gcJwNEQ2eLY)が分かりやすいです。

##policyの設定
ここが初学者には一番難しい部分でしょう。
今回`client1`でpublishしたメッセージを`client2`でsubscribeするためには、下記のjsonを参考にポリシーを設定して証明書にアタッチすることが必要です。
`us-east-2`と`123456780000`の部分をそれぞれ自身のリージョンとアカウントナンバーに書き換えてください。
コンソール画面でアドバンストモードを選べばjsonをそのまま編集することができます。

```.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:Connect"
      ],
      "Resource": [
        "arn:aws:iot:us-east-2:123456780000:client/client1",
        "arn:aws:iot:us-east-2:123456780000:client/client2"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:Publish"
      ],
      "Resource": [
        "arn:aws:iot:us-east-2:123456780000:topic/topic1"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:Subscribe"
      ],
      "Resource": [
        "arn:aws:iot:us-east-2:123456780000:topicfilter/topic1"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:Receive"
      ],
      "Resource": [
        "arn:aws:iot:us-east-2:123456780000:topic/topic1"
      ]
    }
  ]
}
```
詳しくは[こちらを参照ください](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/pub-sub-policy.html)

##証明書をダウンロード
先ほどのポリシーをアタッチした証明書を任意の場所にダウンロードします。
ポリシーは後から変更可能です。

#クライアントのコードを書く
クラウアントのコードを書きます。`aws-iot-device-sdk`を使えば`mqtt.js`の内容をラクチンに書けます。
[公式ドキュメントはこちら](https://github.com/aws/aws-iot-device-sdk-js#install)
##client1によるpublish
```client1.js
// AWS IoT DeviceSDKの利用
const awsIot = require('aws-iot-device-sdk');

// 秘密鍵、証明書などの設定
const device = awsIot.device({
  keyPath:
    './certs/xxxxxxx-private.pem.key', // ダウンロードした秘密鍵
  certPath:
    './certs/xxxxxxx-certificate.pem.crt', // ダウンロードした公開鍵
  caPath: './certs/AmazonRootCA1.cer', // ダウンロードしたルート証明書
  clientId: 'client1', // ポリシーで許可したユニークなクライアント名
  host: 'xxxxx.iot.us-east-2.amazonaws.com' // エンドポイント。コンソール画面でチェックできる
});

let count = 0;

// 通信確立した後、5秒ごとに呼び出されるイベント
device.on('connect', function () {
  console.log('connect');
  setInterval(function () {
    count++;
    device.publish('topic1', `hello!! ${count}`); // topic名もポリシーで許可したものを設定
    console.log(`published message for ${count} time`);
  }, 5000);
});
```

##client2によるsubscribe
```client2.js
const awsIot = require('aws-iot-device-sdk');

// 秘密鍵、証明書などの設定
const device = awsIot.device({
  keyPath:
    './certs/xxxxxxx-private.pem.key',
  certPath:
    './certs/xxxxxxx-certificate.pem.crt',
  caPath: './certs/AmazonRootCA1.cer',
  clientId: 'client2',
  host: 'xxxxx.iot.us-east-2.amazonaws.com'
});


// 通信確立時
device.on('connect', function () {
  console.log('connect');
  device.subscribe('topic1'); // topic1のsubscribeとrecieveをポリシーで許可する必要がある
});

// subscribeしたトピックにpublishされた時のイベント
device.on('message', function (topic, payload) {
  console.log('got message => ', topic, payload.toString());
});
```

##run code!!
これでメッセージの送受信ができます。簡単でしたね。

```bash
node client1.js
node client2.js
```