M5StickCを使って外出先からお家のエアコンを操作（後編）

[前編](https://qiita.com/jonxjon/items/af698107047e91d6a56f)では、M5StickC・AWS IoT Core の設定をしました。
後編では、AWS Lambda・Amazon API Gateway・Slack API の部分を作っていきます。

# やりたいことのイメージ（再掲）
### イメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/09f587bb-a5e9-3103-bfdc-d7c728e6dc7e.png)

### 処理の流れ
1. Slack 上で Bot にメッセージを送る
1. Slack Bot が Amazon API Gateway が発行した API を叩く
1. Amazon API Gateway をトリガーにして、Lambda function が実行される
1. Lambda function が AWS IoT Core にメッセージを格納する（Publish する）
1. M5StickC が AWS IoT Core に定期的にメッセージをとりに行く（Subscribe する）
1. M5StickC が 受信したメッセージに応じて、エアコンのリモコン操作を実行する（赤外線を照射する）

※前編には6,5を実装する手順を記載し、後編には4,3,2を実装する手順を記載します。

### エアコンのリモコン操作の種類
- Cool：電源オン（冷房）
- Heat：電源オン（暖房）
- Stop：電源オフ


# 目次
1. Lambda function の作成
1. Amazon API Gateway の作成
1. Slack API の作成

# 1. Lambda function の作成
### 関数を作成する
AWSコンソールにサインインし、画面上部の検索欄に「Lambda」と入力し、[サービス]-[Lambda]をクリックします。
[関数の作成]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/33b0e182-ed01-b071-a616-57032294bb62.png)

「一から作成」を選択し、任意の関数名を入力します。ここでは「M5StickC_Publish」と入力します。ランタイムは「Python」を選択して、[関数の作成]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/8d1a622c-a23e-f1f1-a692-7ff8ce822b6d.png)

関数が作成されると、画面上にデフォルトのプログラムコードが表示され、そのまま画面上で編集できる状態となります。デフォルトのプログラムコードは削除します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/09c9957c-deac-c12f-ee4c-dda514be5d92.png)

### コードを書く
##### 環境ごとの設定
以下の部分は自分の環境に合わせて書く必要があります。
```c
iot = boto3.client("iot-data", endpoint_url='https://xxxxxxxxxxx-ats.iot.<region>.amazonaws.com')
```

endpoint_url の部分は、AWS IoTの設定画面から「設定」ボタンを押して確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/15e4c677-a681-e09d-5a43-290d7b98fe30.png)


##### コード全文
Amazon API Gateway から渡されるイベントデータに、キーワード（「Cool」「Heat」「Stop」）が含まれていた場合は、対応するメッセージを IoT core に発行（Publish）するようにしています。

```python
# coding: utf-8
import json
import boto3
import logging

iot = boto3.client("iot-data", endpoint_url='https://xxxxxxxxxxxxxxx.iot.xxxxxxxxx.amazonaws.com')
topic = "$aws/things/myM5StickC/shadow/update/delta"

# ログ設定
logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    msg = event.get("event").get("text")

    # 受信データをCloud Watchログに出力
    logging.info(json.dumps(event))

    # SlackのChallenge認証
    if "challenge" in event:
        return event["challenge"]

    # メッセージ毎に処理を行う
    if "Cool" in msg:
        payload = {
        "message": "Cool"
        }

    elif "Heat" in msg:
        payload = {
        "message": "Heat"
        }

    elif "Stop" in msg:
        payload = {
        "message": "Stop"
        }
        
    else:
        print("キーワードが一致しません。")
        return "OK"

    # publishする
    try:
        iot.publish(
            topic=topic,
            qos=0,
            payload=json.dumps(payload, ensure_ascii=False)
        )
        print(payload, "をpublishしました。")
        return "Succeeeded."

    # 例外のメッセージをログに出力
    except Exception as e:
        print(e)
        return "Failed."
```

コードを書き終わったら、[Deploy]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/9c30baa2-4400-dfa3-e73c-73bca8f1ad0d.png)


### 関数のアクセス権限を設定する
続いて、[設定]-[アクセス権限]を開き、ロール名のリンクをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/4d32cc2b-a6ab-baf8-884b-2715caa51983.png)

[許可を追加]-[ポリシーをアタッチ]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/40683889-1307-5c6c-188b-29b23fdf0870.png)

検索欄に「IoTDataAccess」と入力します。
「IoTDataAccess」にチェックを入れて、[許可を追加]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/17a9762c-def0-32c2-44a7-f1c32b2141e0.png)


### テストしてみる
関数の画面に戻り、[テスト]タブを開きます。
「イベントJSON」欄に、以下の様に入力して、[テスト]をクリックします。

```JSON
{
    "event": {
        "text": "Cool"
    }
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/4868ba10-6bda-4669-3c1c-16d7bd5b7f03.png)

成功しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/67ad4885-3534-74ec-794d-81e541198b3a.png)

ログを確認すると、メッセージ"Cool"を受け取り、対応するメッセージ"Cool"を IoT core に発行したことが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/4f2995eb-5cc3-3767-5706-1c43de3834d2.png)

次に、実際に、IoT core にメッセージが格納されるかを確認します。
AWS IoT > 管理 > すべてのデバイス > モノ > myM5StickC　を開きます。
[アクティビティ]タブを開き、「MQTTテストクライアント」をクリックします。
[トピックにサブスクライブする]タブを開き、トピックのフィルター欄に「$aws/things/myM5StickC/shadow/update/delta」を入力し、[サブスクライブ]をクリックします。
メッセージ"Cool"が格納されることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/8ce7934e-dbf1-f0cf-5952-d361b1a49573.png)

# 2. Amazon API Gateway の作成
### APIを作成する
AWSコンソール画面上部の検索欄に「API Gateway」と入力し、[サービス]-[API Gateway]をクリックします。
[APIを作成]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/13ec1762-463d-9421-584c-38721043c6c4.png)

API タイプは「REST API」を選択します。[構築]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/9fe0ae9c-56c1-020e-b2d3-261b0600b4f4.png)

API名欄に任意の名前を入力します。ここでは「M5StickC_Publish-API」と入力します。[APIを作成]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/150e76a7-e858-ac24-ac20-66e7eef4a7c2.png)

[リソースを作成]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/30c7a7bb-d9cc-3b3c-0af1-36a4956f1a07.png)

リソース名欄に任意の名前を入力します。ここでは「M5StickC_Publish」と入力します。「リソースを作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/b60b099e-2ef6-38ef-eaf2-89600f290116.png)

[メソッドを作成]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/f432f292-fde2-256c-aa18-8cede58ae065.png)

メソッドタイプは、「POST」を選択します。Lambda関数は、先ほど作成した関数を選択します。「メソッドを作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/d9c10f52-37e8-2d85-32a0-88bbb76bdc5b.png)

[APIをデプロイ]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/7dd3d105-82e2-7025-41c8-9c0c4f14dce1.png)

任意のステージを選択します。ここでは、新たにステージを作成し、ステージ名を「production」としました。[デプロイ]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/f4e80553-139b-8ebe-d802-954a6daa3ff5.png)

この時点で、関数の画面から[設定]-[トリガー]を開いてみると、作成した API Gateway がトリガーとして追加されていることが確認できます。ここに表示されている API endpoint は、 Slack API 作成時に必要となるので控えておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/97add836-67ee-85f7-ea6e-58f9f768ba76.png)


# 3. Slack API の作成
### Slack API を作成する
[Slack API](https://api.slack.com/apps) にアクセスします。
[Create New App]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/83a9cd5e-8f39-727a-1efe-37692c4b7cd5.png)

[From scratch]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/8753ea09-d406-6783-383d-3f0c0d1e5dd0.png)

App Name 欄に任意の名称を入力します。ここでは「Air Conditioning by M5StickC」と入力します。Workspace を選択し、[Create App]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/90ed71c1-2910-089c-1298-748ef77cebc6.png)

[Event Subscriptions]を開き、[Enable Events]を On にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/054fabaa-84d2-d596-fe07-d59a17d73f45.png)

[Request URL]欄に、先ほど控えた API endpoint を入力します。
Lambda関数によるSlackのChallenge認証がうまく通れば、Verified と表示されるはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/862100e3-a46c-0bff-c8e4-3dcd42fd8b69.png)

少し下にスクロールし、[Subscribe to bot events]を展開して、[Add Bot User Event]をクリックし、「app_mention」を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/890676af-14fc-1716-00e7-2e3b189831e3.png)

画面右下の[Save Changes]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/ff2190c5-93ca-d0d6-4dad-42550a0e9001.png)

[Install App]を開き、[Install to Workspace]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/e3aa733d-1faa-0f27-05ff-459cbe67e654.png)

[Allow]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/9705548e-aac7-41c8-e080-e870aed70d1d.png)

### テストしてみる
スマホ上でSlackを開き、適当なチャンネルを作成して、チャンネルにAppを追加します。
Botにメンションして、キーワード（「Cool」「Heat」「Stop」）を送ってみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/fa5c3311-8727-8002-1951-2435e7ee8a1e.png)

ここで、Lambda のログを確認すると、Slackから送ったメッセージが届いていることが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/81a78523-9d5d-b1c1-5e1e-ca1358612851.png)

IoT core にも、メッセージが格納されていることが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407204/876d4c78-2cd6-12a3-a40a-a2fc4e397b52.png)

そして、ほどなくしてエアコン操作が実行できれば成功です。　

# おわりに
最後まで読んで頂いてありがとうございました。
今回の取り組みは、やりたいことが先にあって、どうやってそれを実現するかを考えながら手を進めました。世の中には、色んな製品やサービスがあって、それらを組み合わせることで色んなことが実現できて便利ですね。
私にとっては、M5StickC も、Arduino IDE も、AWS の各サービスも、Slack API も、初めて触るものばかりで苦労しましたが、その分、学びの楽しさと、実現の喜びを感じることが出来ました。
この記事が、同じ目的を持つ人のお役に立てば幸いです。