RaspberryPiをAWS IoTに繋いでenebularと連携する


`enebular`×`AWS IoT`×`RaspberryPi`の情報がすごく少なかったけど、使ってみたらすごい便利だったので備忘録的に連携方法を書いていきます。

# やりたいこと
enebularでRaspberryPi(ラズパイ)の開発をするとき、一々enebularで作ったフローをRaspberryPiのNode-REDにコピペするのがめんどかったので、enebularで作ったフローをAWS IoT経由でRapberryPiにDeployできるようにしてみます。

# メリット
**・開発環境を行き来する手間がなくなる！**
今まで`enebularでフローを編集して、RaspberryPiのnode-redにフローをコピペして・・・`という方法で開発していたんですが、そのようなenebularとラズパイのNode-REDの編集画面を行き来する手間ともおさらば、enebularの編集画面一つで開発できます。

**・プロジェクトの一括管理ができる！**
`最初からラズパイのNode-REDとenebularで別々にフロー作ればいいんじゃね？ 頑張ってenebularだけで編集する意味とは？`と思われるかもしれませんが、ラズパイ用のフローとenebularまたはその他のサービスのフローをenebular上では1つのプロジェクトとしてまとめて管理できます。全体を把握しやすく、コードも分散しないので管理が楽です。

**・遠隔からもデプロイできる！**
主にAWS IoTのおかげで、ラズパイがどこにあってもデプロイできます。なので遠くにセンサーの管理用などで設置したラズパイのフロー修正も簡単。固定IPも必要ないのが個人的に嬉しいところ。

#早速始める
AWS IoTについての確認や、AWSのアカウント作成など以下のページから事前に行っておきます。
>[AWS IoT Core](https://aws.amazon.com/jp/iot-core/)

AWS IoTとenebularの連携の仕方についてはenebular公式の以下のドキュメントに書かれています。
>[AWS IoT へのデプロイ](https://docs.enebular.com/ja/Deploy/DeployFlow/AWSIoT/)

しかし、RaspberryPiであればこのドキュメントの手順を踏まなくてもより簡単に連携できます！

# AWS IoT 用 IAM ユーザーの作成
まずは、AWS IoTとenebularの架け橋となるIAMユーザーの作成を行います。
これは簡単に言えば外部からAWS IoTを操作するためのアカウントのようなものです。
ユーザの作り方は基本的に[enebular公式ドキュメント](https://docs.enebular.com/ja/Deploy/DeployFlow/AWSIoT/)の`AWS IoT用 IAMユーザーの作成`の項目の通りなので説明は割愛します。
公式ドキュメントにも書いていますが、登録の最後に**`アクセスキーID と シークレットアクセスキー が記載された CSVファイルのダウンロード`**は必ず行うようにしてください。

# AWS IoTとRaspberryPiを繋げる
さて、RaspberryPiはここが簡単。
ラズパイに限らず、最終的に`enebular`×`AWS IoT`×`デバイス`の連携を達成するには、

```
1. AWS IoTでモノの作成
2. 証明書の作成
3. ポリシーの作成
4. 証明書へのポリシーのアタッチ
5. デバイス（エージェント）のセットアップ
6. フローに AWS IoT の設定を反映
```
と、やることがいっぱいなのですが、RaspberryPiは[enebular-runtime-agent(公式)](https://github.com/enebular/enebular-runtime-agent/blob/master/tools/install/README.ja.md)のインストールスクリプトを一つ実行するだけで上記の1~5あたりまでをやってくれます。便利。
で、実際に実行するインストールスクリプト例は以下のようになります。

```bash:InstallScript
ssh -t pi@raspberrypi.local \
"wget -qO- https://raw.githubusercontent.com/enebular/enebular-runtime-agent/master/tools/install/install.sh | sudo -E bash -s -- \
--aws-iot-thing-name=raspberry-pi \
--aws-access-key-id=<my-key-id> \
--aws-secret-access-key=<my-access-key> \
--aws-iot-region=ap-northeast-1"
```
以上のコードの`<my-key-id>` `<my-access-key>`の部分を先ほど作成したIAMユーザの`Access key ID` `Secret access key`(ダウンロードしたCSVに書いてる)に書き換えて、RaspberryPiにSSH接続できる端末から実行します。**(RaspberryPi上で実行するわけではないことに注意)**
RaspberryPi上で直接`wget -qO- ...`と打ってもインストールできますが、IAMのIDやアクセスキーがデバイスのbash履歴に記録されるのでセキュリティ上好ましくないとされています。

### インストールスクリプトについて若干解説
・格行末にある`\`は行継続文字です、複数行のコマンドを繋げて1行の命令とみなします。見やすくするためにつけているだけなのであまり気にしないでください。
・`pi@raspberrypi.local`の部分は自分のラズパイの`<user>@<device-ip-address>`に合わせてください。
・`--aws-iot-thing-name=`はAWS IoTに作成される`モノ`の名前になります。今回は`raspberry-pi`にしていますが好きな名前をつけて大丈夫です。
・`--aws-iot-region=`は簡単に言えば、今回の場合デバイスを登録・管理するデータセンターの指定です。
今回指定している`ap-northeast-1`はアジアパシフィック (東京)のリュージョンですが、対応している地域ならどこのリュージョンを指定しても特に問題はありません。
[AWSの対応リュージョン一覧はここで見れます。](https://docs.aws.amazon.com/ja_jp/general/latest/gr/rande.html)

### 確認
**AWS IoT側**
インストールスクリプトが無事に実行完了していればAWS IoTの[管理]-[モノ]の項目に「raspberry-pi」が追加されていると思います。
インストールが正しく実行できたのに表示されない場合は、この画面の右上の地域名がリュージョンで指定した地域名と同じ(今回は東京)になっていることを確認しましょう。
 <img width="500" alt="mono" src="https://qiita-image-store.s3.amazonaws.com/0/259617/7543b803-79a4-177a-47ee-28c3f050bef9.png">

**RaspberryPi側**
エージェントがインストールされるとデフォルトで「enebular」というユーザが作成されます。

```bash:
$ ls /home
enebular  pi
```

で、エージェントの実行状態を確認するには以下のコマンドを打ちます。

```bash:
sudo journalctl -ex -u enebular-agent-<user>.service
```

ユーザはデフォルトのままなら「enebular」のはずなので以下のコマンドで確認できます。

```bash:
sudo journalctl -ex -u enebular-agent-enebular.service
```

色々とログが出ますが、この中に`「Connected to AWS IoT」`の文字があればAWS IoTとの連携に成功しています。ログが多すぎて目視で探すのは大変なので`grep`を使いましょう。

```bash:
sudo journalctl -ex -u enebular-agent-enebular.service | grep "Connected to AWS IoT"
```
これで`「Connected to AWS IoT」`の文字がヒットすればOKです。
ちなみに`enebular-agent`はデフォルトでスタートアップ登録されるので、ラズパイを起動すると自動的にエージェントも起動しますし、ノードも実行されます。

# AWS IoTとenebularを連携させる
さて、いよいよenebularと連携します！
### AWS IoTの情報をenebularに登録
プロジェクト画面の左側、[Connections]を選択して、右下の＋ボタンを押します。
<img width="500" alt="Connections" src="https://qiita-image-store.s3.amazonaws.com/0/259617/3d80a6b7-2767-6275-0004-9efb50a3e995.png">
または、フローの管理画面の[Deploy]タブの[Deploy]ボタンを押して出てくる[Add Connection]を選択してもOKです。
<img width="500" src="https://qiita-image-store.s3.amazonaws.com/0/259617/786cd272-f200-3b64-3df9-9d77f8faa3cd.png">
そうすると[Connection Type]の選択が出るので`[AWS IoT]`を選択しましょう
<img width="350" src="https://qiita-image-store.s3.amazonaws.com/0/259617/1a4d075c-eef0-44ff-f904-55d75f78050f.png">
必要な情報を打ち込んでいきます。
<img width="350" src="https://qiita-image-store.s3.amazonaws.com/0/259617/f105c866-e62d-8b91-7280-7f1de1b4b398.png">

|設定項目|内容|
|:-:|:--|
|Connection Name|任意の名前(英数字)|
|AWS Access Key ID|IAMのID (CSVに記載されてる)|
|AWS Secret Access Key|IAMのKey (CSVに記載されてる)|
|Region|設定したリュージョン|
|AWS IoT Endpoint URL|モノのメニューの操作より確認（下の画像参照）|
<img width="500" src="https://docs.enebular.com/ja/_asset/images/Deploy/DeployFlow/AWSIoT/deploy-deployflow-awsiot_36.png">
※↑公式ドキュメントより引用
`Endpoint URL`はモノの[操作]の項目に記載されているURLであって、[詳細]に記載されている[モノのARN]出ないことに注意。（1回間違えた）

# Deploy!!
さて、これで全ての作業が終わりました！
試しにenebular→AWS IoT→RaspberryPi に Deployしてみます。
以下のような適当なフローを作って・・・

<img width="400" src="https://qiita-image-store.s3.amazonaws.com/0/259617/a386ebd6-0dc2-578a-cd44-144116d9289b.png">

```json:
[
    {
        "id": "3fa104ec.acf80c",
        "type": "tab",
        "label": "Flow 1"
    },
    {
        "id": "be62a9d.01d5358",
        "type": "http in",
        "z": "3fa104ec.acf80c",
        "name": "",
        "url": "/test",
        "method": "get",
        "swaggerDoc": "",
        "x": 120,
        "y": 80,
        "wires": [
            [
                "4f075244.96521c"
            ]
        ]
    },
    {
        "id": "7b28b075.8c7a9",
        "type": "http response",
        "z": "3fa104ec.acf80c",
        "name": "",
        "x": 410,
        "y": 80,
        "wires": []
    },
    {
        "id": "4f075244.96521c",
        "type": "template",
        "z": "3fa104ec.acf80c",
        "name": "",
        "field": "payload",
        "fieldType": "msg",
        "format": "handlebars",
        "syntax": "mustache",
        "template": "Hello AWS IoT & RaspberryPi !",
        "x": 270,
        "y": 80,
        "wires": [
            [
                "7b28b075.8c7a9"
            ]
        ]
    }
]
```
普通に[Deploy]した後に、デプロイボタンの横にある矢印を押して、[Export to Other Service]を選択します。
<img width="305" src="https://qiita-image-store.s3.amazonaws.com/0/259617/348e5e08-07b9-1a42-fbb4-be87f5c8b9f1.png">
自分が作成したコネクションを選択し、[Target]から自分が登録したモノを指定して**`deploy!`**
<img width="662" src="https://qiita-image-store.s3.amazonaws.com/0/259617/4b5ed9d3-323b-dfa6-85d0-9a3fb6c6dc63.png">
以下のように[Deploy Status]にチェックマークがつけばDeploy成功です！
<img width="780" src="https://qiita-image-store.s3.amazonaws.com/0/259617/c4892d20-0f9a-88d4-1d0a-e9deecda9216.png">

RaspberryPi側でエージェントの実行状態を確認してみます。

```bash:
sudo journalctl -ex -u enebular-agent-enebular.service
```
以下のように転送したフローのJSONがログに記録されているので無事転送されたことが確認できます。
<img width="500" src="https://qiita-image-store.s3.amazonaws.com/0/259617/3d68d649-b1fd-f38f-b1e3-37e19d07606b.png">

試しにラズパイの`/test`にHTTPリクエストを送ると以下のように表示されます!
<img width="500" src="https://qiita-image-store.s3.amazonaws.com/0/259617/7ff08773-0409-d0db-4102-bf80ba679893.png">

これのおかげでだいぶ開発が楽になりました。
AWSは新規登録してから12ヶ月間は基本的に無料なので試しに使ってみる価値はあると思います！