Greengrass(V1)のグループにデバイスを追加する

#はじめに
Greengrass(V1)は、Greengrassをインストールしたデバイス（コアデバイス）がMQTTブローカーの役割を果たし、グループ内のデバイス間でMQTTメッセージのやり取りを行うことができます。
今回は、Greengrassグループへのデバイスの追加とGreengrassデバイス間で通信をやり取りするまでを確認します。

以降、公式ドキュメントの以下を参考にしています。
参考：[モジュール 4: AWS IoT Greengrass グループでのデバイスの操作](https://docs.aws.amazon.com/ja_jp/greengrass/v1/developerguide/module4.html)
#1　Greengrassグループへのデバイス追加
Greengrassグループへのデバイス追加として、以下2つの手順を確認しました。

* Greengrassグループに新規のデバイスを追加
* モノとして登録済みのデバイスをGreengrassグループに追加

なお、今回はラズパイとMacをそれぞれ追加しています。
##1-1　新規のデバイスをグループに追加
IoT Coreに未登録のデバイスをGreengrassグループに追加します。

1.IoT Coreのマネジメントコンソールで左のメニューから Greengrass > クラシック(V1) > グループ の順にクリック
2.今回追加する対象のGreengrassグループをクリック
3.デバイス > 「デバイスの追加」の順にクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/ab94ff5b-d0a4-4629-1780-f2cbef9cbf64.png)
4.「新しいデバイスの作成」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/cd75d469-4d67-8fe8-f5fa-6fa8772a01f4.png)
5.任意の名前を入力して「次へ」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/245adf7d-2693-b3ae-4ccb-1821750b1919.png)
6.今回は1-clickデプロイを利用することとし、「デフォルトを使用」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/f9db7e14-28aa-4192-bd8d-172cc2753d74.png)
7.以下のファイルをダウンロードし、「完了」をクリック

* デバイス証明書、パブリックキー、プライベートキーをまとめたtar.gzファイル
* ルートCA　※[Amazon Root CA 1](https://www.amazontrust.com/repository/AmazonRootCA1.pem)をダウンロード

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/ad709fec-1db0-bd2b-bc65-3c1be94501b4.png)
8.完了すると、以下の通りグループにデバイスが追加される

* 作成時にポリシーが証明書にアタッチされ、証明書もアクティブになっている
* IoT Coreのモノとしても登録される
* Greengrass > クラシック(V1) > デバイス にはグループがデプロイされるまで表示されない

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/5895751e-52e1-31cb-477f-5fc3c157772d.png)
#1-2　モノと登録済のデバイスをグループに追加
既にIoT Coreにモノとして登録されているデバイスをGreengrassのグループに追加します。
なお、IoT Coreへのモノの登録方法はこちらをご参照ください。
参考：[AWS IoT Coreに「1-Click証明書作成」と「CSRによる作成」の2つの方法でプロビジョニングを実施してみる](https://qiita.com/kt-yt/items/936b2c80a7dedad83e7b)

1.IoT Coreのマネジメントコンソールで左のメニューから Greengrass > クラシック(V1) > グループ の順にクリック
2.今回追加する対象のGreengrassグループをクリック
3.デバイス > 「デバイスの追加」の順にクリック
4.「IoT Thingを選択する」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/cd75d469-4d67-8fe8-f5fa-6fa8772a01f4.png)
5.追加するモノを選択して「完了」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/a6857413-805e-b143-a7e9-5b5081321b92.png)
6.完了すると、グループにデバイスが追加される
#2　Greengrassデバイス間で通信
次にGreengrassデバイス間で通信できることを確認します。
今回は、AWS IoT Device SDK for Pythonの/samples/greengrass配下にある `basicDiscovery.py` を利用します。
GitHub：[AWS IoT Device SDK for Python](https://github.com/aws/aws-iot-device-sdk-python)
#2-1　グループのデプロイ
クラウドで行った設定をGreengrassコアデバイスにデプロイします。
また、デプロイ前にGreengrassデバイス間で通信できるよう、サブスクリプションの設定を行います。

1.IoT Coreのマネジメントコンソールで左のメニューから Greengrass > クラシック(V1) > グループ の順にクリック
2.対象のGreengrassグループをクリック
3.サブスクリプションをクリック
4.今回はgg-test-001がhell/world/pubsubにパブリッシュしたメッセージをgg-test-002でサブスクライブできるよう、以下の通り設定して「完了」をクリック

* ソース：gg-test-001
* ターゲット：hello/world/pubsub
* topic：gg-test-002

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/d7f82151-de43-4f76-ecec-e8eea162db1a.png)
5.サブスクリプションに追加されたことを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/216c8987-a932-c923-815a-5c37209184f1.png)
6.アクション > デプロイ の順にクリック
7.「正常に完了しました」と表示されることを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/a4e9e6cb-1428-e948-f8a9-ff7b8c8665fe.png)
#2-2　basicDicovery.py によるPub/Subの実施
`basicDiscovery.py` でGreengrassデバイス間の通信が出来ることを確認します。
参考：[通信をテストする](https://docs.aws.amazon.com/ja_jp/greengrass/v1/developerguide/test-comms.html)

1.「1-1　新規のデバイスをグループに追加」で取得したtar.gzファイルとルートCA証明書をGreengrassデバイスのディレクトリに格納する
※今回はMacにDeviceというディレクトリを作成して以降手順を実施
2.tar.gzファイルを解凍

```bash
cd Device
tar -xzf xxxxxxxxxx-setup.tar.gz
```
※解凍後、ディレクトリには以下のファイルが存在する

* xxxxxxxxxx-setup.tar.gz
* xxxxxxxxxx.private.key
* xxxxxxxxxx.public.key
* xxxxxxxxxx.cert.perm
* AmazonRootCA1.pem　※ルート証明書

3.AWS IoT Device SDK for Pythonをインストールする
※以降の作業はPublishするデバイス、Subscribeするデバイス双方ともに必要
参考：[をインストールするAWS IoT Device SDK for Python](https://docs.aws.amazon.com/ja_jp/greengrass/v1/developerguide/IoT-SDK.html)

```bash
#2.7未満、3.3未満の場合はバージョンアップが必要
 python --version

#OpenSSLは1.01以降が必要
python
>>>import ssl
>>>print ssl.OPENSSL_VERSION

#確認したらPythonシェルを終了
>>>exit()

#AWS IoT Device SDK for Pythonをインストールする 
cd ~

git clone https://github.com/aws/aws-iot-device-sdk-python.git

cd aws-iot-device-sdk-python

sudo python setup.py install
```
4.AWS IoT Device SDK for Pythonのサンプルコード `basicDicovery.py` を証明書を格納したディレクトリにコピーする

```
#証明書を格納したディレクトリに移動
cd /xxx/xxx/Device

#basicDicovery.py をコピー
cp ~/aws-iot-device-sdk-python/samples/greengrass/basicDicovery.py ./
```
5.AWS IoT Coreのマネジメントコンソールで左のメニューから設定をクリックし、エンドポイント情報をコピーする
※有効になっていない場合は有効にする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/a5379b68-b6f7-9212-a8af-6283b1026d79.png)
6.Publishを行う
※サブスクリプションでソースに指定したデバイスから実施

```python
python basicDiscovery.py --endpoint [エンドポイントのURL] \
 --rootCA [ルート証明書] --cert [デバイス証明書] --key [秘密鍵] \
 --thingName [モノの名前] --topic 'hello/world/pubsub' --mode publish \
 --message 'Hello World'

#成功すると以下のメッセージが "sequence"をインクリメントしながら流れ続ける（Ctrl + C で止まる）
2021-03-29 16:26:37,233 - AWSIoTPythonSDK.core.protocol.mqtt_core - INFO - Performing sync publish...
Published topic hello/world/pubsub: {"message": "Hello World", "sequence": 0}
```
7.Subscribeを行う
※サブスクリプションでターゲットに指定したデバイスから実施

```python
python basicDiscovery.py --endpoint [エンドポイントのURL] \
 --rootCA [ルート証明書] --cert [デバイス証明書] --key [秘密鍵] \
 --thingName [モノの名前] --topic 'hello/world/pubsub' --mode subscribe

#成功すると以下の通り、PublishされたメッセージをSubscribeしつづける（Ctrl + C で止まる）
2021-03-29 16:26:38,712 - AWSIoTPythonSDK.core.protocol.internal.workers - DEBUG - Produced [message] event
2021-03-29 16:26:38,712 - AWSIoTPythonSDK.core.protocol.internal.workers - DEBUG - Dispatching [message] event
2021-03-29 16:26:38,712 - AWSIoTPythonSDK.core.protocol.internal.clients - DEBUG - Invoking custom event callback...
Received message on topic hello/world/pubsub: b'{"message": "Hello World", "sequence": 1}'
```
#3　トラブルシューティング
上記の通り、`basicDiscovery.py` を実行した際に、Pub/Subともに以下の通りエラーが発生してしまいました（抜粋）。

* Pub側：`ConnectionRefusedError: [Errno 111] Connection refused`
* Sub側：`ConnectionRefusedError: [Errno 61] Connection refused`

Connectionが明示的に拒絶されているので、権限周り、接続設定を調べました。

* デバイス証明書が有効になっているか
* デバイス証明書にポリシーがアタッチされているか
* ポリシーは通信を許可しているか
* サブスクリプションの設定は間違っていないか

しかし、いずれも問題はありませんでした。
また、いずれのデバイスでもIoT Coreと直接やり取りする `basicPubSub.py` も実行し、こちらでは疎通が確認できました。
そのため、Greengrass側の設定ミスであることが分かります。
※`basicPubSub.py` もAWS IoT Device SDK for Pythonのサンプルコード

結果として、コマンド実行時の以下メッセージが解決の決め手になりました。

> Trying to connect to core at 127.0.0.1:8883

Greengrassコアデバイスに接続しに行くはずが、localhostのループバックアドレスに接続しようとしていました。
GreengrassデバイスはIoT CoreからGreengrassコアデバイスの情報を取得して、接続しにいきます。
そのため、IoT CoreのマネジメントコンソールでGreengrassのコア情報を確認すると以下の通りでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/13be0d30-6f91-e48a-29e0-f0c6aa95ae38.png)
ここの接続情報の一番上を使って接続しているようでした。

上記画面の編集をクリックし、127.0.0.1を削除してからコマンドを再度実行すると、エラーは解消されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001693/dbdb3667-a449-0bff-66f3-2a0d59e51e68.png)
#4　おわりに
Greengrassのグループへのデバイス追加、メッセージのやり取りまでを確認できました。
自動接続情報の検出で、127.0.0.1を拾ってきてしまうのは困りものですが、レアケースなのでしょうか？
ここはもう少し調べてみようと思います。