WebBluetoothAPI を利用すれば、ブラウザからBluetoothLE(BEL)デバイスを操作できるようになります。
従来であれば、BLEデバイスを操作するには iOS や Android のアプリケーションを用意する必要がありましたが、
このAPIを利用すれば、javascriptのみでブラウザからBLEデバイスを操作できるようになります。
基本的には下記の5ステップで実装をしていきます。
- BLEデバイスをスキャンして探す
- BLEデバイスに接続する
- BLEデバイスの Service オブジェクトを取得する
- Service オブジェクトから Characteristic オブジェクトを取得する
- Characteristic オブジェクトのRead/Write でデバイスを制御する
上記5ステップと、接続の解除、デバイスからの通知の受け取り、の7項目について説明していきます。
なお、動作環境として以下の制約があります。
- セキュリティのため SSL 通信が必須です
- 各ブラウザの実装状況 (Macではほとんどの機能が対応しています)
1. BLEデバイスをスキャンして探す
BLEデバイスのスキャンは navigator.bluetooth.requestDevice メソッドを使用します。
Promise を介して BluetoothDevice オブジェクトが取得できます。
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'], }]}) .catch(error => console.log(error));
引数として、BLEデバイスのフィルター条件を指定します。
上記の例では、heart_rate サービスを保持するデバイスが検出されます。services の代わりに name を指定すれば、指示したデバイス名を持つデバイスが検出できます。
なお、セキュリティ上の理由で、このメソッドを呼び出すためにはクリックアクションなどのユーザジェスチャーが必須となっています。
ちなみに、現時点では、検出可能な全てのデバイスを検出するには下記のように実装すれば可能です。
navigator.bluetooth.requestDevice({filters: anyDevice()}) function anyDevice() { return Array.from('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') .map(c => ({namePrefix: c})) .concat({name: ''}); }
2. BLEデバイスに接続する
BLEデバイスに接続するためには BluetoothDevice#gatt.connect() を使用します。
Promise を介して BluetoothRemoteGATTServer オブジェクトが取得できます。
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'], }]}) .then(device => device.gatt.connect()) .catch(error => console.log(error));
3. BLEデバイスの Service オブジェクトを取得する
BluetoothGATTService オブジェクトの取得は BluetoothGATTRemoteServer#getPrimaryService() を使用します。
Promise を介して取得できます。
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'], }]}) .then(device => device.gatt.connect()) .then(server => server.getPrimaryService('heart_rate')) .catch(error => console.log(error));
4. Service オブジェクトから Characteristic オブジェクトを取得する
BluetoothRemoteGATTCharacteristic オブジェクトの取得は BluetoothGATTService#getCharacteristic() を使用します。
こちらも Promise を介して取得できます。
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'], }]}) .then(device => device.gatt.connect()) .then(server => server.getPrimaryService('heart_rate')) .then(service => service.getCharacteristic('body_sensor_location')) .catch(error => console.log(error));
また、複数の Characteristic を取得する場合には Promise.all を利用します。
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'], }]}) .then(device => device.gatt.connect()) .then(server => server.getPrimaryService('heart_rate')) .then(service => { chosenHeartRateService = service; return Promise.all([ service.getCharacteristic('body_sensor_location') .then( /* do some processing */), service.getCharacteristic('heart_rate_measurement') .then( /* do some processing */), ]); }) .catch(error => console.log(error));;
5. Characteristic オブジェクトのRead/Write でデバイスを制御する
BluetoothRemoteGATTCharacteristic の値を書き込むには BluetoothGATTCharacteristic#writeValue() を使用します。
なお、writeValue に渡す値は ArrayBuffer オブジェクトである必要があります。
また、読み取る場合には BluetoothGATTCharacteristic#readValue() を使用します。
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'], }]}) .then(device => device.gatt.connect()) .then(server => server.getPrimaryService('heart_rate')) .then(service => service.getCharacteristic('heart_rate_control_point')) .then(characteristic => { let resetEnergyExpended = new Uint8Array([1]); return characteristic.writeValue(resetEnergyExpended); }) .catch(error => console.log(error));
6. BLEデバイスとの接続を解除する
参考までに接続を解除する方法もご紹介します。
解除に関しては2パターンあり
- BLEデバイスの電源が切れるなど、コネクションがロストしてしまう時
- ブラウザから意図的に接続を解除する時
です。
まずは1つめのパターン。
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'], }]}) .then(device => { device.addEventListener('gattserverdisconnected', onDisconnected); device.gatt.connect() }) .catch(error => console.log(error)); function onDisconnected() { console.log('> Bluetooth Device disconnected'); }
BLEデバイスと接続する時に gattserverdisconnected のイベントリスナを追加しておきます。
そうすると、デバイスとの通信が切れてしまった時に、コールバックに指定したイベントが発火します。
次に、意図的に接続を解除する場合は BluetoothDevice#gatt.disconnect() を使用します。
function onDisconnectButtonClick() { if (!bluetoothDevice) { return; } console.log('Disconnecting from Bluetooth Device...'); if (bluetoothDevice.gatt.connected) { bluetoothDevice.gatt.disconnect(); } else { console.log('> Bluetooth Device is already disconnected'); } }
のように処理をします。
gatt.connect() と異なり、gatt.disconnect() はユーザアクションでなくても構いません。
7. BLEデバイスからの通知を受け取る。
readValue を利用する時は、ブラウザから指示をする必要があるため能動的です。
受動的に、Characteristic の値が変化した時に、BLEデバイスからブラウザへの通知を受け取ることも可能です。
characteristicvaluechanged イベントを利用します。
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'], }]}) .then(device => device.gatt.connect()) .then(server => server.getPrimaryService('heart_rate')) .then(service => service.getCharacteristic('heart_rate_measurement')) .then(characteristic => { characteristic.addEventListener('characteristicvaluechanged', onHeartRateChanged); }) .catch(error => console.log(error)); function onHeartRateChanged(event) { let characteristic = event.target; console.log(characteristic.value); }
このように Characteristic を取得した後に、イベントリスナーを登録することで、値が変化する度にブラウザに通知され、コールバックで指定した処理を実行できます。
注意事項として、この characteristicvaluechanged イベントは値が変化した時以外にも、 readValue を実行した後にも発生してしまいます。
characteristicvaluechanged
Fired on a BluetoothRemoteGATTCharacteristic when its value changes, either as a result of a read request, or a value change notification/indication.
https://webbluetoothcg.github.io/web-bluetooth/#event-types
開発中になぜか notification が大量発生したことがあり、調べてみると仕様であることがわかりました。お気をつけ下さい。
参考
WebBluetoothAPI 公式ドキュメント
https://webbluetoothcg.github.io/web-bluetooth/ (英語)
https://tkybpp.github.io/web-bluetooth-jp/ (日本語)
日本語に翻訳してみましたのでよければご参照ください。
いくつかのBLEデバイスを利用してサンプルデモも公開しています。
GitHub - tkybpp/simple-webbluetooth: Enjoy Web Bluetooth!
サンプルで利用しているBLEデバイスは以下の3つです。
【日本正規代理店品】Sphero スター・ウォーズ エピソード7(スター・ウォーズ/フォースの覚醒) BB-8 (ドライブ / ホログラム機能) R001ROW
- 出版社/メーカー: Sphero
- 発売日: 2015/09/05
- メディア: Wireless Phone Accessory
- この商品を含むブログ (4件) を見る
PLAYBULB candle 【ルームキャンドル アロマキャンドル Bluetoothコントロール LED 】 BTL300 (1)
- 出版社/メーカー: Mipow
- メディア: Tools & Hardware
- この商品を含むブログを見る
【日本正規代理店品】 Witti Design DOTTI PIXEL LIGHT アプリでコントロールできる “ピクセル アート ライト” 6821-WH00A00
- 出版社/メーカー: Witti Design
- メディア: 付属品
- この商品を含むブログを見る
BB-8を利用してみましたが、とても可愛いです。おすすめです。
他にも Google や WebBluetoothコミュニティグループがサンプルを公開しています。
Google Codelabs - PLAYBULB Tutorial
Control a PLAYBULB candle with Web Bluetooth
Web Bluetooth Samples
https://googlechrome.github.io/samples/web-bluetooth/index.html
Web Bluetooth Demos
GitHub - WebBluetoothCG/demos: Demo applications showing off Web Bluetooth
手元にBLEデバイスが無いけど使いたい
大丈夫です。
手元のスマートフォンをBLEのシミュレータとして扱えるアプリが用意されています。
このAPIを利用すれば、javascript のみでBLEデバイスを操作できますが、より複雑なライブラリやアプリケーションを実装するには、Bluetooth自体の知識も必要になってきます。BLEに関してはこの2冊がとても詳しく説明してくれているのでおすすめです。
Bluetooth Low Energy: The Developer's Handbook
- 作者: Robin Heydon
- 出版社/メーカー: Prentice Hall
- 発売日: 2012/10/10
- メディア: ペーパーバック
- この商品を含むブログを見る
- 作者: 堤修一,松村礼央
- 出版社/メーカー: ソシム
- 発売日: 2015/03/23
- メディア: 単行本
- この商品を含むブログを見る
(関連記事)