Web Bluetooth APIでBLEビーコンを受信する

2020/06/07

使ってみた

t f B! P L

どうもどうも、Bluetooth&IoT大好きひつじ(@youmounlp)です。
 
ひょんなことからIoTデバイスを購入し、それをWeb Bluetooth APIから使えるんじゃないか?と思ったのがこの記事のきっかけです。
 
結局Web Bluetooth APIを使うのはやめたのですが、後々使うことになるかもしれないので、記録を残しておきます。

ビーコン

私がゲットしたIoTデバイスは、Bluetoothを介してあるデータを送信してくる仕様です。いや、あるデータとかぼかす必要ないですね笑。データは温度湿度なので、単なる温湿度計デバイスなります。
 
全然詳しくないのですが、Bluetooth Low Energy(BLE)という規格で通信するようで、IoTデバイス側は非常に省電力で動作するようです。
 
そのデバイスは、製造元メーカーがアプリも作っており、デバイスから送信されてくる温度、湿度をアプリ上から確認できます。
なので、Bluetoothの届く範囲にスマホをおいている限り、アプリは1日中データを受け取って、グラフ化なんかもしてくれます。
 
私の部屋はデスクの横にベッドがあり、1日の大半はたいていデスクで作業しているか、ベッドでゴロゴロしているので、体の一部と化しているスマホはほぼ確実にデータを受信できます
 
Bluetoothに対する認識が10年以上更新されていない私からすると、スマホとデバイスをペアリングするのか?と思いますが、BLEにはビーコンという仕組みがあるらしく、ペアリングせずにデータのやり取りができるそうです。
 
正確には、IoTデバイス側からスマホ側へ、一方的にデータを送りつけることができるようです。その逆で、スマホ側からデバイスに何らかの操作をする、ということはできません。この場合はふつうにペアリングする必要があります。
 
どうやって動くかというのは、こちらのサイト様の説明が大変わかりやすかったです。

BLEにおけるビーコンとは、セントラルがペリフェラルにConnectせずにペリフェラルの情報を得る裏技です。
実は、ペリフェラル側はAdvertise時に少しの情報をある程度載せる事ができます。
それをセントラル側がScan時にチラ見するという具合です。

出典: 開発視点の超簡単BLE入門
 
セントラルがスマホ側、ペリフェラルがIoTデバイス側です。そして、Advertiseは、IoTデバイスがペアリング前に自分を見つけてもらうために電波を飛ばす行為です。WI-FIのアクセスポイントがSSIDを飛ばしているようなものと理解しています。
 
で、上に書いてあるように、Advertise時にちょっとした量のデータを載せることができるようです。なので、スマホ側では、AdvertiseをScanした際に、そのままConnect(接続)に移らずデータだけを貰うという処理をすれば、一方通行ではありますがペアリング無しのデータ送信が実現します。
 
すごい!私はこういう少量のデータの類や小技的なやり口が大好きなので興奮を禁じえません。
 
温湿度計デバイスの場合は、毎回のAdvertise時にそのときどきの温度、湿度を載せます。
 
さて、非常に素晴らしい、楽しい技術なのですが、BLEで省電力なのはあくまでIoTデバイス側の話で、それを受信するスマホアプリは常にバックグラウンドで起動しています。
 
スマホでアプリごとの電池消費量を見てみると、温湿度計アプリが結構電池を食ってしまっています。楽しいアプリだけど温湿度計でこんなに電池食うのはなぁ、、、何なら物理温湿度計、部屋においてあるし
 
理想としては、温湿度計アプリを立ち上げたときだけ受信するようにしたい、これはメーカーのアプリでは無理なので、自分でAndroidアプリを作る必要があります。
 
でも、もっと手軽にやりたいなぁ、ということでWebアプリとして作りたくなり、冒頭のWeb Bluetooth APIにつながります。

Web Bluetooth API

さて、Bluetooth APIです。Bluetoothはかなりネイティブ寄り?というんですかね、これも全然詳しくないのですが、デバイスや環境固有の低レイヤーなAPIを使う必要があるため、実装や標準化が難しいのだそう。
 
例えば、PythonのBluetoothライブラリを調べてみても、OSごとに対応非対応が結構割れていたりと大変そうな世界だった。
 
これは、ブラウザから利用できるWeb Bluetooth APIでも一緒で、各ブラウザとも実装に苦心している印象です。ただ、ブラウザ自体がキラーアプリというか利用者が多いため、数あるBluetooth関連の実装の中でも、開発が活発であるのは事実です。ブラウザの実装で、OS固有のBluetooth APIをラップしてくれれば、これほど有り難いことはありません。
 
これを使ってAndroidのChromeからIoTデバイスの温湿度データを取得できたので、その方法を記します。
 
実装には、以下のWeb Bluetooth Scanningを使います。
 
Web Bluetooth Scanning
 
更新日が13 May 2020になっており、ほんとに近々の話であることがわかります。
 
各環境におけるセットアップ方法は以下。Androidではchrome://flags/#enable-experimental-web-platform-featuresフラグをEnabledにする必要があるようです。
https://github.com/WebBluetoothCG/web-bluetooth/blob/master/implementation-status.md#scanning-api
 
大変ありがたいことにサンプルまであります。
https://googlechrome.github.io/samples/web-bluetooth/scan.html
 
結論しては、navigator.bluetooth.requestLEScan()というメソッドを使っているようです。
 
サンプルにおいて、Device NameにBluetoothデバイスの名前を入れて、Scanボタンを押すと、受信したAdvertiseおよびそのデータが表示されます。Device Nameは、スマホでBluetoothのペアリング相手をふつうにScanした際に出てくるデバイス名を入力します。
 
上手く受信できると、(Hex)の行にAdvertiseに載っているデータが表示されます。データ形式はバイナリで、4bitごとに16進数になっています。
 
ここからは自由行動、というかデバイスごとにやることが異なります。デバイスごとに何bit目から何bit目が〇〇のデータというようにフォーマット・プロトコルが決まっているはずです。デバイスの仕様書で確認してください。例えば、私の温湿度計では、下位12bitが温度を表す、などという具合です。
 
上2つのリンクはWebBluetoothCGというグループのgithubですが、サンプルはGoogleChromeのgithubにあがっています。両者ともrequestLEScanに言及しているので、おそらく同じものを指しているのだと思われますが、対応デバイスの表記に差があります。現段階では並行してWIPなのかもしれません。
 
ともあれ、これで少なくとも(Hex)行に現れるバイナリデータをいじいじすれば、Advertiseによるビーコンを用いたデータ取得が、Webアプリから可能になる、ということが理解できました。

結末

結局、セキュリティ上の理由から、普段遣いのスマホでchrome://flags/#enable-experimental-web-platform-featuresフラグをEnabledにするのに抵抗があったため、採用は見送りました。requestLEScanが標準化される日を心待ちにしています。
 
結末としては、実はアプリ側にバックグラウンドで起動させないようにする設定がありました笑。そして温度を見たいときにBluetoothをONにしてアプリを起動すると、すぐに温度を取得してくれました。2タップ必要ですがこれでほぼ要件を満たしています。バッテリーを無駄に消費することもありません。
 
スマホのBluetoothがOFFになっているときも、温湿度計デバイスは健気に温湿度をAdvertiseしているので、たまにはスマホアプリから見てあげようと思います。

ラベル

QooQ