LoginSignup
57
59

More than 5 years have passed since last update.

Edisonを使ってセンサデータをAmazon Kinesisにあげてみる【後編】

Last updated at Posted at 2014-12-01

最近話題のIntel Edisonを用いて、温度センサ等のデータをWiFi経由でAmazon KinesisにあげてみるIoT的なのをやってみましょう。前回の記事でIntel EdisonをWifiでつなぎセンサデータをJavaScriptで取得するところまでやりました。今回の後編では、センサのデータをIoTにうってつけのクラウドサービスであるAmazon Kinesisにあげていきます。

IMG_7960-2.png

全体の流れ

前回の記事(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にご自身のものを入れるのに注意です。

cognito.js

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のみを使う場合はもちろん東京リージョンをお使い頂けます。)
2014-11-29_22-09-04.png

シャードという概念がでてきます。シャードは、Amazon Kinesis ストリームを構成しており、シャードの量でスループットを決めることになります(ちなみに、1シャードあたり、1 MB/秒のデータ入力、2MB/秒のデータ出力能力を提供します。また、1シャードでは秒あたり最大1000 PUT および 5READをサポートできます)。
2014-11-29_22-09-05.png

はい、これで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のインフラをスモールスタートで構築できる。

免責
こちらは個人の意見で会社とは関係ありません。

57
59
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57
59