#はじめに
iBeaconのアドバタイズパケットをスキャンするWindowsアプリを作ってみる。
#環境
- OS=Windows10
- 開発環境=Visual Studio 2015
- C#
- .Net Framework 4.6.1
- WPFアプリケーション
- iBeaconデバイス
- MAMORIO
- iPhone iBeacon Scanner
- Android Beacon Simulator
#プログラムを作る
##プロジェクト作成
- iBeaconScannerというWPFプロジェクトを新規作成する。
NuGetからUwpDesktopをインストールする。参考:WPFでBLEのアドバタイズパケットを拾ってみよう- NuGetから
Microsoft.Windows.SDK.Contracts
をインストールする
2020/8/31追記
Microsoft.Windows.SDK.Contracts
について
UwpDesktopは現在開発が止まっており、代わりにMicrosoft.Windows.SDK.Contracts
で同じことができます。
- Windows 10 WinRT API PackがNuGetパッケージ
Microsoft.Windows.SDK.Contracts
として公開されています。 - 開発プロジェクトを
PackageReference
対応へ設定変更し、NuGetパッケージを追加するだけで利用可能。
詳細
##プログラミング①
- usingにWindows.Devices.Bluetooth.Advertisementの追加
- クラスメンバにBluetoothLEAdvertisementWatcher advWatcherを追加
- MainWindowのコンストラクタでBluetoothLEAdvertisementWatcherクラスを生成、アドバタイズパケット受信イベントを追加してStartする。
MainWindowコンストラクタ
public MainWindow()
{
InitializeComponent();
this.advWatcher = new BluetoothLEAdvertisementWatcher();
this.advWatcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(1000);
this.advWatcher.Received += this.Watcher_Received;
this.advWatcher.Start();
}
- Watcher_Received()を追加。
- 非同期でイベントが発生するのでasync/awaitにする。
- アドバタイズパケットはargsに詰まっている。
Watcher_Received()
private async void Watcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
await this.Dispatcher.InvokeAsync(() => {
// ここで処理
});
}
###ひとやすみ・・・
- ここまでで、Bluetoothデバイスをスキャンするところまで完成。
- 実行すると、Bluetoothデバイスが近くにあればWatcher_Received()がCallされて、アドバタイズパケットがargsに詰まっている。
- iBeaconが発信するアドバタイズパケットもこの中に含まれているが、どれがiBeaconなのかチェックする必要がある。
##プログラミング②
- BluetoothLEAdvertisementReceivedEventArgsを解析する。
- Windows10デバイスでiBeaconの全データを取得する方法が大変参考になりましたので、そのままコピペさせていただきました。
Watcher_Receivedの中身を実装する
private async void Watcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
await this.Dispatcher.InvokeAsync(() => {
// 参考:Windows10デバイスでiBeaconの全データを取得する方法 http://sonic.blue/it/605
iBeacon bcon = new iBeacon(args);
if (bcon.UUID != null) {
// iBeacon
DateTimeOffset timestamp = args.Timestamp;
string retBeaconData;
retBeaconData = "{";
retBeaconData += string.Format("uuid:'{0}',", bcon.UUID);//"00000000-0000-0000-0000-000000000000"
retBeaconData += string.Format("major:{0},", bcon.Major.ToString("D"));
retBeaconData += string.Format("minor:{0},", bcon.Minor.ToString("D"));
retBeaconData += string.Format("measuredPower:{0},", bcon.MeasuredPower.ToString("D"));
retBeaconData += string.Format("rssi:{0},", bcon.Rssi.ToString("D"));
retBeaconData += string.Format("accuracy:{0},", bcon.Accuracy.ToString("F6"));
retBeaconData += string.Format("proximity:'{0}'", bcon.Proximity);
retBeaconData += "}";
this.textBox.Text = this.textBox.Text + timestamp.ToString("HH\\:mm\\:ss\\.fff") + ":" + retBeaconData + "\r\n";
}
});
}
###プログラミング完了
これで、Bluetoothデバイスが発信するアドバタイズパケットからiBeaconだけを抽出して画面のテキストボックスに表示するようなアプリができた。
#検証
##MAMORIO
- MAMORIOが届いたので解析したかったによると、UUID = b9407f30-f5f8-466e-aff9-25556b57fe6e 。
- MAMORIOからは30秒に1回ほどアドバタイズパケットが取れた。
##iPhone iBeacon Scanner
- Virtual iBeacon機能でアドバタイズパケットを発信できる。
- UUID = 95f428b1-4a3a-4e39-b086-21bff38deb6d
- アプリを立ち上げている間はスキャンできるが、iphoneがロックされるとスキャンできない。これはiOSアプリの仕様だろう(バックグランド発信できない)。
##Android Beacon Simulator
- SIMULATOR機能でアドバタイズパケットを発信できる。
- UUIDは自由に設定できる。
- Androidをロックしていてもパケット発信するし、アプリが立ち上がっていなくてもパケット発信している。Androdアプリはそういうものなのか、驚。
##その他
- 検証していると、上記以外のパケットがたくさんとれる、iBeaconデバイスがそんなに周りにあるのか、それともノイズなのか、謎…
#最後に
- 今回はざっくり実装ですが、Microsoftのサイトをきちんと読めば正しく理解できるかもです。 → Bluetooth LE アドバタイズ
- Bluetooth、BLE、Beacon、iBeacon。これらの仕様は複雑でネットの情報も少ないです。誤り、アドバイスなどいただければありがたいです。