wonder gadget

ガジェットはインターネットの夢をみるか? Intel edisonを中心に IoT, MAKE, Physical Computingしていきます。

WICED Senseのデータをリアルタイムにグラフ表示してみる

前回の記事でWICED Senseのファームウェアを変更してセンサーデータの通知間隔を長くしたので、そのままMQTTに送り、そのデータをウェブブラウザ上でグラフ表示してみたいと思います。

WICED Senseのファームウェアを変更してみる - wonder gadget

まずはセンサーデータをMQTTに送る部分をしきい値で弾かずに全部送るようにします。

WICED Sense/accelerometer: {"x":4,"y":1,"z":86,"date":"2015-02-18T11:49:06.798Z"}
WICED Sense/gyroscope: {"x":-101,"y":57,"z":-366,"date":"2015-02-18T11:49:06.798Z"}
WICED Sense/magnetometer: {"x":1599,"y":-173,"z":-929,"date":"2015-02-18T11:49:06.798Z"}
WICED Sense/accelerometer: {"x":4,"y":1,"z":86,"date":"2015-02-18T11:49:07.293Z"}
WICED Sense/gyroscope: {"x":-105,"y":51,"z":-352,"date":"2015-02-18T11:49:07.293Z"}
WICED Sense/magnetometer: {"x":1604,"y":-166,"z":-939,"date":"2015-02-18T11:49:07.293Z"}
WICED Sense/accelerometer: {"x":4,"y":2,"z":86,"date":"2015-02-18T11:49:07.788Z"}
WICED Sense/gyroscope: {"x":-93,"y":12,"z":-335,"date":"2015-02-18T11:49:07.788Z"}
WICED Sense/magnetometer: {"x":1590,"y":-156,"z":-941,"date":"2015-02-18T11:49:07.788Z"}
WICED Sense/accelerometer: {"x":4,"y":2,"z":86,"date":"2015-02-18T11:49:08.283Z"}
WICED Sense/gyroscope: {"x":-96,"y":82,"z":-529,"date":"2015-02-18T11:49:08.283Z"}
WICED Sense/magnetometer: {"x":1594,"y":-157,"z":-936,"date":"2015-02-18T11:49:08.283Z"}
WICED Sense/accelerometer: {"x":4,"y":2,"z":87,"date":"2015-02-18T11:49:08.779Z"}
WICED Sense/gyroscope: {"x":-158,"y":77,"z":-475,"date":"2015-02-18T11:49:08.779Z"}
WICED Sense/magnetometer: {"x":1608,"y":-170,"z":-927,"date":"2015-02-18T11:49:08.779Z"}
WICED Sense/accelerometer: {"x":4,"y":1,"z":85,"date":"2015-02-18T11:49:09.274Z"}
WICED Sense/gyroscope: {"x":-142,"y":83,"z":-414,"date":"2015-02-18T11:49:09.274Z"}
WICED Sense/magnetometer: {"x":1588,"y":-161,"z":-936,"date":"2015-02-18T11:49:09.274Z"}
WICED Sense/accelerometer: {"x":4,"y":1,"z":85,"date":"2015-02-18T11:49:09.769Z"}
WICED Sense/gyroscope: {"x":-115,"y":47,"z":-410,"date":"2015-02-18T11:49:09.769Z"}
WICED Sense/magnetometer: {"x":1600,"y":-170,"z":-924,"date":"2015-02-18T11:49:09.769Z"}
WICED Sense/accelerometer: {"x":4,"y":1,"z":86,"date":"2015-02-18T11:49:10.263Z"}
WICED Sense/gyroscope: {"x":-103,"y":57,"z":-361,"date":"2015-02-18T11:49:10.263Z"}
WICED Sense/magnetometer: {"x":1582,"y":-166,"z":-932,"date":"2015-02-18T11:49:10.263Z"}

これはMQTTサブスクライバー側で受信したデータですが、おおよそ500ms毎に送信されているのがわかります。

サブスクライバーはこのデータをブラウザにWebSocketを用いて送信することにします。

var mqtt = require('mqtt')
  , client = mqtt.connect('mqtt://admin:password@127.0.0.1:61613');
var WsServer = require('ws').Server;
var date = require('date-utils');
var sprintf = require('sprintf-js').sprintf;

var accelerometerWs = new WsServer({
    host: 'localhost',
    port: 8016
});

var gyroscopeWs = new WsServer({
    host: 'localhost',
    port: 8017
});

var magnetometerWs = new WsServer({
    host: 'localhost',
    port: 8018
});

client.subscribe('WICED Sense/#');

client.on('message', function(topic, message) {
  console.log(topic + ": " + message);
  data = JSON.parse(message);
  t = topic.split("/");

  var dt = new Date(data["date"]);
  data["date"] = dt.toFormat("HH24:MI:SS") + sprintf(".%03d", dt.getMilliseconds());

  if(t[1] == 'accelerometer') {
    var dataAry = [data["date"], data["x"], data["y"], data["z"]];
    accelerometerWs.clients.forEach(function(client) {
      client.send(JSON.stringify(dataAry));
    });
  }
  else if(t[1] == 'gyroscope') {
    var dataAry = [data["date"], data["x"], data["y"], data["z"]];
    gyroscopeWs.clients.forEach(function(client) {
      client.send(JSON.stringify(dataAry));
    });
  }
  else if(t[1] == 'magnetometer') {
    var dataAry = [data["date"], data["x"], data["y"], data["z"]];
    magnetometerWs.clients.forEach(function(client) {
      client.send(JSON.stringify(dataAry));
    });
  }
});

WebSocketは初めて実装してみましたが、サーバーを作成してclient.sendで送るだけなのでとてもシンプルですね。

<script src="http://ccchart.com/js/ccchart.js" charset="utf-8"></script>
<canvas id="accelerometer"></canvas>
<canvas id="gyroscope"></canvas>
<canvas id="magnetometer"></canvas>
<script>
var chartdata85 = {

  "config": {
    "title": "",
    "type": "bezi2",
    "lineWidth": 2,
    "xScaleSkip": 3,
    "maxWsColLen": 36,
    "width": 1200,
    "height": 300,
    "colorSet":
          ["#FF0000","#00FF00","#0000FF"]
  },

  "data": [
    ["時分秒"],
    ["x"],
    ["y"],
    ["z"]
  ]
};

  var chartdata_a = JSON.parse(JSON.stringify(chartdata85));
  chartdata_a["config"]["title"] = "Accelerometer";

  ccchart.wsCloseAll();
  ccchart
      .init('accelerometer', chartdata_a)
      .ws('ws://localhost:8016')
      .on('message', ccchart.wscase.oneColAtATime)

  var chartdata_g = JSON.parse(JSON.stringify(chartdata85));
  chartdata_g["config"]["title"] = "Gyroscope";

  ccchart.wsCloseAll();
  ccchart
      .init('gyroscope', chartdata_g)
      .ws('ws://localhost:8017')
      .on('message', ccchart.wscase.oneColAtATime)

  var chartdata_m = JSON.parse(JSON.stringify(chartdata85));
  chartdata_m["config"]["title"] = "Magnetometer";

  ccchart.wsCloseAll();
  ccchart
      .init('magnetometer', chartdata_m)
      .ws('ws://localhost:8018')
      .on('message', ccchart.wscase.oneColAtATime)

</script>

グラフを3つ用意したので、ポートを3つに分けてみました。 chartdataを再利用するためにオブジェクトの複製をしています。一度JSONにしてパースしなおすといういまいちなコードですが、これでオブジェクトが複製できます。 jQueryなどを使っていればextend()を利用してオブジェクトの複製ができるようです。=で代入するとグラフがすべて同じ値を表示するので、chartdataを複製するようにしてみました。

こちらの記事を参考にさせていただきました。

このHTMLソースを保存してブラウザで表示します。 センサーデータを受け取るプログラムとMQTTサブスクライバーのプログラムをnodeで実行しておきます。

f:id:daikimura:20150218121906p:plain

WICED Senseを振ったり回したりすると各グラフがリアルタイムで変動していきます。 比較的簡単なコードでここまでできるとなかなか面白いですね。 センサーデータは数値で見てもいまいちよく分からないので、可視化すると良いと思いました。

可視化のために使ったのはccchartというWebSocketのデータをcanvasにグラフとして描画してくれるライブラリです。 グラフの種類も多く、コードも手軽にかけるのでとても便利です。

ccchart

上記のコードを書くに辺り、以下の記事を参考にしました。感謝!!