Node.js(4) I2C

Webサーバとクライアント(ブラウザ)間でコネクションを維持したまま通信を行うsocket.ioライブラリを、Node.jsで使用してWebアプリを作成するのは思ったよりも簡単に出来た。socket.ioを使用するとブラウザ側からリクエストを送出する事無く、サーバ側から自動的に配信を行うPUSH型のアプリを作成できるので、今回はそれを試してみる。

Raspberry PiのGPIOポートにスイッチを付けてその状態を配信するだけでも良いのだが、シンプル過ぎて面白く無いので以前Pythonで使ってみた加速度センサモジュールを今回も使用した。加速度センサモジュールについてはここを参照。

前回と同じようにexpressフレームワークが生成したコードのpackage.jsonに、必要なライブラリの定義を追加。Raspberry Pi用のI2Cパッケージはいくつか存在するようだが、今回はこれを使用した。

{
  "name": "i2c_acc",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.12.0",
    "cookie-parser": "~1.3.4",
    "debug": "~2.1.1",
    "ejs": "~2.3.1",
    "express": "~4.12.2",
    "morgan": "~1.5.1",
    "serve-favicon": "~2.2.0",
    "socket.io": "^1.3.5",
    "i2c": "~0.2.1"
  }
}

加速度センサからのデータ読み出しと、socket.ioによる通信はアプリケーションのエントリポイント”/bin/www”で、サーバオブジェクト生成後に呼び出されるapp_i2c.jsに記述。

var express = require('express');
var router = express.Router();
var i2c = require('i2c');
var addr = 0x1d;
var wire = new i2c(addr, {device: '/dev/i2c-1'});

function signed(n) {
  return (n < 128) ? n : n - 256; 
}

function app_i2c(server) {
  var io = require('socket.io')(server);
  wire.writeBytes(0x16, [0x05], function(err, res){});
  wire.writeBytes(0x10, [0,0,0,0,0,0], function(err, res){});
  setInterval(function() {
    wire.readBytes(0x06, 3, function(err, res){
      io.sockets.emit('event', {
        x: signed(res[0]),
        y: signed(res[1]),
        z: signed(res[2]),
      });
    });
  }, 100);
}

module.exports = app_i2c;

加速度センサを初期化した後、100msec周期でx,y,z値を読み出し、接続されているすべてのクライアントに対してその値を送信している。

クライアント側はHTMLファイルにx,y,z値表示用の項目と、グラフ描画用のCanvasを定義。

<!DOCTYPE html>
<html>
  <head>
    <title>raspi-node.js</title>
    <style type="text/css">
      li { font-size: 1.8em; }
      canvas { border: 1px solid #999; }
    </style>
  </head>
  <body>
    <ul>
      <li id="accx">x</li>
      <li id="accy">y</li>
      <li id="accz">z</li>
    </ul>    
    <canvas id="cv" width="500" height="155"></canvas>
    <script src="/socket.io/socket.io.js"></script>
    <script src="/javascripts/client.js"></script>
  </body>
</html>

クライアント側のJavaScriptでsocket.ioから受信したx,y,xの値をDOMで表示し、Canvasに対して四角を描画する処理を行っている。

var socket = io.connect();
var cv = document.getElementById("cv");
var ctx = cv.getContext('2d');
ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
ctx.shadowBlur = 3;
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;

socket.on('connect', function() {
  console.log('connect');
  var accx = document.getElementById("accx")
  var accy = document.getElementById("accy")
  var accz = document.getElementById("accz")
  socket.on('event', function(data) {
    accx.innerHTML = "x: " + data.x;
    accy.innerHTML = "y: " + data.y;
    accz.innerHTML = "z: " + data.z;
    ctx.fillStyle = '#FFF';
    ctx.fillRect(0, 0, 500, 300);
    ctx.fillStyle = '#F00';
    ctx.fillRect(250, 5, data.x * 2, 45);
    ctx.fillStyle = '#0F0';
    ctx.fillRect(250, 55, data.y * 2, 45);
    ctx.fillStyle = '#00F';
    ctx.fillRect(250, 105, data.z * 2, 45);
  });
});

プロジェクトの全コードはGitHubに置いた

i2Cデバイスへのアクセスはユーザがルート権限かi2cグループへ所属している必要があるので、デフォルトのpiユーザ以外のユーザを作成して使っている場合は

sudo gpasswd -a ユーザID i2c

でグループに追加しておく必要がある。再起動しないと実際には追加されないので注意。

GitHubからクローンしたアプリは前回同様に

$ git clone https://github.com/tokoya/i2c_acc.git  
$ cd i2c_acc  
$ npm install  
$ npm start

でインストールしてから起動する。起動後に「Raspberry PiのIPアドレス:3000/users」へPCのブラウザからアクセスして

スクリーンショット 2015-05-22 16.56.57

このように表示されればOK。加速度センサを傾けると棒グラフがリアルタイムに動くはずだ。

全く同じ加速度センサモジュールを持っていないと実際には試せないが、I2Cインタフェースを持つセンサ類であれば、同じようにしてブラウザで値を表示させることができるので、試してみて欲しい。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中