Windows Phone Advent Calendar 2014の5日目です。
Windows Phoneと外部のセンサー・デバイス
Windows Phone 8.1端末にはGPS、加速度計、電子コンパス、ジャイロスコープなどのセンサーが搭載されています。また、カメラやNFCなどのデバイスも搭載されています。しかし、スマートフォンの小さな筐体に詰め込めるセンサーやデバイスは限度があるので、他のセンサー・デバイスを使いたいときは外部と連携する必要があります。
昨年のWindows Phone Advent Calendarで、「BluetoothによるWindows Phoneとデバイスの連携」と題してWindows Phone 8とワンボードマイコンのmbedをBluetooth(RFCOMM)で連携させる例を紹介しました。
このときはmbedにUSBドングルを挿していましたが、mbed側のプログラムが書きにくいため、RN-42XVPなどのSPPによるBluetooth通信モジュールをmbedにつなげる方法を先日に紹介しています。
- RN-42XVPを使ったmbedでのBluetooth連携(その1)
- RN-42XVPを使ったmbedでのBluetooth連携(その2)
- RN-42XVPを使ったmbedでのBluetooth連携(その3)
- RN-42XVPを使ったmbedでのBluetooth連携(その4)
- RN-42XVPを使ったmbedでのBluetooth連携(その5)
- Windows Phone 8.1 SilverlightアプリでのRFCOMM通信
Windows Phoneから標準にないセンサー・デバイスを使うときは、センサー・デバイスを接続したマイコンとRFCOMM(SPP)で通信を行うと楽に実現できます。
今年のWindows Phone Advent Calendarは、このClassic Bluetoothとは別のBluetoothであるBluetooth LEを使ってWindows Phone 8.1とデバイスを連携させる方法を紹介します。Windows Phoneと連携させるBluetooth LEデバイスは市販されている製品でもいいのですが、それだと面白くないのとmbedアドベントカレンダーの都合もあるため、mbedを使って自分で作ってみます。
Bluetooth LE
Bluetooth 4.0には従来のClassic Bluetoothの他に、Bluetooth Low Energy(Bluetooth LE)が定義されています。Bluetooth LEはBluetooth 3.0までとは互換性がなく、通信速度を抑える代わりにボタン電池でも動作できる省電力が実現されています。
Classic Bluetoothでは目的に応じて定義されたプロファイルに従ってデバイスとクライアントが通信しましたが、Bluetooth LEではGATT(Generic ATTribute)プロファイルを用いて通信します。GATTプロファイルは、その中に複数のService(サービス)を持ち、Serviceは複数のCharacteristic(特性)を持つ構造を取ります。
※採択済み Bluetooth コア仕様 バージョン4.0から引用
たとえば、体温計向けのプロファイルであるHealth Thermometer Profile(HTP)には体温計のサービスである"Health Thermometer Service"と、機器の情報を提供するサービスである"Device Information Service"が含まれます。“Health Thermometer Service"には体温計の情報である"Temperature Measurement Characteristic"のほか、オプションで追加のCharacteristicが含まれます。
mbedによるBluetooth LEデバイス
Windows Phoneと連携させるBluetooth LEデバイスは、今回は単純にHealth Thermometer Profileを使った温度計を作成します。
mbedでBluetooth LEデバイスを作るときに便利なのが“mbed HRM1017”です。 mbed HRM1017はBluetooth LEモジュールを搭載した開発ボードで、mbedの開発環境を使ってデバイスを制作できます。ちなみに、mbed HRM1017は工事設計認証(いわゆる技適)を得ています。
mbed HRM1017には他のmbedボードと同様にI2CやSPI、UARTのピンがあるので、これを使ってセンサーやデバイスを接続できます。なお、それぞれのピンに流せる電流に制限があるため、LEDを光らせる場合はFETなどでドライブする必要があります。
今回はADT7410というI2C対応の温度センサーをmbed HRM1017に接続します。接続するピンは以下の通りです。
:::text
HRM1017 <===> ADT7410
VDD VDD
P20(scl) scl
P22(sda) sda
GND GND
ブレットボードの配線は写真の通りです。
HRM1017に書き込むプログラムBLE_HTM_HRM1017は、tsuboi氏が公開されているBLE_HTM_HRM1017を改造したバージョンです。改造した点は以下の通りです。
- main.cppをADT7410に対応
- nRF51822ライブラリをHRM1017に対応(クロック関係)
これをビルドして作成されたhexファイルをHRM1017に配備しておきます。
なお、BLE_HTM_HRM1017の内部構造は次回に説明します。今回は、“Health Thermometer Profile"と"Health Thermometer Service"を経由して、温度を取得できるCharacteristicにアクセスできるとデバイスだと認識してください。
Windows Phone 8.1でのBluetooth LE
Windows Phone 8.1からBluetooth LE(HTP)デバイスにアクセスするサンプルコードBluetoothLEWinRTDemoをGitHubに公開しました。サンプルコードでHTPデバイスにアクセスしている箇所は、MainPageViewModelクラス(StrawhatNet.BLEDemo.Sharedプロジェクト)のStartMeasurementメソッドで、以下がそのポイントとなる処理です。
:::C#
// (1)Health Thermometer Serviceを提供するデバイスを選択する
string deveiceSelector = GattDeviceService.GetDeviceSelectorFromUuid(GattServiceUuids.HealthThermometer);
DeviceInformationCollection themometerServices = await DeviceInformation.FindAllAsync(deveiceSelector, null);
// デモ用なので見つかった最初のサービスを選択する
DeviceInformation themometerService = themometerServices[0];
GattDeviceService firstThermometerService = await GattDeviceService.FromIdAsync(themometerService.Id);
// (2) CharacteristicからTemperature Measurementを選択する(デモ用なので最初のを選択)
GattCharacteristic thermometerCharacteristic = firstThermometerService.GetCharacteristics(GattCharacteristicUuids.TemperatureMeasurement)[0];
// (3)Temperature Measurement Characteristicに値変更時のイベントハンドラを設定する
thermometerCharacteristic.ValueChanged += TemperatureMeasurementChanged;
// (4) Characteristic indication(デバイスからクライアントへの通知)を有効にする
thermometerCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Indicate);
値変更時のイベントハンドラでは、受け取ったデータから温度の値を求めています。Bluetooth LEの注意点として、温度計などの数値をそのまま受け取れるのではなく、プロファイルごとに決められたバイトデータでの表現形式にしたがって、バイトデータと値の変換をする必要があります。
:::C#
private async void TemperatureMeasurementChanged(
GattCharacteristic sender,
GattValueChangedEventArgs eventArgs)
{
// (1) Characteristicのバイトデータを読み込む
byte[] temperatureData = new byte[eventArgs.CharacteristicValue.Length];
Windows.Storage.Streams.DataReader.FromBuffer(eventArgs.CharacteristicValue).ReadBytes(temperatureData);
// (2) バイトデータを数値に変換する
UInt32 temp = (UInt32)(temperatureData[4] << 24)
| (UInt32)(temperatureData[3] << 8)
| (UInt32)(temperatureData[2] << 8)
| (UInt32)temperatureData[1];
UInt32 mantissa = temp & 0x00FFFFFF;
sbyte exponent = (sbyte)((temp >> 24) & 0x000000FF);
double temparature = (double)mantissa * Math.Pow(10, exponent);
// (3) 画面に表示する
await dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
TemperatureText = temparature.ToString();
});
}
なお、Windows Phone 8.1アプリからBluetooth LEを利用するためには、Capabilityを設定する必要があります。 CapabilityはPackage.appxmanifestを開いたGUI画面では設定できず、Package.appxmanifestファイルを直接編集する必要があります。
Package.appxmanifestファイルを右クリックしてコードの表示を選択して、以下の通りに書き換えます。
:::XML
<Capabilities>
...
<m2:DeviceCapability Name="bluetooth.genericAttributeProfile">
<m2:Device Id="any">
<m2:Function Type="name:healthThermometer" />
</m2:Device>
</m2:DeviceCapability>
</Capabilities>
Function要素のType属性に指定できる値は以下の通りです。
- name:battery
- name:bloodPressure
- name:cyclingSpeedAndCadence
- name:genericAccess
- name:genericAttribute
- name:glucose
- name:healthThermometer
- name:heartRate
- name:runningSpeedAndCadence
実行例
デモコードを実行するときは、前もってWindows Phoneとmbed HRM1017をペアリングしておきます。 ペアリングはWindows Phoneの設定画面からBluetoothを選択した画面で行えます。
その後、アプリを起動して、計測開始のボタンを押すと、mbed HRM1017が計測した温度を受け取り始めます。
Windows 8.1ストアアプリの場合
上記のコードで使ったAPIはWindows.Devices.Bluetooth.GenericAttributeProfile名前空間と、Windows.Devices.Enumeration名前空間に属するものです。このため、Windows 8.1ストアアプリでも使うことができます(Surface RTで動作確認済み)。
サンプルコードはWindows 8.1ストアアプリとWindows Phone 8.1のユニバーサルアプリのプロジェクトで、Bluetooth LEの処理部分は共有しています。
まとめ
RN-42XVPやmbed HRM1017などを使うことで、市販の製品にはない特徴・機能をもったデバイスを、Bluetoothを経由してWindows Phoneから利用できます。 また、mbed側のプログラムの説明ができていませんが、デバイス側のプログラミングは公開されているコードを利用して作成できるので、難易度も高くないと思います。 この方法をつかって、Windows 8.1/Windows Phone 8.1と連携する面白いガジェットがいろいろと出てくるといいですね。
Windows Phone Advent Calendar 2014はいよいよ
Windows Phoneアドベントカレンダーはまだまだ序盤で、この先さらに盛り上がっていきそうで楽しみです。 明日の6日目は@tomoya_shibataさんです。