はじめに
EC2インスタンスの電源ボタンを、ESP-WROOM-02開発ボードで作ってみた。
EC2インスタンスの電源状態のモニタリングをAPI Gateway+Lambdaでやろうとしたが、ポーリングでリクエストが多くなるとお財布事情が、、、と思い、AWS IoTからプッシュ通知ができないか調べてみたところ、ドンピシャなライブラリaws-mqtt-websocketsがあったのでこれを使ってみる。
事前準備
IAMユーザの作成
サンプルスケッチを見ればわかるが、AWSの認証情報(アクセスキー,シークレットキー)を書かないといけないので、専用IAMユーザを作って、認証情報を保存しておく。
アタッチするポリシーは、インラインポリシーで以下のものを(ここまでいらないかもしれない。コメント求む。)。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:Connect",
"iot:Publish",
"iot:Subscribe",
"iot:Receive",
"iot:GetThingShadow",
"iot:UpdateThingShadow"
],
"Resource": "*"
}
]
}
Thingの作成
AWS IoTでThingをaws iot create-thing --thing-name ${thing_name}
で作成する。以下はec2power-switch
という名前のthingを作る例。
$ aws iot create-thing --thing-name ec2power-switch
{
"thingArn": "arn:aws:iot:${region}:${account}:thing/ec2power-switch",
"thingName": "ec2power-switch"
}
# ${region}や${account}は、それぞれ実行環境で変わる。
※登録済みのthingのリストは、aws iot list-things
で確認できる。
$ aws iot list-things
{
"things": [
{
"attributes": {},
"version": 1,
"thingName": "ec2power-switch"
}
]
}
エンドポイントアドレスの確認
AWS IoTのエンドポイントアドレスを確認する。
$ aws iot describe-endpoint
{
"endpointAddress": "xxxxxxxxxxxxxx.iot.${region}.amazonaws.com"
}
ここまでで、
- AWSの認証情報
- アクセスキー
- シークレットキー
- Thingの名前
- エンドポイントアドレス
がそろっているはず。
また
- AWSのリージョン名(ex. ap-northeast-1)
- 実行環境の下記無線LAN情報
- ssid
- password
も確認しておく。
Arduino用ライブラリの取得
既にArudino IDEの構築や、ESP-WROOM-02用の設定は済ませているものとして、AWS IoTにESP-WROOM-02をつなぐのに必要な部分だけ書く。
以下の4つの追加ライブラリを入れる。
- aws-mqtt-websockets
- aws-sdk-arduino
- WebSockets for Arduino
- Paho MQTT for Arduino
aws-mqtt-websockets
aws-mqtt-websockets
githubから取得して、librariesディレクトリ12に展開して保存する。
aws-sdk-arduino
aws-sdk-arduino
githubから取得して、librariesディレクトリ12に展開して保存した後、src/common以下をこのライブラリのルートにコピー、さらにsrc/esp8266以下を同じ場所に上書きコピーする。
WebSockets for Arduino
Arduino IDEのメニューから、[スケッチ]→[ライブラリのインクルード]→[ライブラリの管理...]と辿って検索フィルタにWebSockets for Arduino (Server + Client)
と入れて出てくるライブラリの最新バージョンをインストールする。
Paho MQTT for Arduino
Paho MQTT for Arduino
公式サイトからArduino Client Library 1.0.0(2017/02/12現在)を取得して、librariesディレクトリ12に展開して保存する。
サンプルスケッチの実行
Arduino IDEのメニューから[ファイル]→[スケッチ例]→[aws-mqtt-websocket]→[aws-mqtt-websocket-example]を選択してサンプルスケッチを開き、30行目付近にある下記設定値を変更する。
:
//AWS IOT config, change these:
char wifi_ssid[] = "your-ssid";
char wifi_password[] = "your-password";
char aws_endpoint[] = "your-endpoint.iot.eu-west-1.amazonaws.com";
char aws_key[] = "your-iam-key";
char aws_secret[] = "your-iam-secret-key";
char aws_region[] = "eu-west-1";
const char* aws_topic = "$aws/things/your-device/shadow/update";
:
Thingの名前は、aws_topic
のyour-device
の部分に書く。
このスケッチをコンパイルして書き込めば、AWS IoTに接続して待ち受けして、シリアルコンソールに以下のようなログが出る。
connected with {SSID}, channel 11
dhcp client start...
..........ip:192.168.0.16,mask:255.255.255.0,gw:192.168.0.1
7682 - conn: 1 - (34528)
please start sntp first !
websocket layer connected
MQTT connecting
MQTT connected
MQTT subscribed
ここまでくると接続成功。
またこのサンプルスケッチでは、接続成功時に自分のThingにメッセージを送っていて、その結果も併せて出力されている(下記2行)。
Message 1 arrived: qos 0, retained 0, dup 0, packetid 0
Payload {"state":{"reported":{"on": false}, "desired":{"on": false}}}
余談
自分の環境では、setup()
内の
WiFiMulti.addAP(wifi_ssid, wifi_password);
Serial.println ("connecting to wifi");
while(WiFiMulti.run() != WL_CONNECTED) {
delay(100);
Serial.print (".");
}
の部分(175行目付近)を、
WiFi.begin(wifi_ssid, wifi_password);
Serial.println ("connecting to wifi");
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
のように書き換えないとWiFiにつながらなかった。
これはAWS IoTとかmqttとかwebsocketは関係なく、自分の無線環境の問題か。
おまけ
冒頭の「EC2インスタンスの電源ボタンを~」というのをやるには、CloudWatchのルールでEC2インスタンスの状態を監視して、変化時に起動されるLambda関数でAWS IoTに通知するようにした。
状態に変化があった時に実行されるLambda関数の、AWS IoTへの通知部分は以下のようなコード。
var IoTData = new AWS.IotData({
endpoint: 'xxxxxxxxxxxxxx.iot.${region}.amazonaws.com',
region: '${region}'
});
var params = {
topic: '$aws/things/${thingName}/shadow/update',
payload:
};
IoTData.publish(params).promise()
.then((data) => {
:
});
あと電源のOn/Offは結局API Gateway+Lambdaでやった。