最近話題のIntel Edisonを用いて、温度センサ等のデータをWiFi経由でAmazon KinesisにあげてみるIoT的なのをやってみましょう。前回の記事でIntel EdisonをWifiでつなぎセンサデータをJavaScriptで取得するところまでやりました。今回の後編では、センサのデータをIoTにうってつけのクラウドサービスであるAmazon Kinesisにあげていきます。
全体の流れ
前回の記事(Edisonを使ってセンサデータをAmazon Kinesisにあげてみる【前編】では、下記のEdisonの準備までやりました。
★Edisonの準備(前編の記事)
- Intel Edison Kit for Arduinoのセットアップ
- Groveスターターキットプラスのセットアップ
- センサデータをJavaScriptで取得する
今回は後編ということで、以下の順で実施していきます。
★AWSリソースの準備
- AWS Cognitoでデバイスを認証する
- Amazon Kinesisのストリーム作成
- KinesisへのデータのPut
★仕上げ - センサデータをEdisonからKinesisにPutする
- Kinesis内のデータの確認
では早速手をつけていきましょう。
AWS Cognitoでデバイスを認証する
Kinesisにデータを書き込む際に、デバイス側に認証のためのクレデンシャルを置きたくないので、AWS Cognitoを使ってデバイスからの特定のリソースへのアクセスを認証することにします。詳しくは、こちら参照 (Amazon CognitoをJavaScriptから使ってみる)。
上記の記事を参考に、CognitoのIndentity Poolを作成します。Amazon Cognitoが米国東リージョンとEUリージョンのみで使えるため(2011/12/02時点)、今回は米国東リージョンでCognitoを使います。Cognitoのゲストアクセスユーザーに対して、Kinesisのみへの書き込み権限を与えます。こうすることで、Kinesis以外のAWSリソースにはアクセス出来ないようにします。その上で、下記のようなjsファイルを作成します。AccountID, RoleArn, IdentityPoolIdにご自身のものを入れるのに注意です。
var AWS = require('aws-sdk');
var awsRegion = "us-east-1";
var cognitoParams = {
AccountId: "41073212XXXX",
RoleArn: "arn:aws:iam::41073212XXXX:role/Cognito_iot_hackUnauth_DefaultRole",
IdentityPoolId: "us-east-1:8286c169-3ff5-4feb-aad9-9f7d9XXXXXXXXX"
};
AWS.config.region = awsRegion;
AWS.config.credentials = new AWS.CognitoIdentityCredentials(cognitoParams);
AWS.config.credentials.get(function(err) {
if (!err) {
console.log("Cognito Identity Id: " + AWS.config.credentials.identityId);
}
});
手元のローカル環境(私の場合、Mac Book Air)にて、Cognitoのゲストアクセスができるか試してみましょう。AWS SDK for JavaScriptとnode.js環境があれば、実行できます。すると下記のように、Cognito Identityがとれていることが分かります。これでAWSのリソースにアクセスできます。
$ node cognito.js
Cognito Identity Id: us-east-1:2908a57d-fe97-4b15-a0a9-03dbXXXXXXXX
つまり、同様のJSをEdison上で動かせば、EdisonからCognito認証が行え、AWSのリソースにアクセスできるようになります。簡単!
Amazon Kinesisのストリーム作成
次は、マネージメントコンソールで、Amazon Kinesisのストリーム(ストリーム処理をするときの単位。システム毎にストリームを作ることになります)を作っていきましょう。
(Amazon Cognitoが米国東リージョンとEUリージョンのみで使えるために、今回はKinesisも米国東リージョンで使うことにします。Kinesisのみを使う場合はもちろん東京リージョンをお使い頂けます。)
シャードという概念がでてきます。シャードは、Amazon Kinesis ストリームを構成しており、シャードの量でスループットを決めることになります(ちなみに、1シャードあたり、1 MB/秒のデータ入力、2MB/秒のデータ出力能力を提供します。また、1シャードでは秒あたり最大1000 PUT および 5READをサポートできます)。
はい、これでKinesisのストリームができました。Kinesis の料金は、時間単位のシャード速度と PUT 取引の量で決まります。1シャードあたり約1500円〜/月となるのがかなり低額でリアルタイムストリーミングが行えますが、詳しくはこちらをご参照ください。
Amazon KinesisへのデータのPut
では作成しておいたKinesisストリームに、疑似のセンサデータをローカル環境からPutしてみて、Cognitoでの認証とKinesisへのデータのPutが動作するかチェックしてみましょう。
var AWS = require('aws-sdk');
var deviceId = "Edison";
var streamName = 'iot_hack_edison_sensordata'; // Kinesisストリーム
var partitionKey = "xyz"; // Kinesisのパーティション用のキー
// Congito setting
var awsRegion = "us-east-1";
var cognitoParams = {
AccountId: "41073212XXXX",
RoleArn: "arn:aws:iam::41073212XXXX:role/Cognito_iot_hackUnauth_DefaultRole",
IdentityPoolId: "us-east-1:8286c169-3ff5-4feb-aad9-9f7d9129b797"
};
// Get identity from Amazon Cognito
AWS.config.region = awsRegion;
AWS.config.credentials = new AWS.CognitoIdentityCredentials(cognitoParams);
AWS.config.credentials.get(function(err) {
if (!err) {
console.log("Cognito Identity Id: " + AWS.config.credentials.identityId);
}
});
// Get sensor data
var sensorData = "100";//疑似のセンサーデータ
// Put data into Kinesis
var kinesis = new AWS.Kinesis();
setInterval(periodicActivity, 1000);
function periodicActivity() {
console.log("Sensor " + sensorData);
var json = {
device_id: deviceId,
time: (new Date).getTime(),
sensors: [{
sensordata: {
temp: sensorData,
}
}]
};
var kparams = {
Data: JSON.stringify(json),
PartitionKey: partitionKey,
StreamName: streamName
};
kinesis.putRecord(kparams, function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
console.log(data);
}
});
}
これで実行してみましょう。
$ node kinesis.js
{ SequenceNumber: '49545554908569968986498146905221840262797727776028753922',
ShardId: 'shardId-000000000000' }
実際にKinesisにデータを書き込むことができ、その際にShardIDと、SequenceNumberがかえってきました。
今回作ったKinesisストリームには、Shardは一つしかないので、必ず同じIDがかえってきますが、もしセンサが大量にあってシャードを複数持っている場合は、コードの中のパーティションキーによって、異なるシャードに振り分けられることになります。こういう設計なので、後からでもAPIを用いてシームレスにシャードの数を増やすことで、デバイスやデータ量の数の増加に対応できます。
また、Kinesisは一つ一つのデータにシーケンシャルな番号がつくのが特徴です。データを入れた際に、必ずこのSequenceNumberが返ってくるのでこの位置からデータを取り出すことができます。
センサデータをEdisonからAmazon KinesisにPutする
さて、いよいよ仕上げです。ここまでEdisonのセットアップを終えた後に、AWSリソースのセットアップをし、ローカル開発環境からAWSリソースへの認証と疑似データのPutを行ってきました。
ここからは、またEdisonに戻って、最後の仕上げということで、EdisonからKinesisにデータをPutしてみましょう。先ほどのコードとほとんど同じですが、センサーからデータを取り込む部分(前回の記事参照)のみ書き換えます。Kinesisに送り込むデータは、前回の記事でA0ピンに取り付けた光電センサのみとすると、こんな感じになるでしょう。
var m = require('mraa'); //require mraa
var AWS = require('aws-sdk');
var deviceId = "Edison";
var streamName = 'iot_hack_edison_sensordata'; // Kinesisストリーム
var partitionKey = "xyz"; // Kinesisのパーティション用のキー
// Congito setting
var awsRegion = "us-east-1";
var cognitoParams = {
AccountId: "41073212XXXX",
RoleArn: "arn:aws:iam::41073212XXXX:role/Cognito_iot_hackUnauth_DefaultRole",
IdentityPoolId: "us-east-1:8286c169-3ff5-4feb-aad9-9f7d9129b797"
};
//setup access analog inpuput pin 0
var analogPin0 = new m.Aio(0);
// Get identity from Amazon Cognito
AWS.config.region = awsRegion;
AWS.config.credentials = new AWS.CognitoIdentityCredentials(cognitoParams);
AWS.config.credentials.get(function(err) {
if (!err) {
console.log("Cognito Identity Id: " + AWS.config.credentials.identityId);
}
});
// Put data into Kinesis
var kinesis = new AWS.Kinesis();
setInterval(periodicActivity, 1000);
function periodicActivity() {
var analogValue0 = analogPin0.read(); // Get sensor data
console.log("Sensor: " + analogValue0);
var json = {
device_id: deviceId,
time: (new Date).getTime(),
sensors: [{
sensordata: {
temp: analogValue0,
}
}]
};
var kparams = {
Data: JSON.stringify(json),
PartitionKey: partitionKey,
StreamName: streamName
};
kinesis.putRecord(kparams, function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
console.log(data);
}
});
}
これで実行すると、同様にSequenceNumberが返ってくるはずです!ようやくEdisonからKinesisにデータを入れることができました!Congrats!
$ node kinesis.js
{ SequenceNumber: '495455549085699689864981469052218402627977277760287XXXXX',
ShardId: 'shardId-000000000000' }
Amazon Kinesis内のデータの確認
さて、しばし心を落ち着けてみると、本当にこれでEdisonからセンサデータがKinesisに入っているのか気になってきます。実際にKinesisにきちんとデータが入っているのかどうか、データを取り出して検証してみましょう。
Kinesisからデータを取り込んだり、可視化するには様々な方法があります。Kinesis Client Applicationを作って、DynamoDBやRedShiftにデータをおき、BIツールなのでアプリで可視化しても良いですね。実際にAWS re:InventでのIoT Hack Dayでは、DynamoDB経由でWebアプリが作られてハッカソンに参加している全チームのセンサデータを可視化するアプリが作られていました。
今回はよりシンプルに、ローカル開発環境(私の場合Mac Book Air)から直接Kinesisにアクセスして、AWS CLI(コマンドラインインターフェース)を使ってデータをとってみましょう。
データをKinesisにPutした際のシーケンスナンバーを使えばその時点からデータを取得することができます(参照)。
まずは、そのシーケンスナンバーを入れて、データ取得用のシャードイテレーターをとります。
$ aws kinesis get-shard-iterator --stream-name iot_hack_edison_sensordata --shard-id shardId-000000000000 --shard-iterator-type AT_SEQUENCE_NUMBER --region us-east-1 --starting-sequence-number "シーケンスナンバー"
{
"ShardIterator": "AAAAAAAAAAET7feSut....XXXXX"
}
このシャードイテレーターを用いると、無事にデータが取得できます。
$ aws kinesis get-records --region us-east-1 --shard-iterator "シャードイテレーター"
{
"Records": [
{
"PartitionKey": "xyz",
"Data": "eyJkZXZpY2VfaWQiOiJFZGlzb24iLCJ0aW1lIjoxNDE3MjY3MjQwMDc3LCJzZW5zb3JzIjpbeyJzZW5zb3JkYXRhIjp7InRlbXAiOjEwMH19XX0=",
"SequenceNumber": "49545554908569968986498146905139633307063711990311550978"
},
{
"PartitionKey": "xyz",
"Data": "eyJkZXZpY2VfaWQiOiJFZGlzb24iLCJ0aW1lIjoxNDE3MjY3MjQxMDgwLCJzZW5zb3JzIjpbeyJzZW5zb3JkYXRhIjp7InRlbXAiOjEwMH19XX0=",
"SequenceNumber": "49545554908569968986498146905140842232883326688205733890"
},
==略
"NextShardIterator": "AAAAAAAAAAF7ICgZLM4DI5Iav9z1lKFfcz3kAN2XPyzUpQrInH0eP3leHr+S9kt5kjkS8xXAvEM1cuaz3YW+cQwDy8fgcH8jSlkElIBMI9/C3vKsabUHc4ZC5ENn9OdGKqIeGfYqm10W+midO2vacRITlbkb8TWztFTcL+KLECNPgDgQOUKJdLO/WuwTEFj31blAKat+BBlBlmzfVOZ97g1DPk/aCfFQ"
}
結果はBase64エンコードされていますが(現時点のCLIではBase64デコードするオプションがないようです)、デコードすると、こんな感じで確かにPutしたデータが入っています!
{"device_id":"Edison","time":1417267643687,"sensors":[{"sensordata":{"temp":100}}]}
さいごに所感
さて、前編と後編を通じて、Intel Edisonを用いて温度センサ等のデータをWiFi経由でAmazon KinesisにあげてみるIoT的なのをやってみました。最後に例によって所感です。
前編の所感
- Edisonは起動してすぐにwifiにつなげるし、npmでAWS SDK for JavaScriptを組み込み環境にそのままインストールできるなんてのは2000年頃に組み込み系開発をやっていた頃からすると隔世の感がある。
- GROVEスターターキットは色々なセンサーをハンダ付け無しでつないで遊べるので学習用には非常に良い。
- 組み込みボードのIOをnode.jsのJavaScriptで叩いて、そのままAWSのリソースもJavaScriptで書ける。サーバーサイド、スマホ等のクライアントサイドのみならず、デバイスサイドまでJavaScriptである。JS万歳。
今回の後編の所感
- Amazon Cognito使うとAWSリソースのアクセス制限も簡単に出来てよい。スマホ、デバイスからAWSリソースアクセスの際には便利。
- Amazon Kinesisは後からシャードも増やせていけるので、IoTのインフラをスモールスタートで構築できる。
免責
こちらは個人の意見で会社とは関係ありません。