はじめに
AWSのIoTのサービスといえばAWSIoTですよね!
つい先日大阪で行われてた「AWS Cloud Roadshow 2017」の中で、AWS Greengrassが東京リージョンに上陸したことが発表されました!
ということでですね、デバイスとクラウド間のやり取りの基本的な部分をAWSIoTを利用して実装していこうと思います
※前半部分にはsakura.io ✕ AWS IoTハンズオン [AWS編]の内容を投稿者の方の許可をいただいた上で、使わせていただいております
#[0] 主な流れ
AWSIoTとラズパイ間の通信をMQTTでつなぎ、送受信する手順を紹介します
おおまかな流れはこんな感じです
- AWSIoTで証明書を発行する
- 発行した証明書を用いてデバイス(Raspi)とAWSIoTを接続する
- メッセージを送受信する
- (おまけ)Lambda経由でDynamoDBにデータをPUTする
#[1] AWS IoTの設定(Thing)
AWS IoTは概念が少々複雑ですが、ある程度把握しておかないとこれ以降の設定内容が理解できないと思います。AWS Black Belt Online Seminar 2016 AWS IoTで学習すると良いでしょう。
- 証明書にThingとポリシーを紐付ける
- 証明書をデバイスにインストールする
- 流れてきたトピックに対するアクション(連携先等)をルールで定義する
##ポリシーの作成
AWS IoTコンソールを開く
リージョンが「Asia Pacific (Tokyo)」でない場合は変更する
[Get started]をクリックする(下図は表示されない場合もある)
ポリシーを作成する
下表の通り入力して[Create]をクリックする
項目 | 入力内容 |
---|---|
Name | AllPubSub |
Action | iot:* |
Resource ARN | * |
Effect | Allow |
##Thingと証明書の作成
Thingを作成する
device01を入力して[Create thing]をクリックする
作成したThingをクリックする
証明書を作成する
クライアント証明書/クライアント秘密鍵/ルート証明書の3種類をダウンロードする(ルート証明書のみ、右クリック -> リンク先を別名で保存)
[Activate](押し忘れ注意!) -> [Attach a policy]の順にクリックする
[AllPubSub]を選択して[Done]をクリックする
戻る
##エンドポイントを確認する
歯車マークをクリックするとエンドポイントが表示されるので控えておく
#[2] RaspiとAWSIoTを接続する
前章で発行した証明書を使って、RaspiとAWSIoTを接続します
使用したRaspiの情報は以下のとおり
- Raspbian GNU/Linux 8.0 (jessie)
- Linux raspberrypi 4.4.34
MQTTの実装
MQTTの実装には「mosquitto」を利用します。下記コマンドを実行することでAWSIoTとの通信を行います
- Pub mosquitto_pubコマンドで光量データを送信
- Sub mosquitto_subコマンドで光量データを受信
mosquittoのインストール
Raspberry Piのデフォルトリポジトリのmosquitto-clientsはバージョンが古く、TLSのエラーが発生するため最新のmosquitto-clientsをインストールします
$ wget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key
$ sudo apt-key add mosquitto-repo.gpg.key
$ wget http://repo.mosquitto.org/debian/mosquitto-stretch.list
$ sudo cp mosquitto-stretch.list /etc/apt/sources.list.d/
$ sudo apt-get update
$ sudo reboot
$ sudo apt-get install mosquitto-clients
$ mosquitto_sub --help |grep version
mosquitto_sub version 1.5 running on libmosquitto 1.5.0.
2018/05/28時点で最新のバージョンは1.5.0です
先ほど発行した証明書(クライアント証明書/クライアント秘密鍵/ルート証明書の3種類)をRasberry Piにコピーします
※この際コピーミスを防ぐために、SFTPなどで確実にコピーするようにしてください。scpでホームディレクトリにファイルを置く例
$ scp file-name pi@IP_ADDRESS:~
AWSIoT MQTTクライアントを開く
[Test]を選択する
[Subscription topic]に「$aws/things/device01/test」と入力する
[Subscribe to topic]をクリックする
下記のような画面になると思います
ラズパイからAWSIoTへのメッセージ送信(publish)
例)トピック「$aws/things/device01/test」に対して文字列「test message」を送信します
$ mosquitto_pub --cafile [ルート証明書] --cert [クライアント証明書] --key [クライアント秘密鍵] -h [AWSIoTのエンドポイント] -p 8883 -q 1 -t '$aws/things/device01/test' -i device01 --tls-version tlsv1.2 -m '{"test": "message"}' -d
例)トピック「$aws/things/device01/test」に対してJSONファイル「data_sample.json」を送信します
{
"data": [
{
"d1": "0000",
"d2": "9999",
"d3": "0003",
"d4": "0004",
"d5": "0005",
"d6": "0006",
"d7": "0007",
"d8": "0008",
"d9": "0009",
"d10": "0010",
"serial": "00000001",
"time": "201706010100"
}
]
}
$ mosquitto_pub --cafile [ルート証明書] --cert [クライアント証明書] --key [クライアント秘密鍵] -h [AWSIoTのエンドポイント] -p 8883 -q 1 -t '$aws/things/device01/test' -i device01 --tls-version tlsv1.2 -f data_sample.json -d
問題なく送信が完了すれば、先ほど開いたテスト画面にデバイスからのメッセージが表示されます
↓こんな感じ(data_sample.jsonを送信した際の結果)
AWSIoTからのメッセージ受信(subscribe)
例)トピック「$aws/things/device01/test」に対するメッセージを待ち受けます
$ mosquitto_sub --cafile [ルート証明書] --cert [クライアント証明書] --key [クライアント秘密鍵] -h [AWSIoTのエンドポイント] -p 8883 -q 1 -t '$aws/things/device01/test' -i device01 --tls-version tlsv1.2
上記コマンドでsubscribeしている状態で、テスト画面からメッセージをデバイスへ送信します
問題なければデバイス側のターミナルに、こんなメッセージが表示されます
{
"message": "Hello from AWS IoT console"
}
Device shadowを更新する
AWSIoTにはすでに予約されているトピックがあり「$aws/things/device01/shadow/update」に対してメッセージを送信するとshadowを更新することができます
{
"state":
{
"desired":
{
"status_data": [
{
"status1": "1101",
"status2": "1202",
"status3": "1303",
"status4": "1404",
"status5": "1005",
"status6": "1006"
}
]
}
}
}
$ mosquitto_pub --cafile [ルート証明書] --cert [クライアント証明書] --key [クライアント秘密鍵] -h [AWSIoTのエンドポイント] -p 8883 -q 1 -t '$aws/things/device01/shadow/update' -i device01 --tls-version tlsv1.2 -f shadow_sample.json -d
#[3]Lambda経由でDynamoDBにデータをPUTする(おまけ)
前章でデバイスからAWSIoTにメッセージを送信することができるようになりましたので、デバイスからJSONのデータを送信し、それをDynamoDBに格納してみます
簡単な流れとしては
- AWSIoTのルールを設定し、特定のトピックにメッセージが送信されたらLambdaをキックする
- Lambdaが受け取ったデータを加工しDynamoDBにPUTする
送信するデータは前章で作成した「data_sample.json」を利用します
Lambdaの作成
関数名「IoT-Lambda-DynamoDB」というLambda関数を作成していきます
今回はRuntimeをNode.js6.10でLambdaを作成しています
Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": "dynamodb:PutItem",
"Resource": "arn:aws:dynamodb:ap-northeast-1:xxxxxxxxxx:table/iot-data-lambda"
}
]
}
※DynamoDBにPUTする部分のARNはご利用されているAWSのアカウントIDに書き換えてください
Code(Node.js)
const AWS = require("aws-sdk");
const dynamoDB = new AWS.DynamoDB.DocumentClient({
region: "ap-northeast-1"
});
exports.handler = (event, context, callback) => {
const item = event["data"][0];
item["deviceID"] = event["deviceID"];
const nowTime = Date.now();
item["time"] = String(nowTime);
const params = {
TableName: "iot-data-lambda",
Item: item
};
dynamoDB.put(params).promise();
};
DynamoDBの作成
LambdaがPUTするDynamoDBを作成します
DynamoDBの情報
項目 | 入力内容 |
---|---|
TableName | iot-data-lambda |
Primary partition key | deviceID (String) |
Primary sort key | time (String) |
AWSIoTルールの作成
- AWSIoTコンソール画面左メニューからルール画面に移動し、画面右上の「create」をクリックしてルール作成画面に移動する
- 「Name」に任意の文字列を入力する
- 「Attribute」「Topic filter」に下記の内容を入力する
項目 | 入力内容 |
---|---|
Attribute | *,topic(3) AS deviceID |
Topic filter | $aws/things/+/data |
「topic(3) AS deviceID」と書いておくことで、トピックの3番目をdeviceIDとしてデータの中に含ませて次のActionに渡します
今回の場合はトピックの「+」に入る文字列が、Lambdaに渡されるeventの中にdeviceIDが含まれるようになります
4. [Set one or more actions]の「Add action」をクリックし、Lambdaを選択、画面下部の[Configure action]をクリック
5. 先ほど作成したLambda関数を選択し[Add action]をクリック
これで「IoT_Lambda_DynamoDB」というルールが作成されました
デバイスからトピック「$aws/things/+/data」(+にはdeviceIDとなる文字列を入れる)にメッセージが送信されたときに、Lambdaにデータが渡され、加工してDynamoDBに格納します
実際に実行してみる
デバイスからデータを送信する
$ mosquitto_pub --cafile [ルート証明書] --cert [クライアント証明書] --key [クライアント秘密鍵] -h [AWSIoTのエンドポイント] -p 8883 -q 1 -t '$aws/things/device01/data' -i device01 --tls-version tlsv1.2 -f data_sample.json -d
問題なく処理が実行されればDynamoDBにデータがPUTされる
さいごに
AWSIoTで発行した証明書ベースでメッセージの送受信ができるようになりました
今回は証明書の発行、デバイスへの証明書のコピーなどすべて手作業で行いましたが、デバイスが複数台になってくるとこんなことしれいられないので、このあたりを自動化するのが必要になってくるなと実感しましたね
そこらへんの自動化を実現してくれたすばらしいお方から資料をいただいたので、試していこうと思います
もし許可をいただいたら記事にまとめようと思いますー
ではまた!