この記事はisaaxアドベントカレンダー2018 9日目の記事です。

AWS DynamoDBはAWSの提供するNoSQL型のデータベースで、RESTfulなインタフェースでデータを登録したり、更新できます。一般的なデータベースのように接続処理がなく、RESTfulで使えるのはIoT向きと言えます。

今回はこのAWS DynamoDBを使ってisaaxプロジェクトのデータ保存、そしてデータ可視化を実現します。

DynamoDBのテーブルを作成する

DynamoDBは一つの巨大なデータベースであり、テーブルを作成して、データをテーブル単位で管理します。コードでテーブルの作成もできますが、今回は管理画面から行います。

作成したら、DynamoDBにフルアクセスできるIAMを作成します。

認証キーなどは以下のフォーマットでJSONファイル(今回は config.json )にします。 region はDynamoDBのテーブルを作成したリージョンです。

{
  "accessKeyId": "YOUR_ACCESS_KEY_ID",
  "secretAccessKey": "YOUR_SECRET_ACCESS_KEY",
  "region": "DYNAMODB_REGION"
}

プロジェクトのコードを書く

isaaxプロジェクトを作成します。

今回はセンサーではなくIoTデバイスのCPU温度を使います。まずDynamoDBの準備をします。プログラミング言語はNode.jsを使います。

const AWS = require('aws-sdk'); 
const deviceId = 'pi';
AWS.config.loadFromPath('./config.json');
const dynamodb = new AWS.DynamoDB();
const tableName = 'isaax';

// CPU温度の取得用
const {exec} = require('child_process');
// Promise処理用
const {promisify} = require('util');

そしてCPU温度を取得します。

const {stdout, stderr} = await promisify(exec)('vcgencmd measure_temp');
const temp = parseFloat(stdout.replace(/temp=([0-9\.]*)'C/, '$1'));

その値を使いつつ、データを保存します。

const params = {
  TableName: tableName,
  Item: {
    device : {S: deviceId},
    value: {N: temp.toString()},
    timestamp: {N: Date.now().toString()},
    id: {S: Date.now().toString()}
  }
};
// DynamoDBに保存
dynamodb.putItem(params).promise()
  .then((err, data) => {
    if (err) {
      console.error(err);
    }
  });

データを可視化する

データが保存できたら、次に可視化処理を作ります。Lambdaを使ったとしても、何らかのサーバが必要になるので、今回は簡易的なWebサーバを作成します。DynamoDBの値を取得してJSONで返却するだけのサーバです。

このサーバはDynamoDBを検索していますが、その際に時間(タイムスタンプ)を指定しています。2回目以降のデータ取得時には最後のタイムスタンプを指定しているので、過剰にデータを取ることはありません。

app.get('/data.json', async (req, res) => {
  console.log(req.query);
  try {
    const items = await getItem(req.query.t);
    res.send(items)
  } catch (e) {
    res.status(503).send(e);
  }
});

const getItem = (t) => {
  return new Promise((res, rej) => {
    const params = {
      TableName : tableName,
      FilterExpression : "#ts > :val",
      ExpressionAttributeValues : {":val" : parseInt(t)},
      ExpressionAttributeNames: {
        '#ts' : 'timestamp'
      }
    };
    dynamo.scan(params, (err, data) => {
      if (err) {
        return rej(err);
      }
      res(data);
    });
  })
}

後はこれをWebブラウザのJavaScriptから定期的に呼び出してグラフライブラリであるEpochで表示します。まずグラフを定義します。

let t = 0;
const chart = $('#area').epoch({
  type: 'time.line',
  data: [{
    label: 'pi',
    values: []
  }],
  axes: 'right'
});

次にデータを取得して表示します。

setInterval(async () => {
  const data = await $.ajax({
    url: `/data.json?t=${t}`
  })
  for (const item of data.Items) {
    if (t < item.timestamp) {
      t = item.timestamp;
      chart.push([{
        time: parseInt(item.timestamp / 1000),
        y: item.value
      }]);
    }
  }
}, 5000);

実際に動作しているところです。5秒ごとに新しいデータを取得して表示を更新します。


DynamoDBの場合、WebSocketがなく、データ追加された際にはLambdaを呼び出す仕組みです。LambdaではWebSocketが利用できないので(常時接続できないので)、何らかのサーバが必要になります。リアルタイムの可視化を実現するのは若干面倒ですが、AWSのスケーリング能力を活かした小規模から大規模な案件までこなせるIoTプロジェクトには必須の存在と言えるでしょう。

今回のコードはgoofmint/isaax-dynamodb-demoにアップロードしてあります。実装時の参考にしてください。

ぜひ皆さんのIoTプロジェクトでもご利用ください。


Leave a Reply

Your email address will not be published. Required fields are marked *