JavaScript だけで BLE に入門する

この記事はCPS Lab Advent Calenderの2日目の記事です。1日目の記事はM5Stackをメトロノームにするです。3日目の記事は

@kotako_rs です。
書くネタが全くなかったので、研究で気になっていたBLEについて調べて実装してみました!

やってみたこと

ChromeからBLEデバイスに接続し、そのデバイスの電池残量をWebページに表示してみます。
今回はRaspberry Pi 3とMacを接続しています。

f:id:takorras:20181202200833g:plain

ハードウェアの知識はほとんどないですが、JavaScriptのみ書いて実現することができます!すごい

BLEについて

通常のBluetoothより省コストで通信を行うことができる技術です。 既存のBluetooth同様2.4GHzの電波を用いていますが、通信速度・通信範囲・データサイズ等がとても小さいものです。(実際には10kbps、10m、33bytesくらい?らしい?)

下の記事が個人的に分かりやすくて参考になりました。他にも良い記事があったら教えて下さい。

jellyware.jp

  • Bluetooth がコンパクトになった
  • GAP、 GATTという共通仕様を用いる
  • サーバー・クライアントみたいにセントラル・ペリフェラルという存在がある
  • Characteristic がBLEのデータを持つ単位で、Service がそれらをまとめる
  • Advertise, Scan, Connect, Disconnect という通信の流れ
  • 単方向通信もあるみたい

というくらいの、フワッとした理解です...。正直まだ全然理解できていません。

bleno

BLEペリフェラルを実装するための、nodejsライブラリです。
電池残量を取得するサンプルをRaspberry Pi で動かして、後ほどブラウザから見つけてもらいます。

github.com

電池残量のようにどういった形式のデータを扱うか、というのがGATTプロファイルで、battery-serviceが公式が提供しているGATTプロファイルの1つです。独自に定義することもできます。

以下のサンプルコードをRaspberry Pi 3 に保存して、
bleno/examples/battery-service at master · noble/bleno · GitHub

自分の環境がはそのままだと動かなかったので、依存関係に手を入れます。
Bluetooth-hci-socket という依存ライブラリが古いので、他の方が修正してくれたものに向き先を変えてあげます。参考issue

// package.json
... 
  },
  "resolution": {
    "bleno/bluetooth-hci-socket": "https://github.com/jrobeson/node-bluetooth-hci-socket/#fix-builds-for-node-10"
  }
}

BLEの仕様がなんとなく分かると、コードもなんとなく読めると思います。

Web Bluetooth API

ブラウザでBluetoothを利用するためのAPIです。
現在策定中ですが、試験機能としてChrome で利用できます。chromium ベースだからか Opera でも利用できるんですね。

Can I use... Support tables for HTML5, CSS3, etc f:id:takorras:20181202215942p:plain

利用したい場合は、試験機能を有効にするために chrome://flags/#enable-experimental-web-platform-features を有効にする必要があります。

f:id:takorras:20181202221759p:plain:w500

Web Bluetoothには

The first version of this specification allows web pages, running on a UA in the Central role, to connect to GATT Servers over either a BR/EDR or LE connection.

と書いてあり、GATTプロファイルを用いてBluetoothバイスと通信するためのものという事が分かります。
セントラルとして動作します(Web Bluetooth APIを用いてデバイスを見つけて接続する)

またセキュリティから、localhosthttps のページでしか使用することはできません。試験機能がoffかhttpかBluetooth機能がない場合は navigator.bluetooth でnullが返されるので、そこでチェックしておきます。

同様にデバイスへの接続も勝手にする事はできず、ユーザーが選択する必要があります。
PCは上記gifのように、Android Chromeでは以下のようなモーダルが出てきました。

f:id:takorras:20181202221707p:plain:w300

以下チュートリアルを確認しながら、先程作成したRaspberry Piを探して接続するコードを書いていきます。
developers.google.com

バイスを検索するモーダルを出して接続し、電池残量を取得するまでが以下になります。
パッと見やる気が失せますが、これだけです!

  connect() {
    // Web Bluetooth APIが使用できるか
    if (!navigator.bluetooth) return;
   
    // battery_serviceを持つデバイスを検索して、データを取得するまで
    navigator.bluetooth
      .requestDevice({ filters: [{ services: ["battery_service"] }] }) 
      .then(device => device.gatt.connect())
      .then(server => server.getPrimaryService("battery_service"))
      .then(service => service.getCharacteristic("battery_level"))
      .then(characteristic => characteristic.readValue())
      .catch(e => console.log(e));
  }

以下、create-react-app したものを修正してこのコードを入れたものです。
Raspberry Piのサンプルを準備して実行すると出てきました!👀

f:id:takorras:20181202200833g:plain:w500

github.com

まとめ

間違っているところなどあればご指摘お願いします!

だらだらと書いてしまいましたが、JavaScript だけ書いてBluetoothバイスとそれを利用するアプリを作る事ができました!
身の回りのBLEデバイスや研究室にあるマイコンを使って、なんだか面白いモノが作れるんじゃないかなとワクワクしますね👨‍💻(思いついてないですが)

ハード開発に縁の薄い自分でも、 JavaScript のみで開発ができると手が出しやすく嬉しいです。

では、研究は全く進んでいませんが、奄美大島に行ってきます。