さて、UWPのAPIを使えるということで先日アドバタイズパケットの受信をやりました。
今度はBLEの通信をしてみたいと思います。
参考ページは以下。
そして、今回使うセンサーはSensorTagのv1です。
Windows Runtime用ソースコードがあるので、参考にさせてもらいます。
作ってみよう
WPFのプロジェクトを作ってUwpDesktopパッケージをNuGetからインストールします。SensorTagで使うUUIDを定義します。
namespace BleSample { public class SensorTagUuid { // https://sensortag.codeplex.com/SourceControl/latest#SensorTagLibrary/SensorTagLibrary/Source/SensorTagUuid.cs public const string UuidIrtService = "f000aa00-0451-4000-b000-000000000000"; public const string UuidIrtData = "f000aa01-0451-4000-b000-000000000000"; public const string UuidIrtConf = "f000aa02-0451-4000-b000-000000000000"; } }
画面に初期化用ボタンと値を読み込み始めるボタンとデータ表示用TextBlockを置きます。
<Window x:Class="BleSample.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:BleSample" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <StackPanel> <Button Content="Connect" Click="ButtonConnect_Click" /> <Button Content="Read value" Click="ButtonReadValue_Click" /> <TextBlock x:Name="TextBlockTemp" /> </StackPanel> </Window>
そして、コードビハインドにUWPのAPIを使ってさくっとコードを書きましょう。
using System; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using System.Windows; using Windows.Devices.Bluetooth.GenericAttributeProfile; using Windows.Devices.Enumeration; using Windows.Storage.Streams; namespace BleSample { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { private GattDeviceService GattDeviceService { get; set; } private GattCharacteristic GattCharacteristic { get; set; } public MainWindow() { InitializeComponent(); } private async void ButtonConnect_Click(object sender, RoutedEventArgs e) { // SensorTagを取得 var selector = GattDeviceService.GetDeviceSelectorFromUuid(new Guid(SensorTagUuid.UuidIrtService)); var devices = await DeviceInformation.FindAllAsync(selector); var deviceInformation = devices.FirstOrDefault(); if (deviceInformation == null) { MessageBox.Show("not found"); return; } this.GattDeviceService = await GattDeviceService.FromIdAsync(deviceInformation.Id); MessageBox.Show($"found {deviceInformation.Id}"); // センサーの有効化? var configCharacteristic = this.GattDeviceService.GetCharacteristics(new Guid(SensorTagUuid.UuidIrtConf)).First(); var status = await configCharacteristic.WriteValueAsync(new byte[] { 1 }.AsBuffer()); if (status == GattCommunicationStatus.Unreachable) { MessageBox.Show("Initialize failed"); return; } } private async void ButtonReadValue_Click(object sender, RoutedEventArgs e) { if (this.GattDeviceService == null) { MessageBox.Show("Please click connect button"); return; } // 値を読み始める if (this.GattCharacteristic == null) { this.GattCharacteristic = this.GattDeviceService.GetCharacteristics(new Guid(SensorTagUuid.UuidIrtData)).First(); this.GattCharacteristic.ValueChanged += this.GattCharacteristic_ValueChanged; var status = await this.GattCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify); if (status == GattCommunicationStatus.Unreachable) { MessageBox.Show("Failed"); } } } private async void GattCharacteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args) { // 値を読んで表示する await this.Dispatcher.InvokeAsync(() => { var data = new byte[args.CharacteristicValue.Length]; DataReader.FromBuffer(args.CharacteristicValue).ReadBytes(data); var temp = BitConverter.ToUInt16(data, 2) / 128.0; this.TextBlockTemp.Text = $"{temp}℃"; }); } } }
基本的にGattなにがし系のクラスを使う感じですね。あとはIBufferとbyte[]の相互変換あたりがポイントでしょうか。あとはSensorTagのコードを参考に真似させてもらいました。
実行してボタンをぽちぽちっと押すと温度が表示されます。
ソースコード
ソースコード全体はGitHubに上げておきます。