Edisonでセンサ値をAmazon Kinesisに上げてみた

Edison に接続したセンサ値を Amazon Kinesis にUPする手順を試してみました。

0.動機

JAWS-DAYS 2015 HackDay は参加できずに斜め見程度で残念に思ってました。
http://jawsdays2015.jaws-ug.jp/timetable/about_hackday/

ですが、その後気づいたのが KenTamagawa さんの素晴らしいブロッグ!

Edisonを使ってセンサデータをAmazon Kinesisにあげてみる【前編】
http://qiita.com/KenTamagawa/items/3f2e2bd3bb36a27dc439

Edisonを使ってセンサデータをAmazon Kinesisにあげてみる【後編】
http://qiita.com/KenTamagawa/items/b5bc103ab84761281112

ちょうど必要となり2台目のエジソンを購入しました。
一応、楽しむためだけに買ったのではないであしからず。(汗)

11149484_874564905933098_524984166140834136_n (1)

そりゃ届いたからには一通り触らにゃいかん!
という性格で、先ずは同じ手順をやってみることにしました。

1.OSの設定

前のブロッグ記事(これ)なども振り返りながら、先ず Yoct Linux を設定。

今回は自宅の Windows 7 のTraTermで接続してみます。

起動した接続画面を閉じて、シリアルポートを開きます。
IoT_Ed-01

ボート・レートを 115200 に変更するだけでコンソール画面を表示します。
IoT_Ed-02

以下のログイン画面が表示されます。
最初は root でパスワード無しでログインできます。
IoT_Ed-03

2.自分の環境設定

先ずは configure_edison でパスワード、無線LANの設定します。
この説明はKenTamagawa さんのブロッグか、私の過去の記事などをご参照ください。

ネットに繋がったら先ず現在のパッケージソフトを最新のものに更新します。
普段はパッケージソフトの管理は、yum、apt-get を使いますが、Yoct Linux は opkg というパッケージ管理ソフトを使います。
しかしながら初期設定がされていませんので、viエディタで以下のファイルを作成します。

vi /etc/opkg/base-feeds.conf
src/gz all http://repo.opkg.net/edison/repo/all
src/gz edison http://repo.opkg.net/edison/repo/edison
src/gz core2-32 http://repo.opkg.net/edison/repo/core2-32

vi /etc/opkg/intel-iotdk.conf
src intel-all http://iotdk.intel.com/repos/1.1/iotdk/all
src intel-iotdk http://iotdk.intel.com/repos/1.1/intelgalactic
src intel-quark http://iotdk.intel.com/repos/1.1/iotdk/quark
src intel-i586 http://iotdk.intel.com/repos/1.1/iotdk/i586
src intel-x86 http://iotdk.intel.com/repos/1.1/iotdk/x86

上記が終わったら、apt-get と同じように update を行います。

opkg update
opkg upgrade

ネット環境が良いと、処理速度が速いのでそんなに待たされません。
私は個人的に vi エディタの代わりに nano を使いますのでインストールします。

opkg install nano

その他、パッケージはそこそこ準備されているようですので、お好みの環境を整えると良いでしょう。

3.センサデータをJavaScriptで取得

いよいよ、KenTamagawa さんのブロッグの手順に従い、Edison に mraa  をインストールします。
mraa の詳細については玉川さんのブロッグか以下のリンクをご参照ください。

intel-iot-devkit/mraa
https://github.com/intel-iot-devkit/mraa/tree/master/examples/javascript

nano /etc/opkg/mraa-upm.conf
src mraa-upm http://iotdk.intel.com/repos/1.1/intelgalactic

opkg update
opkg upgrade

以上で、mraa の準備が完了します。

全く同じでは芸がない、という事で玉川さんの例を以下にしてみました。

nano readIO2.js

var m = require('mraa'); //require mraa

var B=3975*4; //B value of the thermistor
var S=100; //C value for which the LED should turn on.

//setup access analog inpuput pin 0, 1
var analogPin0 = new m.Aio(0);
var analogPin1 = new m.Aio(1);

var digitalPin = new m.Gpio(8);
digitalPin.dir(m.DIR_OUT);

//read the value of the analog pin
var analogValue0 = analogPin0.read();
var analogValue1 = analogPin1.read();

//light
var analogValue10 = (1023-analogValue0)*10/analogValue0;
analogValue10 = (10000 / Math.pow(analogValue10*10,4/3))*200;
analogValue10 = Math.round(analogValue10)/10;
console.log("light: " + analogValue0 + " => " + analogValue10);

//LED
if(analogValue10 < S){
  digitalPin.write(1);
}else{
  digitalPin.write(0);
}

//temperature
analogValue1b = (1023-analogValue1)*10000/analogValue1;
var analogValue11 = (1/(Math.log(analogValue1b/10000)/B+1/298.15)-273.15)*10;
analogValue11 = Math.round(analogValue11)/10;
console.log("temperature: " + analogValue1 + " => " + analogValue11);

過去 Raspberry Pi でGroveのセンサを使った事がありましたので以下のリンクを参照しました。
温度、照度の計測に、照度がある程度下がったたLEDを点灯するロジックも追加しています。

seeed Main Page
http://www.seeedstudio.com/wiki/index.php?title=Main_Page#Grove

Grove – Light Sensor
http://www.seeedstudio.com/wiki/Grove_-_Light_Sensor
https://github.com/spaniakos/LightSensor/blob/master/LightSensor.cpp

照度と明るさの目安
http://photon.sci-museum.kita.osaka.jp/publish/text/koyomi/66.html

Grove – Temperature Sensor
http://www.seeedstudio.com/wiki/Grove_-_Temperature_Sensor
https://github.com/Seeed-Studio/Grove_Temperature_Sensor/blob/master/Temperature_Sensor.ino

照度LUX値は上記リンクから、以下をJavaScriptに変換したら良い筈でした。

sensorValueはセンサからの取得値。
Rensor = ( (float) (1023 – sensorValue) * 10.0f / (float) sensorValue);
LUX = round(10000.0f / (float) pow((Rensor*10.0f),(4.0f/3.0f)));

ですが Raspberry Pi で同じセンサで取得した値と異なり、照度と明るさの目安からもおかしい値が表示されます。
苦肉の策として、LUX値*200 で室内レベルではそこそこましになってきました。
浮動小数点の精度誤差としてもあり得ないように感じましたので、不思議です。
後日時間がある時に mraa の中身や、PDFのセンサスペックを覗いてみようと思います。

温度も同じく、以下をJavaScriptに変換したら良い筈でした。

aはセンサからの取得値。
int
B=3975;
resistance=(float)(1023-a)*10000/a;
temperature=1/(log(resistance/10000)/B+1/298.15)-273.15;

結果がおかしくて Raspberry Pi で計測している温度(検証済)と異なります。
ですが実際は B=3975*4 でやっと近似値になりました。

node.js は初体験ですので、根本を理解できてないミスかもしれないですが、不思議です。

原因はいずれ解明します。

20150417_000012

4.アクセス認証を準備

KenTamagawa さんの例に従い Kinesis へ PUT する再は Cognito のデバイスからの特定のリソースへのアクセスを認証を使います。

最初に Cognito の Indentity Pool を作成します。
こちらも KenTamagawa さんの以下のブロッグを参考に行ってみてください。

Amazon CognitoをJavaScriptから使ってみる

http://qiita.com/KenTamagawa/items/36238d6264ee14c2b50f

作成した IdentityPoolId  を控えます。

Cognitoのゲストアクセスができるか試すため、KenTamagawa さんに習って以下のコードを作成。

AccountId => 2XXXXXXX3
Pool mame => iot_hack
IdentityPoolId => 8XXXXXXXXXXXXXXXXXXXXXXXX9
npm install aws-sdk
nano cognito.js
var AWS = require('aws-sdk');

var awsRegion = "us-east-1";
var cognitoParams = {
  AccountId: "2XXXXXXXXXX3";,
  RoleArn: "arn:aws:iam::2XXXXXXXXX3:role/Cognito_iot_hackUnauth_DefaultRole",
  IdentityPoolId: "us-east-1:8XXXXXXXXXXXXXXXXXXXXXXXX9";
};

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);
  }
});

実際に上記コードを実行すると、以下のCognito Identityが取れた様子が分かります。

node cognito.js
Cognito Identity Id: us-east-1:f041a697-a29d-49be-a986-XXXXXXXXX

5.センサデータをKinesisへPUT

Amazon Kinesis のストリーム作成は KenTamagawa さんのブロッグを参考に行ってみてください。

プログラムは以下のようにしてみました。

nano kinesis3.js

var m = require('mraa'); //require mraa

var B=3975*4; //B value of the thermistor
var S=100; //S value for which the LED should turn on.

var AWS = require('aws-sdk');
var deviceId = "Edison";
var streamName = 'iot_hack_edison_sensordata'; // Kinesis stream
var partitionKey = "xyz"; // Kinesis partitionKey

// Congito setting
var awsRegion = "us-east-1";
var cognitoParams = {
  AccountId: "2XXXXXXXXXX3";,
  RoleArn: "arn:aws:iam::2XXXXXXXXXX3:role/Cognito_iot_hackUnauth_DefaultRole";,
  IdentityPoolId: "us-east-1:8XXXXXXXXXXXXXXXXXXXXXXXXXXXX9";
};

//setup access analog inpuput pin
var analogPin0 = new m.Aio(0);
var analogPin1 = new m.Aio(1);

var digitalPin = new m.Gpio(8);
digitalPin.dir(m.DIR_OUT);

// 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();
  var analogValue1 = analogPin1.read();

  //light
  var analogValue10 = (1023-analogValue0)*10/analogValue0;
  analogValue10 = (10000 / Math.pow(analogValue10*10,4/3))*200;
  analogValue10 = Math.round(analogValue10)/10;
  console.log("light: " + analogValue0 + " => " + analogValue10);

  //LED
  if(analogValue10 < S){
    digitalPin.write(1);
  }else{
    digitalPin.write(0);
  }

  //temperature
  analogValue1b = (1023-analogValue1)*10000/analogValue1;
  var analogValue11 = (1/(Math.log(analogValue1b/10000)/B+1/298.15)-273.15)*10;
  analogValue11 = Math.round(analogValue11)/10;
  console.log("temperature: " + analogValue1 + " => " + analogValue11);

  var json = {
    device_id: deviceId,
    time: (new Date).getTime(),
    sensors: [{
      sensordata: {
        temp: analogValue10,
        lux : analogValue11,
      }
    }]
  };
  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 kinesis3.js
light: 445 => 304
temperature: 351 => 21.4
light: 477 => 359.9
temperature: 348 => 21.3
light: 479 => 363.6
temperature: 352 => 21.4
Cognito Identity Id: us-east-1:2b10dc1b-f1f4-4779-9d49-0492e73a5a57
light: 481 => 367.5
temperature: 349 => 21.4
light: 482 => 369.4
temperature: 350 => 21.4
{ SequenceNumber: ‘49549802611433803905821669191073794678384151765993914370’,
ShardId: ‘shardId-000000000000’ }
{ SequenceNumber: ‘49549802611433803905821669191075003604203766395168620546’,
ShardId: ‘shardId-000000000000’ }
{ SequenceNumber: ‘49549802611433803905821669191076212530023381024343326722’,
ShardId: ‘shardId-000000000000’ }

SequenceNumber を取得できていますので、無事 Kinesis に Put できたようです。

6.KinesisへPUTされたデータの確認

KenTamagawa さんのブロッグでは、Mac で AWS CLI を使った方法が紹介されていました。
今回はお試しに Edison に AWS CLI を設定してみました。
参考サイトは以下です。

CentOS に AWS CLI を「pip install awscli」でインストールする手順(山下 晴規さん)
http://www.checksite.jp/centos-pip-install-awscli/

【AWS】CLIの初期設定について(認証情報とコマンド補完 tasukujpさん)
http://www.task-notes.com/entry/20141026/1414322858

以下を実行します。(詳細は上記リンクを参照ください。)

opkg install python-pip
opkg install python-setuptools
pip install awscli

which aws
/usr/bin/aws

aws –version
aws-cli/1.7.22 Python/2.7.3 Linux/3.10.17-poky-edison+

バージョンまで確認できたら無事インストールできています。
続いて設定を行います。
ACCESS_KEY_ID 他は Kinesis の権限を与えたユーザのものをご利用ください。

aws configure で設定する方法もありますが、私は適宜環境を変えるので以下を実行しています。

export AWS_ACCESS_KEY_ID=***ACCESS_KEY_ID***
export AWS_SECRET_ACCESS_KEY=***SECRET_ACCESS_KEY***
export AWS_DEFAULT_REGION=us-east-1
export AWS_DEFAULT_OUTPUT=json

aws cli で Kinesis に保管されている情報を取得します。
PUT した際の SequenceNumber を指定します。

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 “49549802611433803905821669191073794678384151765993914370”
{
“ShardIterator”: “AAAAAAAAAAFEKajskTnty44aKQLATzuRijuQNgd0xhxdAmplu/VIrTEakExnTOwTs4yMBpug9PYZOZ7kkGL5zLwBiMvHGS/W80uFCQu3qFNQaiZCW2zli7psbr6qszsC+BBdpgPehA4eieXosTpaplDN9za/m8sFaohXoi9DuG+IMqyvawCfMK3IqlSShJogx8mXXv47SLiTROByiLzuL1DZbr3eariS”
}
aws kinesis get-records –region us-east-1 –shard-iterator “AAAAAAAAAAFEKajskTnty44aKQLATzuRijuQNgd0xhxdAmplu/VIrTEakExnTOwTs4yMBpug9PYZOZ7kkGL5zLwBiMvHGS/W80uFCQu3qFNQaiZCW2zli7psbr6qszsC+BBdpgPehA4eieXosTpaplDN9za/m8sFaohXoi9DuG+IMqyvawCfMK3IqlSShJogx8mXXv47SLiTROByiLzuL1DZbr3eariS”
{
“Records”: [
{
“PartitionKey”: “xyz”,
“Data”: “eyJkZXZpY2VfaWQiOiJFZGlzb24iLCJ0aW1lIjoxNDI5MTk1MTM1ODc0LCJzZW5zb3JzIjpbeyJzZW5zb3JkYXRhIjp7InRlbXAiOjM2Ny41LCJsdXgiOjIxLjR9fV19”,
“SequenceNumber”: “49549802611433803905821669191073794678384151765993914370”
},
{
“PartitionKey”: “xyz”,
“Data”: “eyJkZXZpY2VfaWQiOiJFZGlzb24iLCJ0aW1lIjoxNDI5MTk1MTMzNzk1LCJzZW5zb3JzIjpbeyJzZW5zb3JkYXRhIjp7InRlbXAiOjM1OS45LCJsdXgiOjIxLjN9fV19”,

“SequenceNumber”: “49549802611433803905821669191075003604203766395168620546”
},
{
“PartitionKey”: “xyz”,
“Data”: “eyJkZXZpY2VfaWQiOiJFZGlzb24iLCJ0aW1lIjoxNDI5MTk1MTMyNTY0LCJzZW5zb3JzIjpbeyJzZW5zb3JkYXRhIjp7InRlbXAiOjMwNCwibHV4IjoyMS40fX1dfQ==”,
“SequenceNumber”: “49549802611433803905821669191076212530023381024343326722”
},
{
“PartitionKey”: “xyz”,
“Data”: “eyJkZXZpY2VfaWQiOiJFZGlzb24iLCJ0aW1lIjoxNDI5MTk1MTM2OTU0LCJzZW5zb3JzIjpbeyJzZW5zb3JkYXRhIjp7InRlbXAiOjM2OS40LCJsdXgiOjIxLjR9fV19”,
“SequenceNumber”: “49549802611433803905821669191154792708298331989418704898”
}
],
“NextShardIterator”: “AAAAAAAAAAEdhTkDpOeBDGzHYQ1LkbM1upgnekH8/OVxn8UOlIK6WmxEoMMBUS8skb+llha9grOrHSkyE4bGvi8OAEJexu293pALrbm5iOQzsRQL9atSbHktBc5l/1t716/dlazNql/bPIro5MLypSmBSfu//gdohjQ5m3Swb/b3eZI/I+9fr/DfW0aiVL8orYhB6S1auUjgenqtTbpCsrjhnsherhKs”
}

データはBASE64でエンコードされています。
以下のサイトを利用して、デコードしてみます。

BASE64 エンコード・デコード(酒徳峰章さん)
http://kujirahand.com/web-tools/Base64.php

{“device_id”:”Edison”,”time”:1429195136954,”sensors”:[{“sensordata”:{“temp”:369.4,”lux”:21.4}}]}

PUTしたデータを無事取得できました!

IoT_Ed-05

後は Lambada で定期的に DynamoDB に保管までさせてみたいのですね。
こちらは後日試してみる予定です。

最後に、有意義な情報を公開頂いた KenTamagawa さんはじめ、リンクさせて頂いた皆様に感謝します!

広告