2019年2月版 JavaScript/Node.jsでBluetoothを触れるライブラリやAPIをまとめてみた #html5j #iotlt #linethings


## この資料について

* 2019/2/19: [増席】JSで制御するBluetoothと基板の勉強会（html5jロボット部 第11回 勉強会）](https://html5j-robot.connpass.com/event/117812/)でのLT内容です。
	* 発表後にタイトルをそれっぽいのに変更しました。
* 2019/2/22: [大阪版IoT縛りの勉強会 IoTLT Osaka Vol.10](https://iotlt.connpass.com/event/118404/)でもアップデートして話しようかと思っています。
* 書いてたら量が膨らんできてて5分では厳しい気がするので色々端折って発表します。

---

## 自己紹介

<img src="https://qiita-image-store.s3.amazonaws.com/0/35387/profile-images/1473686705">

* 名前: [n0bisuke](https://twitter.com/n0bisuke)
* 所属: [dotstudio](http://dotstud.io)
* コミュニティなど: [IoTLT](http://iotlt.connpass.com) / [Microsoft MVP](https://mvp.microsoft.com/ja-jp/) / [LINE API Experts](https://engineering.linecorp.com/ja/blog/announcing-the-line-api-experts-2018-q1/)
* 少し前に作ったもの
	* [IoTでポケモンマスターに俺はなる！ #iotlt](https://qiita.com/n0bisuke/items/027ac51527a499b5d19f)
		* <img src="https://camo.qiitausercontent.com/479cc9dc64ab9f2a5e4ceb31442068a45cb80677/68747470733a2f2f692e6779617a6f2e636f6d2f38306438376164376466633965313332363966656632653933653637353639642e676966" width="200px">
	* [CROSS MEで黒髪のメガネ女子とマッチングするデバイスをAIとIoTを駆使して作った話 #iotlt](https://qiita.com/n0bisuke/items/1dcc9f9eed8d33c68981)
		* <img src="https://camo.qiitausercontent.com/08453cedcdc1032ee7fd905e6e10a0ce348714b6/68747470733a2f2f692e6779617a6f2e636f6d2f66303265656437383964663030353738313065386136393266653961336234322e676966" width="200px">
* 最近やった(2/21)ハンズオン
	* [イベントページ](https://skyway.connpass.com/event/118081/)
	* <img src="https://camo.qiitausercontent.com/ebfb25472b859ccf61211f211374a3320931bdef/68747470733a2f2f692e6779617a6f2e636f6d2f64333439336366333833373235623332633334326138366564343430623365322e676966" width="400px">
* 最近作ってるもの
	* 動画でマスターするIoTレシピ学習サイト[Graspin](https://graspin.studio/)
		* <img src="https://i.gyazo.com/2aea48c21bdbdc0a927adf48f9ba7b23.jpg" width="200px">
		* 某サービスのIoT版っぽいやつ
		* 使ってみてコメントとかくれる人ゆるぼ

---

## 今日の内容

* JavaScriptでやれるBluetooth周りの話

---

## モチベなど

* こんな事案
	* Webやってる人に「IoTやろうよ〜」みたいな事を言う
	* だいたいの人が「興味はあるけど、モノがない」と返答する
* よくある学習サービスがやりやすい理由
	* -> PCだけあればやれる
* IoTとかモノづくりってそもそも始めにくい
	* -> **デバイス用意が必要**
		* **ここに圧倒的な入門障壁がある**と思ってます

---

### Q.IoTやモノづくり領域ってデバイスないと"全く"やれない?

A. そんなことはないはず

---

### PCとスマホがあれば`やりはじめが出来る`内容を検討したい

* Web Bluetooth
* WebRTC
* WebMIDI
* WebAudio
* その他, ちょっとデバイス必要かも
	* WebVR/XR (HMD機器など)
	* WebUSB (USB機器など)
	* GamePad API（ゲームコントローラー機器など、Nintendo Switchがあれば出来ます。）
		* [Nintendo SwitchのコントローラでGamepad APIを試す](https://routecompass.net/switch-game-api/)

---

## JSで扱えるBluetooth周りのAPIたち

### ブラウザ - WebBluetooth

* ブラウザのJavaScriptでBLE制御できるブラウザAPI
* 現状: Google Chrome (とOpera)のみ
* <img src="https://i.gyazo.com/23510d723cdd7be891843e948588a662.png" width="300px">
* [話題のWebBluetoothでGenuino101をブラウザからリモートコントロールしてみよう](https://dotstud.io/blog/web-bluetooth-remote-blink/)
* その他
	* [LINE Things](https://engineering.linecorp.com/ja/blog/line-things-developer-trial/)
		* LINEのLIFF内で使えるWebBluetoothっぽいやつ
		* **厳密にはWebBluetoothではない**
		* LINE Things対応させたデバイスが必要なのでその他に載せてます。
			* たぶんPCをデバイス化できなくもないけど僕の手元では試せなさそう(後述のbleno問題)
		* [LINE Thingsで作った勤怠管理システムを解説してみる #linethings](https://qiita.com/n0bisuke/items/98ba8b0cb8b843c7cc38)

---

### Node.js (今回のメインこの辺)

* 1. noble
* 2. bleno
* 3. node-bluetooth
* 4. LINE Simple Becon
* 5. CYLON

---

#### [noble](https://github.com/noble/noble)

![](https://github.com/noble/noble/raw/master/assets/noble-logo.png)

* Node.jsでBLE Centralを実装するライブラリ
* 内部でbobleを利用しているパッケージもチラホラ
	* [noble-device](https://www.npmjs.com/package/noble-device)
		* nobleのラッパーライブラリ
	* [flower-power](https://www.npmjs.com/package/flower-power)
		* Parrotの植物監視デバイスのFlower PowerをNode.js制御するライブラリ
		* noble-deviceのラッパーライブラリ
	* [Rolling Spider](https://www.npmjs.com/package/rolling-spider)
		* ParrotのミニドローンをNode.jsから制御するライブラリ
* 諸注意
	* 最新のNode.js(v11系)だとビルドできないことがあり、v8系にしたらいけました(原因よくわかってない) 
* 関連記事
	* [Node.jsでBLE Peripheralの実装をするパッケージblenoを使ってみる](https://qiita.com/n0bisuke/items/e6298f13be6822965045)
	* [Node.jsから周辺のBLEデバイスを探すサンプル](https://qiita.com/n0bisuke/items/00503d2b18fc4f413c4e)
	* [JavaScriptから部屋の植物を監視。 Parrot Flower PowerをNode.jsから制御する](https://qiita.com/n0bisuke/items/f50996a60f5472b9c80f)
	* [ノンプログラマでもコピペでOK！JavaScriptを使ってDroneを飛ばそう](https://liginc.co.jp/187633)

---

#### [bleno](https://github.com/noble/bleno)
* Node.jsでBLE Peripheralを実装するライブラリ、PCなどをBLEデバイス化できる
* Nobleの姉妹プロジェクト
* 内部でbobleを利用しているパッケージもチラホラ
	* [bleacon](https://www.npmjs.com/package/bleacon)
		* iBeacon化するラッパーライブラリ
		* [たった6行!最も簡単にiBeaconの電波を「発信」する方法](https://qiita.com/kpkpkp/items/a0dd3cfcd1eef8dbd492)
	* [line-simplebeacon-nodejs-sample](https://github.com/line/line-simple-beacon/tree/master/tools/line-simplebeacon-nodejs-sample)
		* LINE Simple Beacon(後述)のNode.jsサンプル実装

* 関連記事
	* [Node.jsでBLE Peripheralの実装をするパッケージblenoを使ってみる](https://qiita.com/n0bisuke/items/e6298f13be6822965045)

---

#### 最近のMacでBlenoが使えない(2019/2/19)

* macOS MojaveでBlenoが使えなくなってます。
	* <blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ここでもちょっとやり取りがあるのですが、解消していないという認識です<a href="https://t.co/mT7mEAsk3B">https://t.co/mT7mEAsk3B</a><br><br>* Mojaveを使い、LINE Simple Beaconを実装することは現状できない（依存ライブラリであるところのblenoがmojaveで動かないから）<br>* RasPiを使いLINE Simple Beaconを実装することは引き続き可能。</p>&mdash; Yohsuke (@4_suke) <a href="https://twitter.com/4_suke/status/1093076967975342080?ref_src=twsrc%5Etfw">2019年2月6日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
	* [Advertising not starting in macos Mojave #416](https://github.com/noble/bleno/issues/416)
	* [Currently not working in MacOS Mojave #9](https://github.com/line/line-simple-beacon/issues/9)
* 使えた人いたら教えてください。

---

#### nobleやbleno使うときはBluebirdでプロミス化が良さそう

* サンプルコード通りにやるとコールバック地獄になります
	* GATTのプロフェイル性質上、入れ子構造になるので仕方ない気もする
	* **割と「典型的な地獄」**

* 例: https://github.com/noble/noble/blob/master/examples/pizza/central.js

```js
noble.on('discover', function(peripheral) {
	peripheral.connect(function(err) {
		peripheral.discoverServices([pizzaServiceUuid], function(err, services) {
			services.forEach(function(service) {
				service.discoverCharacteristics([], function(err, characteristics) {
					characteristics.forEach(function(characteristic) {
						CrustCharacteristic.write(crust, false, function(err) {
							//ここでやっと書き込みができる
						}
					}
				}
			}
		}
	}
}
```
	
* async/awaitしたい場合は`bluebirdのpromisifyAll()`を使うと良さげでした。
	* [Nobleのコードをasync/awaitで記述するメモ](https://qiita.com/n0bisuke/items/8e26e502d1245568192c)
	* [Nobleをbluebirdでスッキリさせる](https://graspin.studio/recipes/nodejs-ble-tutorial/10)
	* 通常であれば`util.promisify()`で対応できる

```js
const discovered = async (peripheral) => {
    const p = Promise.promisifyAll(peripheral); //Promisify
    await p.connectAsync();
    const services = await p.discoverSomeServicesAndCharacteristicsAsync(serviceUUIDs,characteristicUUIDs);
    const characteristic = services.reduce((pre, current) => (current.uuid === serviceUUIDs[0]))
                            .characteristics
                            .reduce((pre, current) => (current.uuid === characteristicUUIDs[0]));
    const c = Promise.promisifyAll(characteristic); //Promisify
    
    //書き込み
    await c.writeAsync(new Buffer.from([state]), true);
}
```

---

#### [node-bluetooth](https://www.npmjs.com/package/node-bluetooth)

* BLEではなくBluetoothシリアルを読み込んだりするライブラリ
* いわゆるペアリングなどが発生するデバイス(Bluetooth v3まで?)はこちらで一覧が見れる

```js
const bluetooth = require('node-bluetooth');
const device = new bluetooth.DeviceINQ();
device.listPairedDevices(console.log);
```

```bash
$ node app.js
[ { name: 'u-sen-lan',
    address: 'xx-xx-xx-xx-xx-xx',
    services:
     [ [Object],
       [Object] ] },
  { name: 'Joy-Con (L)',
    address: 'xx-xx-xx-xx-xx-xx',
    services: [ [Object], [Object], [Object] ] },
  { name: 'Nexus 5',
    address: 'xx-xx-xx-xx-xx-xx',
    services:
     [ [Object],
       [Object] ] },
  { name: 'AB Shutter 3',
    address: 'xx-xx-xx-xx-xx-xx',
    services: [ [Object], [Object], [Object] ] } ]
```

↑僕のMacで連携中のBluetoothデバイスの一覧が出ます。

一番最後の「AB Shutter 3」は買ったばかりのBluetooth シャッター

> https://www.instagram.com/p/BuD9tqYDCwU/

<img src="https://i.gyazo.com/d3123718b5b0e185b769a3d5702bf6d8.jpg" width="300px">

---

#### LINE Simple Becon

* LINE BOTと繋がるLINE Beacon（デバイス）の仕様をオープン化したもの
* PCやスマホをLINE Beacon化出来る
* 関連記事
	* [AndroidをLINE Simple Beaconにする](https://qiita.com/moritalous/items/11280cebaeb7792d7868)

---

#### [CYLON](https://cylonjs.com/)

* Node.jsで色々なデバイスを制御できるフレームワーク
* Bluetooth以外にもシリアル制御やGPIO制御なども含まれている
* スマートトイなどのBLE対応ガジェット系が多い
* 姉妹プロジェクト
	* Golang: [GOBOT](https://gobot.io/)
	* Ruby: [artoo](http://artoo.io/)
* 関連記事
	* [『スター・ウォーズ』ファン必見！映画に登場したドロイド「BB-8」をブラウザから動かしてみた！](https://liginc.co.jp/238181)

---

## デバイス用意しないでどうやってやりはじめる？

* スマホアプリでデバイスのエミュレートが出来ます。
	* [LightBlue® Explorer](https://itunes.apple.com/jp/app/lightblue-explorer/id557428110?mt=8)
	* <img src="https://i.gyazo.com/6bf111ad04ca2d1ee0ec8df3b0f6f5cf.png" width="200px">
	* 探すとエミュレートアプリは他にもあると思います。
* スマホ <-> PCで連携してプログラムを試したり出来ます。
	* この辺でやり方解説してます
	* [WebBluetoothを使ってみよう](https://graspin.studio/recipes/webbluetooth-first-tutorial)

---

## その他、面白いAPI見つけ方

* `chrome://flags/`をチェック
	* <img src="https://i.gyazo.com/c166f8ec651e35036e07901946e59606.png" width="300px">

* navigator.~をチェック
	* <img src="https://i.gyazo.com/6d7d50aee912225da9203c5780423d02.png" width="300px">
* 「Web x 既存の通信技術名」で検索してみると意外とヒットするものもある（かも）
	* WebNFCなど
* npmを探ってみる
	* npm内で「bluetooth」「usb」などで検索してみると面白い


皆さんも見つけたらシェアしましょう〜
そして毎月開催している「[IoTLT](https://iotlt.connpass.com)」で話しにきてね☆ (番宣)

---

## まとめ

* JavaScript/Node.jsとか使うとBluetoothけっこうやれるのでみんな楽しんでいきましょ。
* Webエンジニアがこっち側きてくれるようになるといいな