ESP-WROOM-02をAWS IoTにつないでみた


はじめに

EC2インスタンスの電源ボタンを、ESP-WROOM-02開発ボードで作ってみた。

EC2インスタンスの電源状態のモニタリングをAPI Gateway+Lambdaでやろうとしたが、ポーリングでリクエストが多くなるとお財布事情が、、、と思い、AWS IoTからプッシュ通知ができないか調べてみたところ、ドンピシャなライブラリaws-mqtt-websocketsがあったのでこれを使ってみる。

事前準備

IAMユーザの作成

サンプルスケッチを見ればわかるが、AWSの認証情報(アクセスキー,シークレットキー)を書かないといけないので、専用IAMユーザを作って、認証情報を保存しておく。

アタッチするポリシーは、インラインポリシーで以下のものを(ここまでいらないかもしれない。コメント求む。)。

policy.json
{
    "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つの追加ライブラリを入れる。

  1. aws-mqtt-websockets
  2. aws-sdk-arduino
  3. WebSockets for Arduino
  4. 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-mqtt-websocket-example
 :
//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_topicyour-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に通知するようにした。

CloudWatchのルールは、以下のような設定。

状態に変化があった時に実行されるLambda関数の、AWS IoTへの通知部分は以下のようなコード。

index.js
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でやった。



  1. Windowsの場合: %USERPROFILE%\Documents\Arduino\libraries 

  2. macOSの場合:~/Documents/Arduino/libraries