[AWS CDK] SlackとRaspberry PiでエアコンをONにする仕組みを作った(涼しい家に帰宅できるぞ!!)

外出から帰って自宅が暑いと嫌です。でもエアコン付けっぱなしも電気代的な意味で嫌です。

そこで、「自宅に帰る1時間ぐらい前に、エアコンをONにできないか?」と考え構築してました。

仕組み自体は約1年前に構築済ですが、AWSの画面ポチポチで作成していたので、AWS CDK(Cloud Development Kit)を使って作り直してみました。

目次

構成

SlackのSlash Commandsが叩くWebAPIを作成し、Lambaがコマンド解析してIoT CoreのTopicにPublishします。

Raspberry PiはTopicをSubscribeしており、命令に従ってエアコンをONにします。

システム構成図

なお、Raspberry Pi用の赤外線学習リモコンを使っています。

補足

  • 実際のエアコンがAWSに接続されていないため、Device Shadowは使っていません
    • Device Shadowとエアコンの状態不一致を考えるのがめんどくさい
  • APIの応答が3秒以内というSlackの仕様がありますが、3秒未満で処理は完了するため、3秒以上の経過は未考慮です
    • 考慮するなら、処理用のLambdaを非同期で実行させてからすぐ応答します
    • 非同期のLambdaでは、「遅延応答用のURL」に対して応答します

Raspberry Piに学習リモコンを装着した様子

他のGPIOは使えなくなりますが、とてもコンパクトで置き場所にも困りません。

Raspberry Piに学習リモコンを装着した様子

環境

  • Mac
    • macOS Mojave 10.14.6
    • Python 3.6
  • Raspberry Pi 3 Mobile B+
    • Raspbian 9.4
    • Python 3.6
  • ほか
    • AWS CDK 1.3.0 (build bba9914)
    • npm 6.9.0
    • node 10.16.1

リポジトリ構成

下記のように、Raspberry Pi環境とAWS環境を分けています。

$ tree -L 2
.
├── RaspberryPi
│   ├── cert
│   ├── config.ini
│   └── main.py
└── aws
    ├── bin
    ├── cdk.json
    ├── cdk.out
    ├── lib
    ├── node_modules
    ├── package-lock.json
    ├── package.json
    ├── src
    └── tsconfig.json

AWSの環境構築

API仕様

APIは下記を用意します。

Method Path
POST /control

AWS CDKのインストール

インストール済みの場合はSkipしてください。

$ npm install -g aws-cdk

AWS CDKプロジェクトの構築

HomeControlフォルダを作成し(あとでawsにリネームしてます)、その中にCDKプロジェクトを構築します。

$ mkdir HomeControl
$ cd HomeControl
$ cdk init app --language=typescript

必要なライブラリをインストールします。

$ npm install --save @aws-cdk/aws-iot
$ npm install --save @aws-cdk/aws-lambda
$ npm install --save @aws-cdk/aws-apigateway
$ npm install --save @aws-cdk/aws-iam
$ npm install --save-dev aws-sdk

Lambdaコードを書く!

まずはファイルを作ります。

$ mkdir -p src/lambda/iot_publish
$ touch src/lambda/iot_publish/app.ts

続いてコードを下記にします。本人確認等はひとまず省略してます。

インフラをコードで書く!!!

lib/home_control-stack.tsを下記にします。

ビルドする

$ npm run build

デプロイする

Lambdaコード格納用のS3バケットを作るcdk bootstrapは、最初の1回だけでOKです。

$ cdk bootstrap
$ cdk deploy

スタック作成が完了すると、エンドポイント(WebAPIのアドレス)が表示されるので、メモしておきます。

Outputs:
HomeControlStack.HomeControlApiEndpointxxxxx = https://yyyyyyy.execute-api.ap-northeast-1.amazonaws.com/prod/

Slackアプリの構築

チャンネル作成

専用のチャンネルを作成します。

HomeControl用のチャンネルを作成する

Slackアプリの作成

SlackのYour Appsにアクセスし、「Create New App」を選択します。

Create New Appを選択する

適当に入力します。

Slack Appの設定をする

Slash Commandsの作成

「Slash Commands」を選択します。

Slach Commandsを選択する

「Create New Command」を選択します。

Create New Commandを選択する

適当に入力します。

Request URLは、さきほど作成したエンドポイントと作成したAPIのリソース名を入力します。

項目 内容
Command /control
Request URL https://yyyyyyy.execute-api.ap-northeast-1.amazonaws.com/prod/control
Short Description 自宅の家電を操作します
Usage Hint aircon on

Slash Commandを作成する様子

Slash Commandsのインストール

左側のメニューから「Basic Information」を選択し、続けて「Install App to Workspace」を選択します。

Workspaceに追加する

権限を確認し、「インストール」を選択します。

権限を確認してインストールする

Raspberry Piのスクリプト作成

あとでコピーするため、Raspberry Pi上で作業しなくても大丈夫です。

Raspberry Pi用のフォルダ作成

$ mkdir RaspberryPi
$ cd RaspberryPi

IoTエンドポイントの取得

取得してメモしておきます。

$ aws iot describe-endpoint --endpoint-type iot:Data-ATS
{
    "endpointAddress": "xxxxx-ats.iot.ap-northeast-1.amazonaws.com"
}

設定ファイルの作成

config.iniを作成し、下記とします。ENDPOINTはさきほど取得した値です。

[AWS_IOT_CONNECT]
ROOT_CA = ./cert/AmazonRootCA1.pem
PRIVATE_KEY = ./cert/private.pem.key
CERTIFICATE = ./cert/certificate.pem.crt.txt

[AWS_IOT_CORE]
CLIENT_ID = home_control_raspberry_pi
ENDPOINT = xxxxx-ats.iot.ap-northeast-1.amazonaws.com
PORT = 8883
TOPIC = HomeControl/RaspberryPi

メインスクリプトの作成

main.pyを作成し、下記とします。

Raspberry Piの環境構築

「証明書の作成 & ダウンロード」以外は、Raspberry Pi上で作業します。

証明書の作成 & ダウンロード

ブラウザでAWSにログインし、作成したIoT Thingsを開きます。

続いて、「セキュリティ」の「証明書の作成」を選択します。

セキュリティの証明書を作成する

作成された証明書などをダウンロードし、「有効化」をしたのち、「ポリシーをアタッチ」を選択します。

証明書などをダウンロードする

さきほど作成したポリシーを選択し、「完了」を選択します。

証明書とポリシーを紐付ける

Raspberry Piにファイル類をコピー

Raspberry PiとPCを接続し、先ほど作成したファイル類をRaspberry Piにコピーします。

証明書フォルダの作成

$ mkdir cert

上記フォルダ内にダウンロードした証明書などを格納します。

最終的に次のようになっていればOKです。

$ tree -L 2
.
├── cert
│   ├── AmazonRootCA1.pem
│   ├── certificate.pem.crt.txt
│   └── private.pem.key
├── config.ini
└── main.py

ライブラリのインストール

$ pip install AWSIoTPythonSDK
$ pip install rpi.gpio

学習リモコンにエアコンONを学習させる

Raspberry Pi用の赤外線学習リモコンの説明書に従って実施します。

必要に応じて、Pythonスクリプト(main.py)のPIN番号定義を修正します。下記の混在に注意してください。

  • 学習リモコンのSW番号
  • Raspberry PiのGPIO
  • Raspberry PiのPIN

開始コマンド

SSH接続を解除してもバックグラウンド実行してほしいため、nohupを使用しています。また、GPIOの制御にはsudoが必要です。

$ nohup sudo python main.py > output.log &

終了コマンド

スクリプト終了時にGPIO.cleanup()を実行する必要があるため、finish.txtが在る場合に終了させています。

$ touch finish.txt

動作確認!!!

Slackで/control aircon onと入力して実行します。

/control aircon onを入力して実行する

反応が返ってきて、、、実際にエアコンがONになりました!!!

コマンドが受け付けられた!

さいごに

AWS CDKとTypeScriptは初めて使いましたが、CloudFormationやAWS SAMと比べて、非常に便利&楽だと思いました。

YAMLの構成(階層)と微妙に異なるので慣れるまで大変そうですが、TypeScriptの型とエディタの補完機能が便利すぎます!!

AWS CDKの良い勉強になりました。これから積極的に使っていきたいです。

参考