AWS IoT Core と MQTTクライアント (mosquitto/paho)の疎通

# 概要
* AWS IoT CoreとMQTTクライアントの最も簡単な結合確認を行う
* MQTTクライアントには既成の[mosquitto](https://mosquitto.org/)、[paho](https://www.eclipse.org/paho/)を利用
    * MQTT publisher (mosquitto_pub.exe)は、MQTTクライアントからAWS IoTに向けてのpublish送信を確認する。
    * MQTT subscriber (mosquitto_sub.exe, paho_cs_sub)は、AWS IoTへのsubscribe実行とpublish受信を確認する。

# 前提知識
### AWS IoT
* インターネットに接続されたデバイスとAWS クラウドとの**セキュア**な**双方向通信**が可能になります。
    * 複数のデバイスからテレメトリデータを収集し、保存して、分析できます。
    * これらのデバイスをユーザーが各自の電話やタブレットから制御できるようにするアプリケーションを作成することもできます。
* 構成要素
    * Things: AWS IoTに接続されるデバイスまたは論理エンティティ
    * Policy: １つ以上のデバイスについて、AWS IoT Coreオペレーション(接続、subscribe, publish)の許可を定義する。
    * Broker/Publisher/Subscriber: AWS IoTとThingsの間の相互メッセージングをMQTTのPub/Subで実現する。接続、メッセージを管理するBroker（サーバ）機能をAWS IoT Coreが内包している。

## [MQTT](http://mqtt.org/)
* Pub/Sub形式による双方向メッセージプロトコル(OASIS標準)。最新バージョンはv5.0。
* AWS IoT Coreはv3.1.1に対応しているが、一部[仕様機能差分](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/mqtt.html)あり。

# 環境
* 今回目指す結合環境は以下の通り、最もシンプルな構成。

![environment1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/6a57a81a-8bb0-5527-3845-97755aae87cc.png)


# AWS IoT Consoleへのログイン
1. AWSコンソールにログインし、Servicesメニューから「Internet Of Things」/「IoT Core」を選択する
    
![login.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/1f3ecf30-1e12-1b45-1e77-c9cb51af4bb6.png)

# デバイスの準備
## ポリシーの作成（後の作成デバイスへアタッチされる）
1. Secure/Policiesを開き、「Create」を押下

![create_policy1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/937f2658-f79e-9656-3e3d-8914da041a06.png)

2. 以下を入力し、「Create」を押下
    * Name: mqtt_client_policy
    * Action: iot:*
    * Resource ARN: *
    * Effect: Allow

![create_policy2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/7beb2eca-fb89-f26e-d614-4151062f5c0b.png)

## Things(=デバイス、モノ）を作成
1. Manage/Thingsを開く
2. 「Create」を押下

![things_create1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/6bb14b22-cc9b-9694-3468-63857d2df3c8.png)

3. 「Create a single things」を押下 

![things_create2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/91e14c11-4757-b2e1-c4b8-b28bca8c577d.png)


4. 「Name」にデバイスを識別する名前を入れ「ex. device_mosquitto_windows10」、「Next」を押下

![things_create3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/eee8156b-4ed2-6154-e7c0-4918520e61a2.png)

5. 証明書を作成する。One-click certificate creation(recommended)の「Create certificate」を押下

![certificates_create1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/6e59cb0d-3811-2e56-fa72-bea993e39ef2.png)

6. 証明書一覧のDownloadリンクから各種証明書、キーをダウンロードする。
    * （上から）クライアント証明書
    * クライアント証明書の公開キー
    * クライアント証明書の秘密キー
    * ルート証明書（リンク先からAmazon Root CA 1をダウンロード）

    1. 「Active」を押下し、このデバイスへの証明書アサインを有効化する。

![certificates_create2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/9c1f3601-5037-c1d1-a308-6db229f9f8ab.png)

    
    2. 「Attach a policy」を押下

7. デバイスへのポリシーを割り当て、「Regstre Things」を押下

![add_a_policy_to_devices.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/ff2cddaf-4e08-4b67-d9cd-bbef300ba627.png)

![things_registered.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/f5dd512c-8b0a-9f16-13c0-3619c93087ca.png)

## MQTTクライアント環境の構築(mosquitto)
1. カスタムエンドポイントを確認
    1. AWS-IoTにあるbrokerへのURLはカスタムエンドポイントとして設定されている。
    2. これまでの過程でカスタムエンドポイントは既に作られている
    3. Setteings/Custom endpointを確認する。

![custom_endpoint.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/92732b26-18cf-0c7c-80aa-874d99c0a07a.png)

2. cygwin上で任意ディレクトリ (ex. /cygdrive/c/work/Git/TechNotes/AWS_IoT/AWS_IoT_Mqtt_howto)を作成
3. Things作成で作られたクライアント証明書、各種キー、ルート証明書を配置
    
```
    -rwxrwx---+ 1 hoge.hoge Domain Users 1188 2月  10 15:12 AmazonRootCA1.pem
    -rwxrwx---+ 1 hoge.hoge Domain Users 1224 2月  10 15:10 d3ab1602bc-certificate.pem.crt
    -rwxrwx---+ 1 hoge.hoge Domain Users 1679 2月  10 15:10 d3ab1602bc-private.pem.key
    -rwxrwx---+ 1 hoge.hoge Domain Users  451 2月  10 15:10 d3ab1602bc-public.pem.key
    
```

4. publish実行シェルを作成
    1. mosquitto_pub.exeへの実行パスを設定
    2. mosquitto_pub_aws_iot.shを作成
        * cafileにルート証明書を指定
        * certfileにクライアント証明書を指定
        * keyfileにクライアント秘密キーを指定
        * hostにカスタムエンドポイントを指定
        * deviceにデバイス作成で指定したデバイス名を指定
        * topicにbrokerにサブスクライブされている任意のトピック名を指定
            * サブスクライブ設定はpublish疎通で後述
        * qosを指定 (0か1のみ)
        * publishするmessageを指定 (json形式か任意の文字列)


        ```
        #!/bin/sh

        DEVICE_PATH=.

        cafile=$DEVICE_PATH/AmazonRootCA1.pem
        certfile=$DEVICE_PATH/XXXXXXXX-certificate.pem.crt
        keyfile=$DEVICE_PATH/XXXXXXXX-private.pem.key

        host=XXXXXXXX-ats.iot.ap-northeast-1.amazonaws.com

        port=8883
        device="device_mosquitto_windows10"
        topic="aws/things/topic/test"
        qos=1
        message="{'test':'message'}"

        mosquitto_pub.exe --cafile $cafile --cert $certfile --key $keyfile -q $qos -h $host -p $port -t $topic -q $qos -i $device -m $message -d        
        ```

5. subscribe実行シェルを作成
    1. mosquitto_sub.exeへの実行パスを設定
    2. mosquitto_sub_aws_iot.shを作成
        * cafileにルート証明書を指定
        * certfileにクライアント証明書を指定
        * keyfileにクライアント秘密キーを指定
        * hostにカスタムエンドポイントを指定
        * deviceにデバイス作成で指定したデバイス名を指定
        * topicにbrokerにサブスクライブする任意のトピック名を指定
        * qosを指定 (0か1のみ)

        ```
        #!/bin/sh

        DEVICE_PATH=.

        cafile=$DEVICE_PATH/AmazonRootCA1.pem
        certfile=$DEVICE_PATH/XXXXXXXX-certificate.pem.crt
        keyfile=$DEVICE_PATH/XXXXXXXX-private.pem.key

        host=XXXXXXXX-ats.iot.ap-northeast-1.amazonaws.com

        port=8883
        device="device_mosquitto_windows10"
        topic="aws/things/topic2/test"
        qos=1

        mosquitto_sub.exe -d --cafile $cafile --cert $certfile --key $keyfile -q $qos -h $host -p $port -t $topic -i $deviceos -i $device -m $message -d        
        ```

## MQTTクライアント環境の構築(paho)
1. カスタムエンドポイント、クライアント証明書、各種キー、ルート証明書配置はmosquitto同様
2. subscribe実行シェルを作成
    1. paho_cs_subへの実行パスを設定
    2. paho共有ライブラリパスをLD_LIBRARY_PATHに設定
    2. mosquitto_sub_aws_iot.shを作成
        * cafileにルート証明書を指定
        * certfileにクライアント証明書を指定
        * keyfileにクライアント秘密キーを指定
        * hostにカスタムエンドポイントを指定
        * deviceにデバイス作成で指定したデバイス名を指定
        * topicにbrokerにサブスクライブする任意のトピック名を指定
        * qosを指定 (0か1のみ)

        ```
        #!/bin/sh

        DEVICE_PATH=.

        cafile=$DEVICE_PATH/AmazonRootCA1.pem
        certfile=$DEVICE_PATH/XXXXXXXX-certificate.pem.crt
        keyfile=$DEVICE_PATH/XXXXXXXX-private.pem.key

        host=XXXXXXXX-ats.iot.ap-northeast-1.amazonaws.com
        port=8883
        device="device_mosquitto_windows10"
        topic="aws/things/topic2/test"
        qos=1
        tracelevel=min

        PAHO_DIR=~/paho.mqtt.c/build/output
        export LD_LIBRARY_PATH=$PAHO_DIR

        $PAHO_DIR/samples/paho_cs_sub --cafile $cafile --cert $certfile --key $keyfile -q $qos -c ssl://$host:$port -t $topic -i $device --trace protocol
                                                                    
        ```

## MQTTクライアント(mosquitto/publisher)との疎通テスト
1. AWS IoTのTest機能でサブスクリプションを登録する
    1. Testを開き、以下を入力する
        * Subscription topic: 購読可能な任意トピック名 (ex. aws/things/topic/test)
            * publish実行シェル(mosquitto_pub_aws_iot.sh) のtopicで指定
        * Quiality of Service
            * 0/1: 今回ロストさせたくないため1を指定
            * MQTT payload display: JSON解析エラー抑制のため文字列指定
    2. 「Subscrive to topic」を押下

![test_subscription1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/1bc75acb-11d2-34d7-0f26-594a39798383.png)

2. デバイス側(windows10)でpublish実行シェルを実行
    1. [MQTTクライアント環境の構築(mosquitto)](#MQTTクライアント環境の構築(mosquitto))で構築したpublish実行シェルを実行

        ```
        $ ./mosquitto_pub_aws_iot.sh
        Client device_mosquitto_windows10 sending CONNECT
        Client device_mosquitto_windows10 received CONNACK (0)
        Client device_mosquitto_windows10 sending PUBLISH (d0, q1, r0, m1, 'aws/things/topic/test', ... (18 bytes))
        Client device_mosquitto_windows10 received PUBACK (Mid: 1, RC:0)
        Client device_mosquitto_windows10 sending DISCONNECT
        ```

    2. AWS IoTコンソールのTest/MQTT clientの該当トピック画面にpublishメッセージが表示される

![test_subscription_published.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/30ffc939-b51b-e199-7c0c-8043d2bd6aa4.png)


## MQTTクライアント(mosquitto/subscriber)との疎通テスト
1. デバイス側(windows10)でsubscribe実行シェルを実行
    1. [MQTTクライアント環境の構築(mosquitto)](#MQTTクライアント環境の構築(mosquitto))で構築したsubscribe実行シェルを実行

        ```
        $ ./mosquitto_sub_aws_iot.sh
            （実行後、publishするまでは表示無で待ち状態）
        ```

    2. AWS IoTコンソールのTest/MQTT clientのPublish欄で、subscriberが購読したtopic(aws/things/topic2/test)を指定し、「Publish to topic」を押下

![test_subscription_publish.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282300/744df4a0-645a-4164-c0eb-bdb9074ec631.png)
    3. subscribe実行シェルがpublishメッセージを受信している。
    
```
        Client device_mosquitto_windows10 sending CONNECT
        Client device_mosquitto_windows10 received CONNACK (0)
        Client device_mosquitto_windows10 sending SUBSCRIBE (Mid: 1, Topic: aws/things/topic2/test, QoS: 1, Options: 0x00)
        Client device_mosquitto_windows10 received SUBACK
        Subscribed (mid: 1): 1
        Client device_mosquitto_windows10 received PUBLISH (d0, q0, r0, m0, 'aws/things/topic2/test', ... (45 bytes))
        {
        "message": "Hello from AWS IoT console"
        }
```

## MQTTクライアント(paho_cs_sub)との疎通テスト
1. デバイス側(Linux)でsubscribe実行シェルを実行
    1. [MQTTクライアント環境の構築(paho)](#MQTTクライアント環境の構築(paho))で構築したsubscribe実行シェルを実行

        ```
        $ ./paho_cs_sub_iot.sh 
        Trace : 3, =========================================================
        Trace : 3,                    Trace Output
        Trace : 3, Product name: Eclipse Paho Synchronous MQTT C Client Library
        Trace : 3, Version: 1.3.1
        Trace : 3, Build level: 2020年  2月  5日 水曜日 14:55:51 JST
        Trace : 3, OpenSSL version: OpenSSL 1.1.1  11 Sep 2018
        Trace : 3, OpenSSL flags: compiler: gcc -fPIC -pthread -m64 -Wa,--noexecstack -Wall -Wa,--noexecstack -g -O2 -fdebug-prefix-map=/build/openssl-kxN_24/openssl-1.1.1=. -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DRC4_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX2
        Trace : 3, OpenSSL build timestamp: built on: Tue Nov 12 16:58:35 2019 UTC
        Trace : 3, OpenSSL platform: platform: debian-amd64
        Trace : 3, OpenSSL directory: OPENSSLDIR: "/usr/lib/ssl"
        Trace : 3, /proc/version: Linux version 5.3.0-28-generic (buildd@lcy01-amd64-009) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #30~18.04.1-Ubuntu SMP Fri Jan 17 06:14:09 UTC 2020

        Trace : 3, =========================================================

        (...snip...)

        Trace : 4, 20200212 180046.831 SSL certificate verification: X509_V_OK
        Trace : 4, 20200212 180046.831 SSL connect:SSL negotiation finished successfully
        Trace : 4, 20200212 180046.831 peername from X509_check_host is *.iot.ap-northeast-1.amazonaws.com
        Trace : 4, 20200212 180046.832 3 device_mosquitto_windows10 -> CONNECT version 4 clean: 1 (0)
        Trace : 4, 20200212 180046.942 3 device_mosquitto_windows10 <- CONNACK rc: 0
        Trace : 4, 20200212 180046.943 3 device_mosquitto_windows10 -> SUBSCRIBE msgid: 1 (0)
        Trace : 4, 20200212 180047.005 3 device_mosquitto_windows10 <- SUBACK msgid: 1

        ```

    2. AWS IoTコンソールのTest/MQTT clientのPublish欄で、subscriberが購読したtopic(aws/things/topic2/test)を指定し、「Publish to topic」を押下
        * [MQTTクライアント(mosquitto/subscriber)との疎通テスト](#MQTTクライアント(mosquitto/subscriber)との疎通テスト)と同様

    3. subscribe実行シェルがpublishメッセージを受信している。
        
```
        Trace : 4, 20200212 180411.498 3 device_mosquitto_windows10 -> PINGREQ (0)
        Trace : 4, 20200212 180411.539 3 device_mosquitto_windows10 <- PINGRESP
        Trace : 4, 20200212 180421.531 3 device_mosquitto_windows10 -> PINGREQ (0)
        Trace : 4, 20200212 180421.554 3 device_mosquitto_windows10 <- PINGRESP
        Trace : 4, 20200212 180424.729 3 device_mosquitto_windows10 <- PUBLISH msgid: 0 qos: 0 retained: 0 payload: {
        "message": "Hell
        {
        "message": "Hello from AWS IoT console"
        }
        
```