Windows 10 における Bluetooth サポートについて


大分、更新が滞っていましたが、Windows 10 Version 1511(TH2)における BLE(Bluetooth Low Energy)のサポートに関して、調べた内容を記載します。

詳細は省きますが、Bluetooth 4.0以降では、GATT(General Attribute Profile)とAdvertisement(iBeaconで有名な通信方式)の通信方式が追加されています。Windows 10 のアプリ環境である UWP では、2015年7月のリリース時点から、GATT と Advertisement もサポートされていました(GATT については、Windows 8.1のストア アプリからサポートされていました)。Windows 10 Version 1511に対応した Windows SDK 10586 における Bluetooth サポートの機能強化点は、コードによるペアリング操作のサポートになります。具体的には、Windows.Deveices.Enumeration 名前空間における DeviceInformationPairing クラスと DeviceInformationCustomPairing クラスを使うことで、ペアリングを行うことができるというものです。このペアリング操作を行うサンプルも、githubで公開されています。具体例はサンプルを見て頂くとして、ペアリングのための2つのクラスでできることを簡単にまとめます。

  • DeviceInformationPairing クラス
    標準的なペアリング操作を行うためのクラスで、PairAsync メソッド呼び出すと、システム側がペアリング 操作に必要なダイアログを表示します。必要なダイアログとは、「ペアリングをしますか?」や「ペアリング コードの入力」などになります。
  • DeviceInformationCustomPairing クラス
    PairAsync メソッドとPairringRequested イベント ハンドラの組み合わせを使用することで、通信の暗号方式を指定したり、ペアリング コードをコードで指定する(DevicePairingKinds列挙値で指定します)ことができるようになります。これは、標準的なペアリング コード「00000」などを自動的に処理する場合などに使用すると、最低限度の操作でペアリングを行うことができるので、ユーザーにとって操作が易しくなるメリットがあります。

General Attribute Profileについて

GATTのドキュメントは、Windows デベロッパー センターにありますが、より参考になるサンプルもあります。このサンプルは、TI SensorTagを使用するためのものです。GATTを使った通信の基本的な考え方を次に示します。

  • DeviceInformation.FindAllAsyncメソッドで、目的の BLE デバイスを取得します。
  • GattDeviceService.FromIdAsyncメソッドで、GATTのサービスを取得します。
  • 取得したサービスのGetCharacteristicsメソッドを使用して、GattCharacteristic を取得します。
  • ValueChangedイベント ハンドラを設定してから、WriteClientCharacteristicConfigurationDescriptorAsync メソッドで通知を有効にします。
    もちろん、通知サービスを使わないのであれば、これは必要ありません。
  • WriteValueAsync メソッドでデータを送信すれば、ValueChanged イベント ハンドラが呼び出されて結果を取得することができます。

GattCharacteristic には、Device Informationサービス(0000180a-0000-1000-8000-00805f9b34fb)がありますので、このサービスを使用することでデバイス情報を取得することができます。Device Information サービスを実装していない BLE デバイスもありますが、TI SensorTagは実装しているので、問題なくデバイス情報を取得することができます。

GATTを使用する場合は、Package.appxmanifestに Bluetoothの使用を宣言する必要があります。これには、2つの方法があります。

  • Visual Studio のマニフェスト デザイナの[機能]タブで、「Bluetooth」を有効にするか、
  • Package.appxmanifestをコード エディタで編集する方法です。

コード エディタで編集するには、「How to specific device capabilties for Bluetooth(Windows Runtime apps」というドキュメントを参考にします。このドキュメントは、Windows 8.1用に記述されたものなので、UWPでは、プレフィックスの「m2:」を削除することで記述することができます。これは、UWPの名前空間にGATTサポートが含まれていることが理由で、Windows 8.1の時は後から追加されたことから名前空間を追加する必要があったことに由来します。Windows ストア アプリや UWP アプリで、GATT通信を行う上での重要な前提条件は、「ペアリングが必要」という点になります。それと、BLE デバイスの GATT 通信は、通信データの暗号化がほとんどのデバイスで行われていない点にもご注意ください。Bluetoothの規格では、暗号化のサポートもありますが、私が調べた幾つかデバイスでは、暗号化通信を実装しているデバイスは見つかりませんでした。この事は、よりセキュアな通信を行いたいのであれば、独自に暗号化などを考える必要があるということを意味していると考えられます。GATT 通信を試される場合は、通信の暗号化も調べてみてください。暗号化は、GattCharacteristic 単位に設定されています。

 

Advertisementについて

俗称 Beaconの正式名称は、Bluetooth Advertisementになります。BLE デバイスの特徴の 1つとして、デバイス ペアリングの速度向上のためにデバイスの探索に Advertisement パケットを使用しています。逆の言い方をすると、ペアリングに Advertisement パケットしか使用しない BLE デバイスは、Bluetooth 3.x までの機器との通信ができないということになります。

Advertisement サンプルの、SDK サンプルに含まれています。SDK サンプルのコードを見る前に、Advertisement の考え方を知る必要があります。もちろん、Advertisementをご存知の方もいらっしゃるとは思いますが、復習を兼ねて簡単に説明します。

最初に、Advertisement( Beacon )機器とは、Advertisement パケットを一定間隔で不特定多数の機器に対して発信(ブロード キャスト)するもののことを指します。不特定多数の機器に向けたブロード キャストですから、通信が暗号化されていないことが容易に想像できることでしょう。そして、Advertisement パケットを受信する側の機器(一般的にアプリ)が、受信した特定の Advertisement パケットに応じて、何らかの処理を行うことになります。この何らかの処理が、割引クーポンを表示したりということであって、Advertisement パケットに割引クーポンの情報が含まれていることは少ないのではないでしょうか。また、このようなアプリを考える場合に注意しないといけないのは、Advertisement パケットは一定間隔で繰り返し送信されている点です。つまり、同一の機器(同一かどうかは、Bluetoothのアドレスで識別できます)の場合は、1度処理すれば、それ以降は処理しないようにする必要があるということになります。これは、アプリの目的によって異なったりしますが、Advertisement パケットは繰り返し発信されるものだという点を理解しておいてください。例として説明した割引クーポンを表示するアプリの場合は、次のような動作をすることになるでしょう。

  • デバイスにクーポン アプリをインストール。
  • アプリのバックグラウンド タスクが Advertisement パケットを受信して、クーポンがある旨をデバイスに通知する(これは、アプリは起動されることがまれなためです)。
  • ユーザーが通知をタップすることで、アプリが起動し、割引クーポンが表示される。
  • アプリのバックグランド タスクは、表示済みの割引クーポンに該当する Advertisementパケットを表示してからは無視する。

UWP では、Advertisement パケットを処理するために、Windows.Devices.Bluetooth.Advertisement 名前空間にBluetoothLEAdvertisementWatcher クラスとBluetoothLEAdvertisementPublisher クラスが用意されています。

Advertisement を処理する基本のクラスを説明しましたので、SDK サンプルで提供される機能を説明します。

Advertisement パケットの送信と受信を、フォアグランドとバックグランドで行う機能の4 種類がサンプルに含まれています。更にサンプルの特徴としては、CompanyId に 0xFFFE を設定し、UUID に 0x1234 を設定し、AdvertisementFilter を使って BLE デバイスのフィルタリングを行っていることです。このフィルタリングを行っている理由は、特定の BLE デバイス(CompanyId が 0xFFFE で、UUID が 0x1234)の Advertisement パケットのみに反応するようにしているためです。たとえば、iPhoneなどの Advertisement パケットを受信する場合は、このフィルタリングを変更する必要があります。この SDK サンプルを使って、Advertisementの動作を確認するのは、Windows 10 デバイスが2つ必要になります。

  • 1つの Windows 10 デバイスでサンプルを動かし、BluetoothLEAdvertisementWatcher をフォアグラウンドかバックグラウンドで実行します。
  • もう 1つの Windows 10 デバイスでサンプルを動かし、BluetoothLEAdvertisementPublisher をフォアグラウンドかバックグラウンドで実行します。
  • こうすることで、BluetoothLEAdvertisementWatcher を実行している Windows 10 デバイスがAdvertisement パケットを受信するようになります。

この SDK サンプルに含まれていない機能としては、独自のデータを Advertisement パケットに送信することです。このような機能を実装するには、BluetoothLEAdvertisementDataSection クラスを使って送信データを用意し、BluetoothLEAdvertisementPublisher.DataSections.Addメソッドで送信データを追加してから、BluetoothLEAdvertisementPublisher のStartメソッドを呼び出します。

受信する側は、BluetoothLEAdvertisementWatcher の Received イベント ハンドラでイベント引数に含まれる Advertisement クラスの DataSections コレクションより DataSection を読み出すことで受信したデータを確認することができます。BluetoothLEAdvertisementWatcher クラスを使用する上での注意点は、ウォッチャーを繰り返すインターバル(SignalStrengthFilter.SamplingInterval)が、デフォルトで「ゼロ」になっている点です。インターバルがゼロのままだと、CPU負荷が高くなりますので、適切な間隔(SDK サンプルでは 1秒)に指定しないと、アプリの動作に支障をきたすことになります。

もちろん、Advertisement パケットを処理するには、BLE デバイスのペアリングは必要ありません

Comments (2)

  1. okojyo より:

    初めまして。ble関連の記事を見つけまして、興味深く拝見させていただきました。日本語の資料の少なく、大変参考になります。
    現在、Win10環境にて、BluetoothLEAdvertisementWatcherを利用して、
    1秒間隔で電波を発信するビーコンの電波を補足するアプリを作成しているのですが、WatcherのReceivedイベントが1秒間隔で発生せず、また発生イベントタイミングに開きがあり、等間隔でイベント検出できない状態です。
    長い時は10秒ほどイベントが発生しないこともあり、もう少し検出感度を高めたいのですが・・
    設定パラメータは、manufacturedataのフィルター以外はsdkサンプル提示の状態です。

    個人的には、iosのbluetoothLE検出オプションCBCentralManagerscanOptionAllowDuplicate
    のように、、ハードウェアが受信できた電波の分だけ、同時タイミングでイベントを発生させることが出来るようにも思えるのですが、WindowsのBluetothLEAdvertiseWatcherはどのような仕様になっているのでしょうか?

    1. shozoa より:

      気が付くのが、遅くなってごめんなさい。自分で作成したBluetoothLEAdvertisementWatcherを使ったビーコン検出ですが、私の場合はほぼ指定間隔で取得することができます。
      しかしながら、Watcherを開始する場合によっては非常に時間がかかる場合も散見されます。これらの違いを自分なりに考察してみると、時間がかかる場合は受信するビーコンが多い場合に処理時間がかかるようです。私が作成しているビーコンのレシーバーは、watcher.Start()でWatcherを開始し、Receivedイベントで受信したビーコンの内容を表示するというものです。この表示に、時間がかかる場合と、スムーズに表示される場合がありました。このため、ファイルや配列に記録し、Watcherを停止してから表示するようにしたら、問題なく表示ができています。この事象から考えると、BluetoothLEAdvertisementWatcherに適切なフィルタを記述しないと、ビーコンの受信に時間がかかる場合のオーバーヘッドが大きいということです。ですので、試されるのであれば、1)インターバルを伸ばしてみるか、2)受信したビーコンをファイルや配列に記録するなどの対策をして、データを正常に受信できているかを確認することでしょうか。

Skip to main content