ブラウザからBluetooth(BLE)が使えるで話題のWeb Bluetooth APIが少し前に正式リリースされました。
まだ発展途上感がありますが、今後に期待ができますね。
せっかく手元にBLE Nanoがあるので、今回はBLE NanoとブラウザをBluetoothで通信してみます。
Web Bluetooth API
まずWeb Bluetooth APIについて簡単に説明します。
先述したようにWebからBLE通信できる代物で、わざわざネイティブアプリを入れなくてもWebアプリで簡単にBLE通信を可能にするものです。
端末が対応していれば準備オッケー、いいですね。
対応ブラウザなどは以下から確認可能です。
web-bluetooth/implementation-status.md at master · WebBluetoothCG/web-bluetooth · GitHub
その他いろいろ制限(SSLが必須であるとか)があるみたいですが、とりあえず割愛(よくわからなかった)
作るもの
今回はブラウザからBLE Nanoにメッセージを送信し、その後は逆にBLE Nanoからメッセージを取得します。
ボトルメッセージ的な物をイメージしていただけたらなと。
BLE Nano側の実装
BLE NanoのサンプルコードのSimple Chatを元に改変します。
場所はスケッチの例
→ Examples for BLE Nano
→ BLE_Examples
→ Simple Chat
です。
そのままだとBLE Nanoから読み込みができないので、必要なタイミングでread用キャラクタリスティックをアップデートさせます。
ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), rx_buf, rx_buf_num);
全体はGitHubで、
https://github.com/hisurga/rw_blenanogithub.com
ブラウザ側の実装(html + javascript)
通信ではGATT(Generic Attribute Profile)を使用します。
GATTとはBLE通信を行う際の共通の形式です。これによってメーカに関わらず通信を可能にします。
今回の通信で重要なのはUUIDとValueかな、UUIDを指定することででBLE Nanoのサービスとデータ(Value)を扱うことができます。
開発にはCloud9を利用しました。
そこでコード書いてファイルをpublicにすれば、自動的にssl通信の環境になるので楽です。おすすめです。
全体はGitHubで、
requestDevice
本来であれば、「心拍数」などのすでに定義されているサービスを指定して検索をかけますが、今回のメッセージ保存に合致するBLEのサービスが見つからなかったので、acceptAllDevices
で周りのBLEを全て検索します。
それだけだと繋がらないので、optionalServices
でUUIDも指定します。(セキュリティ的な問題?)
UUIDはBLE Nanoの実装時に定義した物を利用します。
navigator.bluetooth.requestDevice({ optionalServices:[SERVICE_UUID], acceptAllDevices:true })
接続
.then(device => { console.log("devicename:" + device.name); console.log("id:" + device.id); return device.gatt.connect(); })
サービスの取得
.then(server => { console.log("success:connect to device"); return server.getPrimaryService(SERVICE_UUID); })
キャラクタリスティックを取得します。
こちらのUUIDもBLE Nano実装時の物を利用します。
RXがBLE Nanoからの読み込みに使うUUIDで、TXはBLE Nanoへの書き込みに使用します。
私はRXとTXを逆にしてしまっていて、それに気づかず1ヶ月ぐらい進捗ストップでした。
.then(service => { console.log("success:service"); // 複数のキャラクタリスティックを配列で取得可能 return Promise.all([ service.getCharacteristic(RX_CHARACTERISTIC_UUID), service.getCharacteristic(TX_CHARACTERISTIC_UUID) ]); })
使用するキャラクタリスティックが1つであれば、以下のようで問題ありません。
service.getCharacteristic(CHARACTERISTIC_UUID)
データ書き込み
writeValue()
でデータの書き込みです。
文字列をUTF-8形式で送信しています。
変換にはtext-encodingを使用しました。
var form_d = document.getElementById("data-form").value; var ary_u8 = new Uint8Array( new TextEncoder("utf-8").encode(form_d) ); console.log(ary_u8); try { txCharacteristic.writeValue(ary_u8); } catch (e) { console.log(e); }
データ読み込み
readValue()
でキャラクタリスティックからデータ読み込みです。
取得したvalueをArraybuffer形式にして、UTF-8形式でデコードしています。
let message; try { rxCharacteristic.readValue() .then(value => { message = value.buffer; console.log(new Uint8Array(message)); document.getElementById("data-form").value = new TextDecoder("utf-8").decode(message); }); } catch (e) { console.log(e); }
動作
MacBook+ChromeとAndroid+Chromeでは動くのを確認しました。
こんな感じに動きます。
WebBluetoothAPIとBLE Nanoでボトルメッセージ的な通信 #WebBluetooth #BLENano pic.twitter.com/rDelL9n34x
— surga (@hisurga) 2017年10月8日
可能性
つまるところ、Webコンテンツの可能性が増えたってことですよね。
以前までだとBluetoothを経由する場合アプリを入れることが必須でしたが、そもそもアプリを入れること自体にハードルがありました。
しかし今回、簡易的な通信であればWebで終わらせることが可能になったので、ハードルが下がって利便性もあがるんじゃないかなーと思います。
IoTデバイスからデータを引っ張ってくるだけならWebBluetoothで十分ですしね。