sakura.io ✕ AWS IoTハンズオン [AWS編]

#**概要**
本コンテンツは、**[JAWS-UG関西IoT専門支部「sakura.io ✕ AWS IoTハンズオン」](https://jawsugosaka.doorkeeper.jp/events/64668)**向けに作成したものです。[sakura.io](https://sakura.io/)とAWSを連携させてセンサーデータをDynamoDBに書き込み、[IoT.kyoto VIS](http://iot.kyoto/)で可視化します。
AWS IoTルールエンジンを利用して直接DynamoDBに書き込むこともできますが、今回はIoT.kyoto VISの制約によりLambdaでデータを整形してからDynamoDBに書き込むことにします。
![スクリーンショット 2017-09-18 10.00.40.png](https://qiita-image-store.s3.amazonaws.com/0/80392/1054de51-1761-2fc9-67be-624394e24aca.png)

##前提条件
* モノとさくらの通信モジュールを接続し、計測値が取得できていること
* sakura.ioコンソールで**モジュール登録まで**が完了していること
* [AWSアカウントの開設](https://aws.amazon.com/jp/register-flow/)が完了していること(要クレジットカード)

モジュール登録までの手順は**[こちら](https://www.slideshare.net/sakura_pr/sakuraio-handson)**。
![FullSizeRender.png](https://qiita-image-store.s3.amazonaws.com/0/80392/a8e515ee-2f0f-1e45-f9e6-d1e4db22a017.png)

#**[1] IAMの設定**
##IAMキーの作成
下表のアクセス権をもつIAMキーを作成します。

| ユーザー名 | アクセス権 | 使用箇所 |
|--------------|----------|----------|
| vis | AmazonDynamoDBReadOnlyAccess | IoT.kyoto VISからDynamoDBの読み出し |

* AWSに[サインイン](https://console.aws.amazon.com/)する
* Identity and Access Management(IAM)コンソールを開く<BR>※ 英語画面で説明するので日本語表示になっている場合は、画面左下の言語選択を「English」に変更する<BR>
![AWS Management Console 2017-02-05 15-21-17.png](https://qiita-image-store.s3.amazonaws.com/0/80392/1cb88cc2-a86a-b9d7-7414-97354a338df6.png)
<BR><BR>
* 「**vis**」というUser nameでProgrammatic accessユーザーを作成する<BR>
![IAM Management Console 2017-02-05 15-25-26.png](https://qiita-image-store.s3.amazonaws.com/0/80392/dc7adb2c-e039-d6f3-12f7-b6b3cf0fb61f.png)<BR><BR><BR>
![スクリーンショット 2017-09-18 10.52.20.png](https://qiita-image-store.s3.amazonaws.com/0/80392/20855ed2-bf2f-145a-51fa-836834e2cbf0.png)<BR><BR>
* [Attach existing policies directly]をクリックし、[dynamo]で検索して、[**AmazonDynamoDBReadOnlyAccess**]にチェックを入れる
* [Next: Review]をクリックする<BR>
![スクリーンショット 2017-09-18 10.56.57.png](https://qiita-image-store.s3.amazonaws.com/0/80392/4f2dad1c-4d46-da20-ecff-70af587be299.png)<BR><BR>
* [AmazonDynamoDBReadOnlyAccess]が表示されていることを確認して[Create user]をクリックする<BR>
![スクリーンショット 2017-09-18 10.57.06.png](https://qiita-image-store.s3.amazonaws.com/0/80392/86ba5722-01b2-32d3-ad14-a72459e057e9.png)<BR><BR>
* 認証情報の書かれたCSVをダウンロードし、[Close]をクリックする<BR>
![IAM Management Console 2017-02-05 15-41-43.png](https://qiita-image-store.s3.amazonaws.com/0/80392/a3c29183-8437-e796-d71e-31289c89af54.png)

##IAM Roleの設定
下表のアクセス権をもつIAMロールを作成します。なお、手順を簡易にするため少し過剰な権限を設定しています。

| ロール名 | アクセス権 | 使用箇所 |
|--------------|----------|----------|
| lambda_dynamodb | AmazonDynamoDBFullAccess<BR> CloudWatchLogsFullAccess | LambdaからDynamoDBへの書き込み |

* 下図の通りLambda用のIAMロールを作成する
![スクリーンショット 2017-09-18 00.04.27.png](https://qiita-image-store.s3.amazonaws.com/0/80392/263de7e1-d564-9ce3-67c2-42e8efd4b8df.png)
![スクリーンショット 2017-09-18 00.18.17.png](https://qiita-image-store.s3.amazonaws.com/0/80392/362e00c1-0dcd-9a53-f9d8-05bf233bf59a.png)<BR><BR>
* [Attach existing policies directly]をクリックし、[dynamo]で検索して、[**AmazonDynamoDBFullAccess**]にチェックを入れる
* 検索文字列を削除後、同様に[cloudwatch]で検索して、[**CloudWatchLogsFullAccess**]にチェックを入れる<BR>
![スクリーンショット 2017-09-18 00.25.22.png](https://qiita-image-store.s3.amazonaws.com/0/80392/02cffed9-d5cb-099f-c23b-6ac802305343.png)<BR><BR>
* 適用されたポリシー2種(緑の囲み)を確認の上、[Role name]に[**lambda_dynamodb**]を入力して[Create role]をクリックする
![スクリーンショット 2017-09-18 00.28.57.png](https://qiita-image-store.s3.amazonaws.com/0/80392/10c76df8-138b-c60e-cef0-1035b559e7cd.png)

#**[2] AWS IoTの設定(Thing)**
AWS IoTは概念が少々複雑ですが、ある程度把握しておかないとこれ以降の設定内容が理解できないと思います。[AWS Black Belt Online Seminar 2016 AWS IoT](https://www.slideshare.net/AmazonWebServicesJapan/aws-black-belt-online-seminar-2016-aws-iot)で学習すると良いでしょう。
おおまかな設定の流れは次の通りです。

1. **証明書**に**Thing**と**ポリシー**を紐付ける
2. 証明書をデバイスにインストールする
3. 流れてきたトピックに対するアクション(連携先等)を**ルール**で定義する

##ポリシーの作成
* AWS IoTコンソールを開く<BR>
![スクリーンショット 2017-09-18 00.46.54.png](https://qiita-image-store.s3.amazonaws.com/0/80392/6b1d3201-444a-423f-6818-b07d6873b119.png)<BR><BR>
* リージョンが「Asia Pacific (Tokyo)」でない場合は変更する<BR>
![4bd6b0f2-3593-3b10-1839-62f3c2f13173.png](https://qiita-image-store.s3.amazonaws.com/0/80392/1c4f7929-0ab8-557d-630b-3d2479e0dc95.png)<BR><BR>
* [Get started]をクリックする(下図は表示されない場合もある)
![スクリーンショット 2017-09-11 17.23.40.png](https://qiita-image-store.s3.amazonaws.com/0/80392/1ab2e28c-7ef6-32a7-ad17-a7f7a858eece.png)<BR><BR>
* ポリシーを作成する<BR>
![スクリーンショット 2017-09-18 01.26.53.png](https://qiita-image-store.s3.amazonaws.com/0/80392/ce2830c3-fb30-bbf4-72fa-0eb00df9f29e.png)<BR><BR>
* 下表の通り入力して[Create]をクリックする

| 項目 | 入力内容 |
|---|---|
| Name | AllPubSub |
| Action | iot:* |
| Resource ARN | * |
| Effect | Allow |

![スクリーンショット 2017-09-18 01.12.18.png](https://qiita-image-store.s3.amazonaws.com/0/80392/ec9efcde-1265-ddb6-d0a7-6ef5d9e31ecf.png)

##Thingと証明書の作成
* Thingを作成する
![スクリーンショット 2017-09-18 00.49.51.png](https://qiita-image-store.s3.amazonaws.com/0/80392/e1951359-33a5-efa3-5c04-0d35f7505921.png)<BR><BR>
* **`sakuraio`**を入力して[Create thing]をクリックする
![スクリーンショット 2017-09-18 00.51.50.png](https://qiita-image-store.s3.amazonaws.com/0/80392/8282fae7-bc92-8cf3-6c62-8335a279465d.png)<BR><BR>
* 作成したThingをクリックする<BR>
![スクリーンショット 2017-09-18 00.53.55.png](https://qiita-image-store.s3.amazonaws.com/0/80392/9207daf0-f9e8-3ce1-9acb-121971c0e5e9.png)<BR><BR>
* 証明書を作成する<BR>
![スクリーンショット 2017-09-18 00.55.14.png](https://qiita-image-store.s3.amazonaws.com/0/80392/29782f80-18dc-ddbd-37e2-064f3c18be5c.png)<BR><BR>
* クライアント証明書／クライアント秘密鍵／ルート証明書の3種類をダウンロードする(ルート証明書のみ、右クリック -> リンク先を別名で保存)
* **<font color="Red">[Activate]</font>**(押し忘れ注意！) -> [Attach a policy]の順にクリックする<BR>
![スクリーンショット 2017-09-18 00.57.16.png](https://qiita-image-store.s3.amazonaws.com/0/80392/69bc4680-8f44-98b8-d67c-d4ebbe8ce6b7.png)<BR><BR>
* [AllPubSub]を選択して[Done]をクリックする<BR>
![スクリーンショット 2017-09-18 01.18.49.png](https://qiita-image-store.s3.amazonaws.com/0/80392/f8dd9a0f-20cb-9798-114e-9d573303f836.png)<BR><BR>
* 戻る<BR>
![スクリーンショット 2017-09-18 01.24.11.png](https://qiita-image-store.s3.amazonaws.com/0/80392/9b5d12bf-a7d1-8c74-3673-aa4dc08fb70b.png)

##エンドポイントを確認する
* 歯車マークをクリックするとエンドポイントが表示されるので控えておく
![スクリーンショット 2017-09-18 01.38.48.png](https://qiita-image-store.s3.amazonaws.com/0/80392/aa0c4723-d822-5827-061a-9a4c3bc98557.png)

#**[3] sakura.ioの設定**
* [sakura.ioコンソール](https://secure.sakura.ad.jp/iot/console/#/)を開く
* [+サービス追加]をクリックする
![スクリーンショット 2017-09-17 19.15.58.png](https://qiita-image-store.s3.amazonaws.com/0/80392/a6d74452-d5c3-c080-fe56-4392532ecdc5.png)<BR><BR>
* [AWS IoT]をクリックする
![スクリーンショット 2017-09-18 01.44.30.png](https://qiita-image-store.s3.amazonaws.com/0/80392/725e9f5f-147d-ec56-87a7-511362302161.png)<BR><BR>
* 下表の通り入力して[作成]をクリックする(証明書は先ほどダウンロードしたものを**テキストエディタ**で開いてコピペする。証明書のファイル名をxxxxx.txtに変更すると開きやすい)

| 項目 | 入力内容 |
|---|---|
| 名前 | temp_humi_awsiot |
| ホスト名 | 先ほど控えたAWS IoTエンドポイント |
| ポート番号 | 8883 |
| PublishするTopicのプレフィックス | sakuraio/pub |
| SubscribeするTopic | sakuraio/sub |
| ルート証明書 | ダウンロードしたものをコピペ<BR>(VeriSign-Class 3-Public-Primary-Certification-Authority-G5.pem) |
| クライアント証明書 | ダウンロードしたものをコピペ<BR>(xxxx-certificate.pem.crt) |
| クライアント秘密鍵 | ダウンロードしたものをコピペ<BR>(xxxx-private.pem.key) |

![スクリーンショット 2017-09-18 01.50.14.png](https://qiita-image-store.s3.amazonaws.com/0/80392/5cf501e9-8dc1-2678-7690-0658341eedde.png)

* 設定済の連携サービス[temp_humi_awsiot]を開き、接続ステータスが[success]となっていることを確認する<BR>接続ステータスが[unknown]と表示される場合は、10秒程度待ってからブラウザをリロードする
![スクリーンショット 2017-09-18 02.17.55.png](https://qiita-image-store.s3.amazonaws.com/0/80392/c5398db8-94d4-febf-66bb-23ac54f6de47.png)
![スクリーンショット 2017-09-18 02.18.34.png](https://qiita-image-store.s3.amazonaws.com/0/80392/82d3f7e8-8e53-b628-423c-5407c9543c6d.png)


#**[4] AWS IoTの受信テスト**
* AWS IoTコンソールを開く(画面キャプチャ省略)
* リージョンが「Asia Pacific (Tokyo)」でない場合は変更する(画面キャプチャ省略)
* [Test]をクリックし[Subscription topic]に**`sakuraio/#`**を入力する
* [Subscribe to topc]をクリックする 
![スクリーンショット 2017-09-18 02.23.14.png](https://qiita-image-store.s3.amazonaws.com/0/80392/ff0506e5-ede1-74c3-ef0e-b1d6b3f561d0.png)<BR><BR>
* 下図のようにトピックが5秒毎に更新されればOK
![スクリーンショット 2017-09-18 02.26.53.png](https://qiita-image-store.s3.amazonaws.com/0/80392/7c339f76-4f44-b94d-8be0-dc3cff276202.png)

##データ構造
AWS IoTには**`sakuraio/pub/{deviceID}`**というトピックで下記のようなメッセージが送られてきます。計測値は**`value`**に格納されており、HDC1000を接続してsakura.io公式コードを使用した場合は下表のようになります。

```json
{
  "module": "xxxxxxxxxx",
  "type": "channels",
  "datetime": "2017-09-18T07:58:24.776736813Z",
  "payload": {
    "channels": [
      {
        "channel": 0,
        "type": "f",
        "value": 27.575073,
        "datetime": "2017-09-18T07:58:24.742738363Z"
      },
      {
        "channel": 1,
        "type": "f",
        "value": 73.33374,
        "datetime": "2017-09-18T07:58:24.754738363Z"
      },
      {
        "channel": 2,
        "type": "I",
        "value": 14021,
        "datetime": "2017-09-18T07:58:24.766738363Z"
      }
    ]
  }
}
```

| channel | 計測対象 |
|---|---|
| 0 | 温度 |
| 1 | 湿度 |
| 2 | カウンタ |

#**[5] DynamoDBの設定**
* DynamoDBコンソールを開く(画面キャプチャ省略)
* リージョンが「Asia Pacific (Tokyo)」でない場合は変更する(画面キャプチャ省略)
* [Create table]をクリックする<BR>
![スクリーンショット 2017-09-18 03.01.18.png](https://qiita-image-store.s3.amazonaws.com/0/80392/77400c25-3543-95bc-79c5-dc1252e7eaf3.png)<BR><BR>
* [Table name]に**`sakuraio_temp_humi`**を入力する
* [Partition key]に**`module`**を入力する
* [Add sort key]にチェックを入れ、**`datetime`**を入力する
* [Create]をクリックする<BR>
![スクリーンショット 2017-09-18 03.02.53.png](https://qiita-image-store.s3.amazonaws.com/0/80392/2317d701-431d-a0da-4b7b-51ff0c809b37.png)


#**[6] LambdaおよびAWS IoT(ルール)の設定**
AWS IoTのルールをトリガーにLambda Functionをキックします。Lambda Functionでは、タイムスタンプのms以下の切り捨てや計測値(value)の取り出しおよび、DynamoDBへの書込を行います。詳細はコードをご覧ください。

* Lambdaコンソールを開く(画面キャプチャ省略)
* リージョンが「Asia Pacific (Tokyo)」でない場合は変更する(画面キャプチャ省略)
* [Create function]をクリックする
![スクリーンショット 2017-09-18 02.37.12.png](https://qiita-image-store.s3.amazonaws.com/0/80392/6819b77b-3671-9047-dc31-89d79a243a05.png)<BR><BR>
* [Author from scratch]をクリックする
![スクリーンショット 2017-09-18 02.38.27.png](https://qiita-image-store.s3.amazonaws.com/0/80392/ac3324a0-4d88-8140-ad94-9adfa3f0a441.png)<BR><BR>
* トリガーに[AWS IoT]を選択する<BR>
![スクリーンショット 2017-09-18 02.38.46.png](https://qiita-image-store.s3.amazonaws.com/0/80392/9479eb63-cb52-0d17-6c6f-d965a5c7877a.png)<BR><BR>
* 下表の通り入力して[Next]をクリックする

| 項目 | 入力内容 |
|---|---|
| IoT type | Custom IoT Rule |
| Rule | Create a new rule |
| Rule name | sakuraio |
| Rule query statement | SELECT * FROM 'sakuraio/#' |
| Enable trigger | ON |

![スクリーンショット 2017-09-18 02.54.45.png](https://qiita-image-store.s3.amazonaws.com/0/80392/8a6424e1-d854-6d83-16d6-e16d05227043.png)<BR><BR>

* [Name]に**`sakuraio_dynamodb`**と入力し、下記のコードをコピペする

```js:
const AWS = require("aws-sdk");
const dynamoDB = new AWS.DynamoDB.DocumentClient({
    region: "ap-northeast-1"
});

exports.handler = (event, context, callback) => {
    console.log(`event: ${JSON.stringify(event)}`);
    
    const payload = event["payload"]["channels"];
    console.log(`payload: ${JSON.stringify(payload)}`);
    
    // DynamoDBにPUTするItemObjectを生成
    const item = {};
    
    // moduleをItemに格納
    item["module"] = event["module"];
    console.log(`item: ${JSON.stringify(item)}`);
    
    // ミリ秒を切り捨て
    const dateTime = event["datetime"];
    const splitTime = dateTime.split(".");
    console.log(`splitTime: ${JSON.stringify(splitTime[0])}`);
    const time = splitTime[0] + "Z";
    console.log(`time: ${JSON.stringify(time)}`);
    
    // datetimeをItemに格納
    item["datetime"] = time;
    console.log(`item: ${JSON.stringify(item)}`);
    
    // 各valueをItemに格納
    Object.keys(payload).map((key) => {
        const channel = "channel-" + payload[key]["channel"];
        const value = payload[key]["value"];
        item[channel] = value;
    });
    console.log(`item: ${JSON.stringify(item)}`);
    
    // Paramsを生成 TableNameは適宜変更
    const params = {
        TableName: "sakuraio_temp_humi",
        Item: item
    };
    console.log(`params: ${JSON.stringify(params)}`);
    
    // DynamoDBにPUT実行
    const dynamoPutPromise = dynamoDB.put(params).promise();
    dynamoPutPromise.then((data) => {
        console.log("put success!");
		callback(null);
    }).catch((err) => {
        console.log(err);
		callback(err);
    });
};
```

![スクリーンショット 2017-09-18 03.16.26.png](https://qiita-image-store.s3.amazonaws.com/0/80392/385b6fec-e697-f03e-e157-45c7f1c11528.png)

* スクロールして、**[lambda_dynamoDB]**ロールを選択し、[Next]をクリックする
![スクリーンショット 2017-09-18 03.17.33.png](https://qiita-image-store.s3.amazonaws.com/0/80392/576d088f-12d6-972b-3753-76c7aab740b9.png)<BR><BR>
* [Create function]をクリックする
![スクリーンショット 2017-09-18 03.30.43.png](https://qiita-image-store.s3.amazonaws.com/0/80392/6543247f-64a1-66b6-5033-9f3134c1e030.png)

#**[7] DynamoDBへの書き込み確認**
* DynamoDBコンソールを開く(画面キャプチャ省略)
* リージョンが「Asia Pacific (Tokyo)」でない場合は変更する(画面キャプチャ省略)
* [Tables] -> [sakuraio_temp_humi] -> [Items]の順にクリックする
* 下図のようにレコードが記録されていることを確かめる
![スクリーンショット 2017-09-18 03.32.46.png](https://qiita-image-store.s3.amazonaws.com/0/80392/8b1ce38b-f216-5ff8-e982-74b5e4e53f0e.png)


#**[8] IoT.kyoto VISの設定**
![スクリーンショット 2017-09-12 11.36.10.png](https://qiita-image-store.s3.amazonaws.com/0/80392/6317dcdb-ffa8-9d20-1b1e-90f8f1bc8a4a.png)

##サインアップ
https://vis.iot.kyoto にアクセスし、「新規登録」をクリックします。登録にはメールアドレスが必要ですが、登録時にメールが受信できる必要はありません。(パスワードリマインド時のみ受信できる必要があります)

##設定
**手順は[IoT.kyoto VIS公式マニュアル](http://iot.kyoto/howtouse.html)の3～4章を参照してください。**
[ユーザー設定]の入力例は下図の通りです。AWSアクセス設定には、先ほど作成したIAMキー(ダウンロードしたCSV参照)を使用します。**「AWS IoT連携」はOFFにしてください**。<BR>
![スクリーンショット 2017-09-18 04.04.44.png](https://qiita-image-store.s3.amazonaws.com/0/80392/ec57f9ae-e903-6b56-8850-695fe561a2be.png)

##グラフを表示させる
[パーティションキー]と[表示対象キー]を選択して、リロードします。
![スクリーンショット 2017-09-18 09.20.54.png](https://qiita-image-store.s3.amazonaws.com/0/80392/541d4dd6-c8a5-1122-f286-3126696fbac1.png)<BR><BR>
グラフ設定で更新間隔等を調整します。
![スクリーンショット 2017-09-18 10.02.06.png](https://qiita-image-store.s3.amazonaws.com/0/80392/2e3d92c6-2d53-2705-9a6a-c626e8bb4518.png)<BR><BR>
温度と湿度を同時にグラフ表示することができます。
![スクリーンショット 2017-09-18 09.57.24.png](https://qiita-image-store.s3.amazonaws.com/0/80392/2472ac4d-9118-444a-6a66-6953bb250e05.png)