Electronで作ったデスクトップアプリとArduinoでシリアル通信して遊ぼう

## 作ったもの
普通は電子ピアノなどのサステインペダルとして使われる、YAMAHAのフットスイッチをArduino Unoと繋げ、
MacのElectron製のアプリとシリアル通信し、足でiTunesを操作できるようなものを作りました。

デスクの下に置いて、新MacBookProのなくなったファンクションキーの代わりとしても使えます。持ってないけど・・・


## 材料
| 名前 | 部品 | 値段 |
|:--|:--|:--|
| フットスイッチ | [![image](https://qiita-image-store.s3.amazonaws.com/0/7132/bd3e03e7-8bf7-11c2-c031-d49d62a39167.png)<br>YAMAHA FC4](http://amzn.to/2gqeJk0) | ¥2,786 |
| モノラルフォンジャック | [![image](https://qiita-image-store.s3.amazonaws.com/0/7132/7cd9adce-5691-d652-f350-ffde144d8715.png)<br>ＭＪ－１６０Ｍ](http://akizukidenshi.com/catalog/g/gC-10620/) | ¥70 |

フットスイッチはメーカーによって極性が違ったり、切り替えるためのスイッチが付いているので注意。

基本的に、楽器系で使われるコードは6.3mmの標準というサイズです。
一般的に使われるイヤフォンなどは、ミニ（ミニプラグ）3.5mmのひとまわり小さいですが、
[変換コネクター](http://amzn.to/2hkXfda)とかも普通に売っています。

## Arduino
この楽器用のフットスイッチは電子工作にも普通に扱えます。楽器用なので結構丈夫。
プラグの先端の黒い帯（絶縁体）を境目に、普通のタクトスイッチみたいな動作をさせることができます。
ジャックを使わないでこんな感じでも一応できる。

![IMG_1103.JPG](https://qiita-image-store.s3.amazonaws.com/0/7132/1f90fad0-d334-a06b-3d97-3be4e23d6539.jpeg)

回路も[Digital Button](https://www.arduino.cc/en/Tutorial/Button)とほぼ同様な感じです。

![footpedal_ブレッドボード.png](https://qiita-image-store.s3.amazonaws.com/0/7132/d9a4a7b5-ceb2-78db-ef49-943e38a60742.png)

フットスイッチのONとOFFを`digitalRead `で取得しSerialで送信する。

```c
const int buttonPin = 8;

void setup() {
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
}

void loop() {
  if (digitalRead(buttonPin) == HIGH) {
    Serial.println("on");
    Serial.print("\n");
    delay(500);
  } else {
    Serial.print("off");
    Serial.print("\n");
  }
  delay(50);
}
```

Serial.printlnを使わず直接改行コードで'\n'と書いているのは、Electron側でparserの区切り文字として使うためです。

実際に動かしてみると、無事に取得できました。
LEDまわりはおまけで、押している最中に点滅するようになってます。
![タイトルなし.gif](https://qiita-image-store.s3.amazonaws.com/0/7132/195c8d40-764a-f4ab-3f8d-b4997580e90f.gif)
<img width="673" alt="スクリーンショット 2016-12-13 0.18.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/7132/08eee5ba-48d5-efe7-a711-513d82d734ee.png">

## Electron
### シリアル通信をする方法
[electron-quick-start](https://github.com/electron/electron-quick-start)が準備できている状態にします。

```bash
$ git clone git@github.com:electron/electron-quick-start.git
```

Node.jsでシリアル通信するためにnpmで[serialport](https://github.com/EmergingTechnologyAdvisors/node-serialport)をインストール

```bash
$ npm install --save serialport
```

この状態でserialportを読み込んで`npm start`した起動しようとすると

```
Uncaught Exception:
Error: Module version mismatch. Expected 50, got 48.
    at Error (native)
    at process.module.(anonymous function) [as dlopen] (ELECTRON_ASAR.js:173:20)
...
```

とエラーになり怒られます。
このエラーは[electron-rebuild](https://github.com/electron/electron-rebuild)を使い解消できます。

```bash
$ npm install --save-dev electron-rebuild
$ ./node_modules/.bin/electron-rebuild
```


フロント側から読み込まれる`renderer.js`に書き加えていきます。

```js:renderer.js
const serialPort = require('serialport');
serialPort.list(function(err, ports) {
  ports.forEach(function(port){
    console.log(port);
  });
});
```

これでElectronを起動

```
$ npm start
```

起動すると
![スクリーンショット 2016-12-12 23.27.41.png](https://qiita-image-store.s3.amazonaws.com/0/7132/cb27a583-aa14-4ef3-1202-3699bd803477.png)

おそらくArduino IDEのシリアルポートに表示されるものと同じものがログに出力されているとおもいますが、
２つ目が`comName: "/dev/cu.usbmodem1411", manufacturer: "Arduino (www.arduino.cc)"`となっているので接続しているArduinoだとわかります。

本来はUIで選択できるようにしたほうが良いですが、
面倒なのでmanufacturerがArduinoだったときにシリアル接続するようにします。
ちなみにウィンドウは`command+R`でWebViewをリロードできる。

```renderer.js
const serialPort = require('serialport');
serialPort.list((err, ports) => {
  ports.forEach((port) => {
    console.log(port);
    if (port.manufacturer === 'Arduino (www.arduino.cc)') {
      const sp = new serialPort(port.comName, {
        baudrate: 9600,
        parser: serialPort.parsers.readline("\n"),
      });
      
      sp.on('data', function(res) {
        console.log('data received: ' + res);
      });
    }
  });
});
```

`sp.on('data', callback)`でシリアル通信を受信し、`on`と`off`が取得できました。
Arduino IDE側でシリアルポート接続しているとうまく取得できないので注意。


### iTunesを操作する方法
Node.js経由でiTunesを操作できる[itunes-remote](https://github.com/mischah/itunes-remote)をインストールします。

```bash
$ npm install --save itunes-remote
```

こんな感じで使えます。

```js
const itunesRemote = require('itunes-remote');
// 再生
itunesRemote("play", () => {});
// 停止
itunesRemote("pause", () => {});
// 次の曲
itunesRemote("next", () => {});
```

## 両方合わせてみる

フットスイッチを踏んだらiTunesを`再生・停止`、長く踏んだら`次の曲`が再生されるようにしたいので、
onが連続するの数をcountする。

```renderer.js
const serialPort = require('serialport');
const itunesRemote = require('itunes-remote');

var playing = false;
var count = 0;
serialPort.list((err, ports) => {
  ports.forEach((port) => {
    console.log(port);
    if (port.manufacturer === 'Arduino (www.arduino.cc)') {
      const sp = new serialPort(port.comName, {
        baudrate: 9600,
        parser: serialPort.parsers.readline("\n"),
      });
      
      sp.on('data', function(res) {
        // console.log('data received: ' + res);
        if (count === 3) {
          itunesRemote("next", () => {});
          console.log('itunes: next');
        }

        if ('on' === res) {
          count++;
        } else {
          if (0 < count && count < 3) {
            if (playing) {
              playing = false;
              itunesRemote("pause", () => {});
              console.log('itunes: pause');
            } else {
              playing = true;
              itunesRemote("play", () => {});
              console.log('itunes: play');
            }
          }
          count = 0;
        }
      });
    }
  });
});
```

baudrateとparserにはArduino側と同じ値をセットします。
これでリロードすると・・・

![スクリーンショット 2016-12-13 1.33.19.png](https://qiita-image-store.s3.amazonaws.com/0/7132/d502ddf5-1a85-4240-bc98-84b8f6d6b20c.png)

動きました！
iTunesが操作できる。
良い感じ

## このアプリよく考えるとウィンドウいらなくね？

ウィンドウ必要ないのでmain.jsの`app.on('ready', createWindow)`部分を書き換えてしまい、
準備ができたらウィンドウを作らずに、シリアル通信できるようにしました。

```js:main.js
const serialPort = require('serialport');
const itunesRemote = require('itunes-remote');
app.on('ready', function() {
  var playing = false;
  var count = 0;
  serialPort.list((err, ports) => {
    ports.forEach((port) => {
      if (port.manufacturer === 'Arduino (www.arduino.cc)') {
        const sp = new serialPort(port.comName, {
          baudrate: 9600,
          parser: serialPort.parsers.readline("\n"),
        });
        
        sp.on('data', function(res) {
          if (count === 3) {
            itunesRemote("next", () => {});
            console.log('itunes: next');
          }

          if ('on' === res) {
            count++;
          } else {
            if (0 < count && count < 3) {
              if (playing) {
                playing = false;
                itunesRemote("pause", () => {});
                console.log('itunes: pause');
              } else {
                playing = true;
                itunesRemote("play", () => {});
                console.log('itunes: play');
              }
            }
            count = 0;
          }
        });
      }
    });
  });
})
```

ウィンドウなくてもちゃんと動きます。

<img width="1680" alt="スクリーンショット 2016-12-13 2.05.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/7132/15fb5a57-f235-797c-820a-af5d2e7c8f94.png">


## Electronのパッケージング
毎回ターミナル経由で起動するのは面倒なのでパッケージングして、Macアプリとして簡単に使えるようにします。

```bash
$ npm install --save-dev electron-packager
$ ./node_modules/.bin/electron-packager ./ itunes-foot-controller --platform=darwin
Packaging app for platform darwin x64 using electron v1.4.12
Wrote new app to /Users/xxx/Documents/works/itunes-foot-controller/itunes-foot-controller-darwin-x64
```

`itunes-foot-controller.app`という名前のファイルができあがり、ダブルクリックで起動できます。
後はアイコン付けたり、`tray`でメニューバーにアイコンを表示したり、フットスイッチの操作パターン増やしたり色々やりたい。

## おわり
ArduinoとElectronと組み合わせることで、PC向けアプリが構築できるようになりかなり応用の範囲が広がる、
IoT的な業務用のアプリケーションとかも開発できるんじゃないかと企んだりできる。