Node.js(2) GPIO

Raspberry PiにNode.jsをインストールして、ExpressフレームワークでWebアプリを簡単に作成して動かすことができたが、何もデバイスを制御しない状態ではRaspberry Piを使う意味が無いので、まずはGPIOを制御するモジュールを追加して簡単な制御を行ってみる。

Node.jsのRaspberry Pi用GPIOパッケージは何種類も存在していて、ざっと調べてみた限りでは以下の三種類が良く使われているようだ。

  1. pi-gpio
  2. rpi-gpio
  3. onoff

今回はその三種類の中からonoffを試してみたが、最初に目についたというだけで特に理由はない。他のパッケージでも恐らく同様に使えるはず。

インストールはExpressでプロジェクトのひな型(プロジェクト名はledとする)を作ってからそのディレクトリに移動して

$ express -e led
$ cd led
$ npm install
$ npm install onoff

を実行するか、あるいは生成されたpackage.jsonにパッケージ名”onoff”を追加してから npm install を行えば良い。

{
  "name": "led",
  "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",
    "onoff": "~1.0.2"
  }
}

このパッケージを使用してGPIO操作を行う場合、ユーザがgpioグループに属していればルート権限が不要なのでデフォルトの「pi」ユーザならそのままで使えるが、新たに作成したユーザでログインしている場合はsudoを付けてNode.jsを起動するか、あるいはそのユーザをgpioグループに属させる必要がある。

$ sudo gpasswd -a ユーザID gpio

GPIO操作のサンプルとして、まずは定番のLED点滅を行ってみる。
GPIOの適当なポートにLEDと電流制限抵抗をつなぎ、ポートに”1″を出力すると点灯、”0″を出力すると消灯する状態になっている場合、ブラウザからの操作でLEDをON/OFFするには/routes/users.jsファイルに以下のようなコードを書く。LEDはGPIO17(ピン番号11)に接続した。

var express = require('express');
var router = express.Router();

var GPIO = require('onoff').Gpio;
var led = new GPIO(17, 'out');

/* GET users listing. */
router.get('/', function(req, res, next) {
  console.log(req.query);
  var onoff = req.query.onoff;
  var msg = '';
  if (onoff == 'on') {
    led.writeSync(1);
    msg = 'LED ON';
  }
  if (onoff == 'off') {
    led.writeSync(0);
    msg = 'LED OFF';
  }
  res.send(msg);
});

module.exports = router;

ブラウザからHTTPのGETでパラメータが送られてきた時、”onoff”の値が”on”ならばLEDを点灯、”off”ならば消灯という動きをするので、本来ならばブラウザで表示するHTMLファイルを作成しなければならないが、動作を試すだけならばGETのパラメータを直接URLに書いて確認できる。

プロジェクトのディレクトリに移動して

$ npm start

でWebアプリを起動した後、サーバが起動して待受け状態になるまで少し待ってから、PCのブラウザで以下のようにアクセスする。

Raspberry PiのIPアドレス:3000/users?onoff=on

スクリーンショット 2015-05-12 10.38.35
全て正しければこれでRaspberry PiのGPIOに接続したLEDが点灯するはず。URLの最後を”onoff=off”に変えれば消灯する。

動作が確認できたら次にクライアント(ブラウザ)用のHTMLファイルを作成する。/routes/users.jsに対応するファイルなので、分かりやすいように/views/users.ejsというファイル名で新規に作成する。拡張子がHTMLでは無いのは、HTMLレンダリングエンジンEJSがこのファイルを変換するため。
expressフレームワークのデフォルトはJADEエンジンなので、-eオプションを付けずにひな型を生成した場合は拡張子を.jadeにしなければならない。

/views/users.ejsファイルの内容は以下のようにする。

<!DOCTYPE html>
<html>
  <head>
    <title>raspi-node.js</title>
    <style type="text/css">
    input.button {
      width: 150px;
      height: 50px;
      font-size: 1.8em;
    }
    img.led {
      width: 100px;
      height: 100px;
    }
    </style>
  </head>
  <body>
    <% if (message == "on") { %>
    <img src="/images/led-on.png" class="led">
    <% } %>
    <% if (message == "off") { %>
    <img src="/images/led-off.png" class="led">
    <% } %>
    <form method="GET" action="/users">
      <input type="submit" name="onoff" value="on" class="button"/>
      <input type="submit" name="onoff" value="off" class="button"/>
    </form>
  </body>
</html>

LEDのON/OFF状態は画像で表すことにしたので、以下の画像ファイルをプロジェクトの/public/imagesディレクトリに入れておく。
led-onled-off

ブラウザへはEJSレンダリングエンジンで生成したHTMLファイルを送信するので、/routes/users.jsファイルの内容を以下のようにする。

var express = require('express');
var router = express.Router();

var GPIO = require('onoff').Gpio;
var led = new GPIO(17, 'out');

/* GET users listing. */
router.get('/', function(req, res, next) {
  console.log(req.query);
  var onoff = req.query.onoff;
  if (onoff == 'on') {
    led.writeSync(1);
  }
  if (onoff == 'off') {
    led.writeSync(0);
  }
  res.render('users', {message: onoff});
});

module.exports = router;

以前は”res.send”でブラウザに対して文字列を送信していた部分が、”res.render”に変わっている。これは指定したファイルをレンダリングエンジンでHTMLファイルに変換してからブラウザへ送信するという意味になる。

このWebアプリを起動してPCのブラウザからアクセスすると、on/offの2つのボタンが表示されるので、onをクリックするとGPIOポートに接続したLEDが点灯し、ブラウザに点灯したLEDの画像が表示されるはず。offをクリックすると画像が変わる。
同じネットワーク内の他のPCのブラウザからアクセスした場合でも、同様にLEDのOn/Offが行えるはずだ。
スクリーンショット 2015-05-12 16.32.02
画像が変化するのはEJSレンダリングエンジンがパラメータによってimgタグの画像ファイル名を変えたHTMLファイルを生成し、それをブラウザに送信しているからで、/views/users.ejsファイルの以下の記述がそれを行っている部分。

    <% if (message == "on") { %>
    <img src="/images/led-on.png" class="led">
    <% } %>
    <% if (message == "off") { %>
    <img src="/images/led-off.png" class="led">
    <% } %>

かなり長くなってしまったので今回はここまで。次はWebSocketを使ってリアルタイムにサーバとブラウザ間で通信を行うアプリを作成してみる予定。

広告

コメントを残す

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

WordPress.com ロゴ

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

Twitter 画像

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

Facebook の写真

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

Google+ フォト

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

%s と連携中