CHIRIMENをNode.jsで使用してみる⑵ ー GPIO編 ー

## はじめに
本記事では、複数回に分けてCHIRIMENコミュニティが提供しているnpmパッケージnode-web-gpioとnode-web-i2cを使用してNode.jsからGPIOとI2Cを制御するために私が実施した方法とそのサンプルコードを記載した備忘録になっています。
今回は[前回の記事](https://qiita.com/okojon/items/58726940ef51d1c4a74c)に引き続きExamplesにあるGPIO ExamplesのコードをNode.jsから実行可能にする方法について説明していきます。

## コードの主な違い
Webブラウザ版とNode.js 版でのコードの主な違いについて説明します。

- navigator()関数がNode.jsでは使用不可、記述する必要がないため削除する。
- sleep()関数がNode.js には存在しないため、使用する場合は適宜実装する必要がある。
- その他、HTML下では動作するがNode.js下では動作しない記法を変更する必要がある。<br> ex)下記GPIO-Buttonなどの"ledPort.write(val === 0 ? 1 : 0);"という表記はNode.js では使用できない。

## GPIO-Blink
CHIRIMENからLEDを点滅させるGPIO-Blinkについて説明します。

### 使用パーツ
- LED x 1
- 抵抗（100Ω〜470Ω） x 1 (220Ωのカラーコード:赤赤茶金)
- ジャンパー線（オス・メス） x 2
- ブレッドボード x 1

### 配線
以下の図のように配線してください。
![schematic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1797679/da26a2f5-b2e6-bf7c-a0e3-731146cb6d6f.png)

### Webブラウザ版のJavaScript
```JavaScript
// プログラムの本体となる関数です。await で扱えるよう全体を async 関数で宣言します。
async function main() {
  // 非同期関数は await を付けて呼び出します。
  const gpioAccess = await navigator.requestGPIOAccess(); // GPIO を操作する
  const port = gpioAccess.ports.get(26); // 26 番ポートを操作する

  await port.export("out"); // ポートを出力モードに設定

  // 無限ループ
  while (true) {
    // 1秒間隔で LED が点滅します。
    await port.write(1); // LED を点灯
    await sleep(1000); // 1000 ms (1秒) 待機
    await port.write(0); // LED を消灯
    await sleep(1000); // 1000 ms (1秒) 待機
  }
}

// await sleep(ms) と呼ぶと、指定 ms (ミリ秒) 待機
// 同じものが polyfill.js でも定義されているため省略可能
function sleep(ms) {
  return new Promise(function (resolve) {
    setTimeout(resolve, ms);
  });
}

// 宣言した関数を実行します。このプログラムのエントリーポイントです。
main();
```

### Node.js版のJavaScript
"gpio-ledblink.js"というファイル名で下記のコードを保存してください。
このNode.jsでは、LEDが5回点滅すると処理が終了します。

```JavaScript
// node-web-gpioを呼び出すおまじない
const { requestGPIOAccess } = require("node-web-gpio");

// sleep関数の実装
const sleep = require("util").promisify(setTimeout);

async function blink() {
    const gpioAccess = await requestGPIOAccess();

    // LEDの接続されているポートの指定
    const port = gpioAccess.ports.get(26);
    await port.export("out");
    
    // 点滅した回数を指定する引数 i
    var i = 0;

    while (i < 5) {
      await port.write(1);
      await sleep(1000);
      await port.write(0);
      await sleep(1000);
      i = i + 1;
    }
}

blink();
```

### 実行してみよう
下記のようにコマンドラインから実行し、LEDが５回点滅すれば成功です。

```
% node gpio-ledblink.js
```

## GPIO-Button
CHIRIMENからタクトスイッチの入力を読み込み、タクトスイッチを押すとLEDが点灯、離すと消灯します。なお、GPIOポートの読み込みにはonchange関数を使用しています。

### 使用パーツ
- タクトスイッチ x 1
- LED x 1
- 抵抗（100Ω〜470Ω） x 1 (220Ωのカラーコード:赤赤茶金)
- ジャンパー線（オス・メス） x 4
- ブレッドボード x 1

### 配線
以下の図のように配線してください。
![schematic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1797679/296207e0-08f5-06a4-14cc-0c53887e37cc.png)

### Webブラウザ版のJavaScript
```JavaScript
main();

async function main() {
  var gpioAccess = await navigator.requestGPIOAccess();
  var ledPort = gpioAccess.ports.get(26); // LEDの付いているポート
  await ledPort.export("out");
  var switchPort = gpioAccess.ports.get(5); // タクトスイッチの付いているポート
  await switchPort.export("in");
  switchPort.onchange = function(val) {
    // スイッチはPullupで離すと1なので反転させる
    ledPort.write(val === 0 ? 1 : 0);
  };
}
```

### Node.js版のJavaScript
"gpio-button.js"というファイル名で下記のコードを保存してください。
このNode.jsでは、タクトスイッチを押すとLEDが点灯し、離すと消灯します。5回繰り返すと終了します。

```JavaScript
// タクトスイッチでLEDの点灯を行うチュートリアル
const { requestGPIOAccess } = require("node-web-gpio");

async function button() {
    const gpioAccess = await requestGPIOAccess();

    // LEDの接続されているポートの指定
    const ledPort = gpioAccess.ports.get(26);
    await ledPort.export("out");

    // タクトスイッチの接続されているポートの指定
    const switchPort = gpioAccess.ports.get(5);
    await switchPort.export("in");

    // 点灯回数をカウントする引数cnt
    var cnt = 0;

    switchPort.onchange = function(val) {
        // ボタンを押すと点灯、離すと消灯する
	    if (cnt > 9 && val.value == 0){
            console.log("Light : OFF");
	        process.exit(1);
	    }

	    if(val.value == 1){
	        ledPort.write(0);
            console.log("Light : OFF");
            cnt = cnt + 1;
        } else if(val.value == 0){
            ledPort.write(1);
            console.log("Light : ON");
	        cnt = cnt + 1;
	    }
    };
}

button();
```

### ​実行してみよう
下記のようにコマンドラインから実行し、タクトスイッチを押すとLEDが点灯し、離すと消灯すれば成功です。

```
% node gpio-button.js
Light : OFF
Light : ON
Light : OFF
Light : ON
Light : OFF
```

## GPIO-readGpioValue
CHRIMENからタクトスイッチの状態（押されているか、押されていないか）をコンソールへ出力します。なお今回は、GPIO-Buttonとは異なり、GPIOポートの読み込みにread関数を使用したポーリング処理によって読み込みを実現しています。

### 使用パーツ
- タクトスイッチ x 1
- ジャンパ線（オス・メス）x 2
- ブレッドボード x 1

### 配線
以下の図のように配線してください。
![schematic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1797679/e9ef9109-61e3-71df-21c1-caec9fd9212e.png)

### Webブラウザ版のJavaScript
```JavaScript
main();

async function main() {
  var gpioAccess = await navigator.requestGPIOAccess();
  console.log("GPIO ready!");
  var port = gpioAccess.ports.get(5);
  await port.export("in");
  while (true) {
    var value = await port.read();
    console.log("unixtime:" + new Date().getTime() + "  gpio(5)= " + value);
    await sleep(500);
  }
}
```

### Node.js版のJavaScript
"gpio-readgpiovalue.js"というファイル名で下記のコードを保存してください。
タクトスイッチを押すとON、離すとOFFのように入力状況が出力します。合計で10回シュッツ力されると終了します。

```JavaScript
// タクトスイッチの入力状態を確認するチュートリアル
const { requestGPIOAccess } = require("node-web-gpio");

// sleep関数の実装
const sleep = require("util").promisify(setTimeout);

async function button() {
    const gpioAccess = await requestGPIOAccess();
    console.log("GPIO ready!");

    const switchPort = gpioAccess.ports.get(5);
    await switchPort.export("in");

    // タクトスイッチの入力回数をカウントする引数cnt
    var cnt = 0;

    // タクトスイッチの入力状況を把握する引数flag
    var flag = 0;
    
    while(cnt != 10) {
        const value = await switchPort.read();
        if (flag == 1 && value == 1){
            console.log("Button : OFF");
            flag = 0;
            cnt = cnt + 1;
        } else if (flag == 0 && value == 0) {
            console.log("Button : ON");
            flag = 1;
            cnt = cnt + 1;
        }
    }
    process.exit(1);
  }

button();
```

### ​実行してみよう
下記のようにコマンドラインから実行し、タクトスイッチを押すとON、離すとOFFのように入力状況が出力されると成功です。

```
% node gpio-readgpiovalue.js
GPIO ready!
Button : ON
Button : OFF
Button : ON
Button : OFF
Button : ON
Button : OFF
```

## GPIO-pirSensor

### 使用パーツ
- 人感センサー (KP-IR412) x 1 (※ジェネリック部品(HC-SR501)でも可)
- ジャンパー線（オス・メス）x 6
- ブレッドボード x 1

### 配線
以下の図のように配線してください。
![schematic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1797679/54c3f8f2-0366-b748-ec8e-410142ce8e11.png)

### Webブラウザ版のJavaScript
```JavaScript
main();

async function main() {
  var gpioAccess = await navigator.requestGPIOAccess();
  var sensor = document.getElementById("sensor");
  var dPort = gpioAccess.ports.get(12);
  await dPort.export("in");
  dPort.onchange = function(v) {
    if (v === 1) {
      sensor.innerHTML = "ON";
    } else {
      sensor.innerHTML = "OFF";
    }
  };
}
```

### Node.js版ブラウザ版のJavaScript
"gpio-kp-ir412.js"というファイル名で下記のコードを保存してください。
人感センサーによる感知のON/OFFを３回行います。

```JavaScript
// KP-IR412で人体赤外線感知を行うチュートリアル
const { requestGPIOAccess } = require("node-web-gpio");

async function ir412() {
  const gpioAccess = await requestGPIOAccess();

  // KP-IR412の接続されているポートの指定
  const port = gpioAccess.ports.get(12);
  await port.export("in");

  // センサーの検知回数をカウントする引数cnt
  var cnt = 0;

  // センサーで感知した結果を出力する
  // ただしセンサーの仕様上、ONからOFFにリセットされるまでに4〜6秒かかる
  port.onchange = function(v) {
    if (cnt > 3 && v.value == 0){
      console.log("Sensor : OFF");
	    process.exit(1);
	  }
    if (v.value == 1) {
      console.log("Sensor : ON");
      cnt = cnt + 1;
    } else {
      console.log("Sensor : OFF");
      cnt = cnt + 1;
    }
  };
}

ir412();
```

### ​実行してみよう
下記のようにコマンドラインから実行し、人感センサーによる感知のON/OFFが３回行われると終了します。

```
% node gpio-kp-ir412.js
Sensor : ON
Sensor : OFF
Sensor : ON
Sensor : OFF
Sensor : ON
Sensor : OFF
```

## さいごに
今回は以上になります。今回はnode-web-gpioでのGPIOの使用方法についての記事でした。次回はnode-web-i2cで使用可能なI2Cパーツの使用方法についての記事になる予定です。