nodejsを使ってwebページからデバイスを制御する

# 何ができるようになるか
webページを使ったインタラクティブなシステムの設計ができるようになります。
例えば、webページのボタンを世界の誰かがクリックするとLEDが点灯したり。
この記事は、実装重視で行くので細かいところは、調べてください。


# システム構成
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281453/ebadf6a0-c3ae-bb4e-6d39-06a2a7b86a86.png)


nodejsでwebサーバーを立てて、webページをホスティングします。webページの閲覧者はサーバーに対してクライアントと呼ばれます。
nodejsのsocket.ioというライブラリを使うことによってチャットのような機能を実現することができます。webページのボタンをクリックすることで何かデバイスを制御するということは、チャットでもし〜という文字が打たれたら〜を実行するということと同じです。

# 手順
実際に全世界からサーバーに接続してもらうためには、サーバーを借りなければいけません。しかし、今の時代これくらいの機能であれば完全無料でできます。
この記事では自分のパソコン（ローカル）で一通り、流れを押さえた上で、glitch.comを使用して、webページを公開し、全世界からアクセスを受け付けたいと思います。
とは言っても、ローカルでチャットアプリを実現する方法は探せばたくさん出てくるので、この記事では、その後の全世界に公開するところからに注力します。


具体的な手順を示します。
1. ローカルサーバーを立てる
1.1 nodejsのインストール
1.2 サーバーコードを書く
1.3 クライアントコードを書く
2. glitchに移植する
3. nodejsアプリケーションを作成する 
4. デバイスを制御する

glitchへの移植まで飛ばしたい人は[こちら](https://glitch.com/edit/#!/amethyst-flaxen-farm?path=app.js%3A1%3A0)

## 環境
- Mac

## node.jsのインストール
nodejsをMacにインストールする方法は色々とありますが、nodejsのバージョン管理ができるnvmを使用してインストールすることをお勧めします。
この辺りは、記事がたくさん出ているので参考にしながら進めてください。
[公式ドキュメント](https://github.com/nvm-sh/nvm#install-script)
[nvm + Node.js + npmのインストール](https://qiita.com/sansaisoba/items/242a8ba95bf70ba179d3)
[nvm(Node Version Manager)を使ってNode.jsをインストールする手順](https://qiita.com/ffggss/items/94f1c4c5d311db2ec71a)


## サーバーを立ててwebページでチャットを実現する
こちらも `nodejs socket.io チャット` とかで調べるとたくさん参考が出てくるので、調べてください。
こちらの記事をお勧めします。
[Node.js + Express + Socket.ioで簡易チャットを作ってみる](https://qiita.com/riku-shiru/items/ffba3448f3aff152b6c1)

こちらの記事ではnodejsのsocket.ioとexpressというライブラリを用いて、チャットアプリを制作しています。

## glitchに移植する
[glitch.com](https://glitch.com)を開いて、sign up しましょう。
色々バグることがあるのでGoogle Chromeがお勧めです。
glitchは、オンライン上でコードの編集から公開までできるとても便利なサービスです。

glitchでは人が作ったコードremixという形で、流用することができます。
[こちら](https://glitch.com/edit/#!/amethyst-flaxen-farm?path=app.js%3A1%3A0)からremixできるので自分でやるのがめんどくさい人は、リンクに飛んで、右上の`remix to edit` を選択してください


サインアップしたら、右上の`New Project`を押して`glitch-hello-node`を選択します。
開くと、サンプルファイルがあると思いますが、`public/`, `src/`, `server.js`は不要なのでそれらのファイル名の右側にあるメニューから`delete`を選択して消してしまいましょう。

続いて、前の項で作った`app.js`, `index.html`をアップロードします。
`New File`から`Upload File`を選択します。

そして、足りないモジュールを追加していきます。
glitch画面左下の`tools`から`Terminal`を選択します。
（Safariだとターミナルに書き込めないことがあります）

```
$ npm install express --save
$ npm install socket.io --save
```

最後に`package.json`の5〜7行目`main`となるコードを`app.js`に書き換えます。

```
"main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
```

これで、サーバーが正常に機能するはずです。

つまり、全世界からこのwebサイトにアクセスすることができます。

左上の`Show`から`In a new window`を選択して、webページを開きましょう。
このリンクは全世界に公開されてるのでスマホなどからアクセスすることもできます。

## デバイスでメッセージを受け取る
さて、本題です。どうしたらデバイスでこのメッセージを受け取れるでしょう。
実はnodejsではsocket.ioを用いた通信をwebページ以外からも受け取ることができます。

nodejsが実行できるデバイス（macやraspberry pi）で受信用のプログラムを作成します。
まず、作業用のフォルダを作成し、必要なモジュールを`npm`でインストールします。

```bash
$ mkdir receiver
$ cd receiver
$ npm install socket.io-client --save
$ touch client.js
```

作成した`client.js`の中身を書いていきます。

```client.js
const io = require('socket.io-client');

var socket = io.connect('glitchなどのURL');//接続先のサーバを指定

socket.on('message' ,function (data) {
    console.log(data);
});
```

接続先のサーバには、先ほどglitchで公開したwebページのurlを指定します。
これを実行します。

```bash
$ node client.js
```

そして、先ほど作ったglitch上のwebサイトから何か送ってみましょう。
表示されたでしょうか。


## アプリケーションとの連携
さて、ここからこの値を使ってデバイスを実際に制御します。
ここでは例としてこのデータをOSCを用いて他のアプリケーションに流す方法、raspberry piなどでGPIOを用いてLチカする方法を紹介します。

### OSCを用いて他のアプリケーションに流す
OSCを流すためのモジュールをインストールします。
OSC知らない人はとても便利なので一度ググってね。

[github用意してます](https://github.com/kiyu-git/nodejs-client)

```bash
$ npm install node-osc --save
```

OSCを送るためにclient.jsを改変します。

```client.js
const { Client, Server } = require('node-osc');
const io = require('socket.io-client');


const client = new Client('127.0.0.1', 3333);

var socket = io.connect('glitchなどのURL');//接続先のサーバを指定

socket.on('message' ,function (data) {
  console.log(data)
  client.send('/message', String(data)); //型に注意
  });

```
この例では、自分のパソコンの3333ポートにwebページで入力された内容を送っています。
一点注意するべきは、送る`data`の型に注意することです。JavaScriptは基本的に型を宣言することがないので、気にならないですが、例えば、Touch DesingerのOSC In Chopにデータを送りたいときは、`String()`を受け取ることができないので`Int()`か`Float()`にしてあげる必要があります。

さて、どうでしょう。他のアプリケーションで受け取れたでしょうか。

### GPIOを制御してLチカ
こちらはraspberry piなどのGPIOを制御する例です。webページで`0`が送られてきたらLEDをオフ、`1`がきたらLEDをオンするようにしています。

```bash
$ npm install onoff --save
```

GPIOを制御するためにclient.jsを改変します。

```client.js
const io = require('socket.io-client');
const Gpio = require('onoff').Gpio
var led = new Gpio(8, 'out')
var socket = io.connect('glitchなどのURL');//接続先のサーバを指定
socket.on('message' ,function (data) {
    console.log(data)
    if(data == '0'){
        led.writeSync(0)
    }else if(data == '1'){
        led.writeSync(1)
    }
});

```


# まとめ
Webサイトから何かを制御するって楽しいですよね！
ぜひ自分が作ったウェブサイトのリンクをTwitterなどで公開していろんな人にLチカしてもらいましょう！！