かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

UWPでバックグラウンドでBLEの電波を受信する(未検証)

バックグラウンドでBLEの電波受けたら何かするっていうことが出来るようになってます。

用意するバックグラウンドタスクのクラスはこんな感じです。(Windows Runtimeコンポーネントのプロジェクトで作る必要があるのはバックグラウンドタスクのお約束ですね)

using System.Linq;
using Windows.ApplicationModel.Background;
using Windows.Devices.Bluetooth.Background;
using Windows.UI.Notifications;

namespace RuntimeComponent1
{
    public sealed class BLETask : IBackgroundTask
    {
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            var detail = taskInstance.TriggerDetails as BluetoothLEAdvertisementWatcherTriggerDetails;
            if (detail == null) { return; }

            var rssis = string.Join("\n", detail.Advertisements
                .Select(x => $"{x.BluetoothAddress.ToString("X")}: {x.RawSignalStrengthInDBm}")
                .ToArray());

            var toast = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01);
            toast.GetElementsByTagName("text").First().AppendChild(toast.CreateTextNode(rssis));
            var tn = new ToastNotification(toast);
            ToastNotificationManager.CreateToastNotifier().Show(tn);
        }
    }
}

受信した電波のRSSIとかをトーストで出すだけにしてみました。

そして、バックグラウンドタスクの登録のコードは以下のような感じでApp.xaml.csに適当にメソッドをはやして、これをOnLaunchで呼んでいます。

private void RegisterBackgroundTasks()
{
    foreach (var task in BackgroundTaskRegistration.AllTasks.Values)
    {
        task.Unregister(true);
    }

    var trigger = new BluetoothLEAdvertisementWatcherTrigger();
    var dw = new DataWriter();
    dw.WriteUInt16(0x0123);
    trigger.AdvertisementFilter.Advertisement.ManufacturerData.Add(new BluetoothLEManufacturerData
    {
        CompanyId = 0xFFFF,
        Data = dw.DetachBuffer()
    });
    trigger.SignalStrengthFilter.InRangeThresholdInDBm = -60;
    trigger.SignalStrengthFilter.OutOfRangeThresholdInDBm = -65;
    trigger.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(2000);
    trigger.SignalStrengthFilter.SamplingInterval = TimeSpan.FromSeconds(10);

    var taskBuilder = new BackgroundTaskBuilder();
    taskBuilder.Name = "BLE";
    taskBuilder.TaskEntryPoint = typeof(RuntimeComponent1.BLETask).FullName;
    taskBuilder.SetTrigger(trigger);
    taskBuilder.Register();
}

このとき、trigger.AdvertisementFilterには何かしらフィルタの条件を追加しないとエラーになります。無制限に電波受信してわいわいやるようなアプリは作れないっぽいです。

あとは、appxmanifestで機能でBluetoothを選択して、宣言でバックグラウンドタスクを作成してサポートされるタスクの種類をBluetoothにしてエントリポイントにバックグラウンドタスク名を設定すればOKです。

ただ…。ビーコン持ってないので試せないorz