かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

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