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

IoTではセンサーデータを受け取って、可視化するのが基本的な使い方ではないでしょうか。その際に必要になるのが、センサーから随時上がってくるデータを格納しておく場所と、それをリアルタイムに可視化する方法です。

今回はisaaxプロジェクトからFirebaseへデータを保存し、さらにそれをグラフ化してみたいと思います。Firebaseにはリアルタイムデータベース機能があり、まさにセンサーデータを可視化するのにぴったりな使い方が実現できます。

Firebaseプロジェクトの作成

まずFirebaseへアクセスして新しいプロジェクトを作成します。この時、プロジェクトIDが生成されますので覚えておきましょう。

そしてデータベースを作成します。利用するのはCloud Firestoreではないのですが、作成しないといけないようです。

作成したら、上にあるメニューでRealtime Databaseに切り替えます。ここにデータが保存されます。

今回はセキュリティのルールとして、read を true にしています。これで認証なしで読み込みできるデータが作成されます。

認証キーの作成

次にFirebaseにデータを保存するための認証キーを作成します。設定のサービスアカウントで作成できます。この時生成されるJSONファイルは間違っても公開されることがないよう注意しましょう。今回は isaax-demo-firebase-adminsdk-p27d1-914f648c7d.json というファイル名になります。

デバイスのコード

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

今回はデモとして、デバイスの温度をとって、それをFirebaseに保存します。このコードはシンプルなもので、以下のようになります。今回はNode.jsを使っています。

const admin = require("firebase-admin");
const {exec} = require('child_process');
const {promisify} = require('util');
const deviceId = 'pi';
const collectionId = 'cpu';
const firebaseUrl = 'https://isaax-demo.firebaseio.com';
const serviceAccount = require("./isaax-demo-firebase-adminsdk-p27d1-914f648c7d.json");

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: firebaseUrl
});
const db = admin.database();
const ref = db.ref(collectionId);
// 5秒ごとに温度を取得してFirebaseに保存する
setInterval(async () => {
  try {
    // CPU温度の取得
    const {stdout, stderr} = await promisify(exec)('vcgencmd measure_temp');
    const temp = parseFloat(stdout.replace(/temp=([0-9\.]*)'C/, '$1'));
    
    // Firebaseに保存する処理
    const obj = ref.child("temp");
    obj.push({
      device: deviceId,
      timestamp: Date.now(),
      value: temp
    });
  } catch (e) {
    console.log(e)
  }
}, 5000);

認証ファイルのアップロード

認証ファイルはGitリポジトリに含められません。そこで一度クラウド上のサーバ(今回はAmazon S3)にアップロードします。そしてisaaxのpre-updateスクリプトを使ってダウンロードします。

wget https://path/to/auth.json -O /var/isaax/project/auth.json

例えば、上記のように設定することで処理前に認証ファイルをダウンロードしてくれます。一度ダウンロードしてしまえばファイルは削除し、post-updateスクリプトも実行しなくていいでしょう。

データを表示する

ここまでの処理でデータをFirebaseに保存できるようになりました。続いてデータの表示処理を作ります。グラフを用いた可視化にはEpochというライブラリを用いています。

FirebaseにはWebアプリ用のAPIキーがあります。これはWebSocketを使ってデータを取得できるものです。まず設定を行います。 tbl はFirebaseのテーブルオブジェクトになります。

const config = {
  apiKey: "YOUR_API_KEY",
  authDomain: "isaax-demo.firebaseapp.com",
  databaseURL: "https://isaax-demo.firebaseio.com",
  storageBucket: "bucket.appspot.com"
};

firebase.initializeApp(config);
const collectionId = 'cpu/temp';
const db = firebase.database();
const tbl = db.ref(collectionId);

そうすると tblvalue イベントと child_added イベントが指定できます。それぞれ、全データが返ってくるものと、新しいデータが追加されたタイミングで実行されるイベントです。

初期表示時にはデータをグラフに登録し、イベント購読をやめています。そうしないと新しいデータが来るたびに全データが取得されてしまってネットワークコストが大きくなります。

// 初期データ取得時の処理
tbl.on('value', data => {
  const values = data.val();
  const params = [];
  let device = '';
  for (const key in values) {
    const data = values[key];
    device = data.device;
    params.push({
      time: parseInt(data.timestamp / 1000),
      y: data.value
    });
  }
  chart = $('#area').epoch({
    type: 'time.line',
    data: [{
      label: device,
      values: params
    }],
    axes: 'right'
  });
  tbl.off('value');
});

新しいデータが来た時には child_added イベントを使います。

// 新しいデータが追加された時のイベント
tbl.on('child_added', val => {
  const values = val.val();
  chart.push([{
    time: parseInt(values.timestamp / 1000),
    y: values.value
  }]);
});

このようにすることでEpochを使ってリアルタイムグラフが描けるようになります。


Firebaseのリアルタイムデータベースを使うことで、IoTデバイスからのセンサーデータの保存と、そのリアルタイムな可視化が実現できます。Realtime Databaseはスキーマ型ではないので使い慣れるまでは若干難しいかも知れませんが、センサーデータのように複雑ではない構造を扱うのはとても簡単です。

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

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


Leave a Reply

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