CodeZine(コードジン)

特集ページ一覧

Tessel 2で取得したデータをリアルタイムにグラフ表示する

Tessel 2ではじめるお手軽IoT 第4回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2017/01/18 14:00
目次

リアルタイムグラフ

 MQTTサーバーに接続できるようになりました。次は本連載の第2回の気候センサーモジュールで計測した値をMQTTサーバーに送信し、ブラウザでリアルタイムにグラフ表示してみます。

計測データの送信

 気候センサーからデータを取得する部分については、本連載の第2回を参照してください。ただし今回のサンプルでは、Promise機能を使ってコールバックのネストを減らしています。

 3秒ごとに気候センサーから気温、湿度を取得してMQTTサーバーに送信します。

リスト2 climate.jsの一部
climate.on('ready', () => {
  // 3秒ごとに、気温、湿度を取得して送信する
  setImmediate(function loop() {
    readAll();
    setTimeout(loop, 3*1000);
  });
});

// 気温、湿度のデータ送信
function readAll() {
  // 気温、湿度のデータがそろったら送信する(3)
  Promise.all([readTemperature(),readHumidity()]).then( (values) => {
    // 現在時刻(エポック秒)
    const now = require('moment')().unix();
    // 計測結果をJSON文字列にする(4)
    const json = JSON.stringify([
      { time : now, y : values[0] }, // 温度
      { time : now, y : values[1] }  // 湿度
    ]);
    client.publish('climate', json);
    console.log(json);
  })
  .catch(function(e) {
    console.log(e);
  });
}

// 温度の取得(1)
function readTemperature() {
  return new Promise( (resolve,reject) => {
    climate.readTemperature('c', (err, temp) => {
      if (!err) { resolve(temp); }
      else { reject(err); }
    });
  });
}

// 湿度の取得(2)
function readHumidity() {
  return new Promise( (resolve,reject) => {
    climate.readHumidity( (err, humid) => {
      if (!err) { resolve(humid); }
      else { reject(err); }
    });
  });
}

 温度の取得(1)と湿度の取得(2)では、Promiseオブジェクトを作成して返しています。

 Promiseは非同期処理のデザインパターンのひとつです。「処理の途中」を意味するオブジェクトを利用することで、非同期処理をわかりやすく記述することができます。非同期処理が成功した場合はresolveメソッドを、失敗した場合はrejectメソッドを呼び出しています。

 また、温度と湿度の取得、両方の非同期処理が完了してからデータを送信するためにPromise.allメソッドを用いています(3)。thenメソッドでは、それぞれの非同期処理の結果が配列として渡されます。その配列の値と現在時刻をJSON文字列にして(4)、MQTTサーバーに送信しています。なお、非同期処理のいずれかがrejectメソッドを呼び出してエラーを返せば、即座にcatchメソッドが実行されます。

 このサンプルを実行すると、次のように送信したデータをコンソールにも出力します。

[{"time":1479021886,"y":26.836783447265624},{"time":1479021886,"y":46.417755126953125}]

 時刻がtimeで、温度/湿度がyという名のキーです。yにしているのは次に解説するグラフ表示のためです。

グラフ表示

 MQTTサーバーに計測データを送信できるようになったので、このデータをリアルタイムにグラフにしてブラウザ表示してみましょう。

 グラフ表示は、EpochというJavaScriptのグラフライブラリを利用します。Epochは表示に関して細かいカスタマイズはあまりできないようですが、リアルタイムの表示はかんたんに行うことができます。

MQTTクライアント

 MQTTクライアントはEclipse Paho JavaScript Clientを利用します。

 ただしブラウザからは、まだ直接MQTTのプロトコルを扱うことができません。そのためWebSocketを通じてMQTTのメッセージを送受信します(MQTT over WebSocket)。WebSocketはウェブサーバーとブラウザ間で双方向通信を低コストで行うためのプロトコルです。MQTTと似ていますが別のものです。なおMQTT over WebSocketを使うには、MQTTサーバー側もWebSocketに対応している必要があります。前述のEMQはデフォルトで対応しています。

HTMLの用意

 まずEpochグラフライブラリをダウンロードして解凍し、JavaScriptコードとスタイルシートを適当なところに配置しておきます(epoch.min.js、epoch.min.css)。

 HTMLで指定する外部のJavaScriptとCSSコードは次のようになります。Epochはデータをブラウザで可視化するためのライブラリであるD3.js(のバージョン3)が必要なので、合わせて指定しています。なお、jquery、d3.js、MQTTクライアントは、公開されているCDNを利用しています。

リスト3 test.htmlの一部
<link rel="stylesheet" type="text/css" href="css/epoch.min.css">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js"></script>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="js/epoch.min.js"></script>
<script src="js/graph.js"></script>

 グラフの表示部分のHTMLは、次のように<div>タグで指定しておきます。

<div id="myChart" class="epoch category10" style="width: 800px; height: 300px"></div>

 classのcategory10は、D3.jsでのCategorical Colors(色分け)の指定です。温度と湿度の線を色分けして表示するために設定しています。

JavaScriptコード

 JavaScriptのコードはグラフの初期表示とMQTTサーバーからの受信処理となります。まずグラフの初期表示です。

リスト4 graph.jsの一部
$(function(){
  // グラフの範囲を設定する(1)
  var leftRange = [-5, 40];
  var rightRange = [0, 100];

  // グラフのデータ設定(2)
  var lineChartData = [
    { label: "温度", values: [], range: leftRange },
    { label: "湿度", values: [], range: rightRange }
  ];

  // 折れ線グラフを生成する(3)
  var chart = $('#myChart').epoch({
    type: 'time.line',
    data: lineChartData,
    range: {
      left: leftRange,
      right: rightRange
    },
    axes: ['left','right','bottom'] // 表示する軸の指定
  });
  ~中略~
});

 最初にグラフ上Y軸の値の範囲(1)、表示するデータの設定(2)を行っています。データは動的に追加するため、ここでは空の配列を指定します。

 epochメソッドでグラフを生成します(3)。ここではパラメータとして、グラフの種類、データ、範囲、軸の表示を指定しています。グラフの種類はリアルタイム表示の折れ線グラフ、time.lineとしました。

 次はMQTTサーバーからの受信処理です。

リスト5 graph.jsの一部
$(function(){
  // MQTTサーバーを指定してクライアントを生成する(1)
  var client = 
    new Paho.MQTT.Client("xxx.xxx.xxx", Number(8083),
      "clientId" + new Date().getTime());

  // MQTTサーバーに接続する(2)
  client.connect({onSuccess:onConnect, onFailure: failConnect});

  // サーバーに接続したとき(3)
  function onConnect() {
    client.subscribe("climate"); // topicを指定する
  }

  // メッセージを受信したとき(4)
  client.onMessageArrived = function(message) {
    // 受信したJSON文字列をデコードする
    const d = $.parseJSON(message.payloadString);
    chart.push(d); // 折れ線グラフにデータを追加する
  }

  ~中略~
});

 最初にMQTTサーバーを指定してクライアントオブジェクトを生成します(1)。ポートはMQTTサーバーのWebsockets用のポートとします。3つめのパラメータはクライアントの識別コードです。

 次にconnectメソッドでMQTTサーバーに接続します(2)。パラメータには正常に接続した時と失敗した時のコールバック先を指定しています。

 サーバー接続時のコールバックでは、subscribeメソッドでtopicを指定しています(3)。

 メッセージを受信したときのコールバックはonMessageArrivedプロパティに設定します(4)。受信したメッセージ本体は受信データオブジェクトのpayloadStringプロパティに格納されているので、それをデコードしてグラフオブジェクトに追加します。Tessel 2側で出力している値がグラフのデータフォーマットになっているので、そのままpushメソッドに渡しています。1つのデータはUNIXタイムとY軸に表示する値のペアで、それぞれtime、yという名のプロパティになっています。

ブラウザ表示

 ブラウズで表示すると次のようなグラフ表示となります。データを受信するたびにリアルタイムに右から左にグラフが伸びていきます。

リアルタイムグラフ表示
リアルタイムグラフ表示

最後に

 今回はMQTTサーバーを使い、Tessel 2で計測した値をリアルタイムに表示しました。オープンソースのサーバーやライブラリを活用すれば、このようなこともシンプルなコードで実現できます。

 Tessel 2はRaspberry PiのようにOSのインストールから行う必要もなく、手軽にNode.jsでハードウェアを操作することができます。国内でも早く正式に販売されることを願っています。

参考資料



  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:Tessel 2ではじめるお手軽IoT

著者プロフィール

  • WINGSプロジェクト 高江 賢(タカエ ケン)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5