LoginSignup
6
5

More than 3 years have passed since last update.

Xamarin.Forms Tips - Plugin.BLEを使う

Last updated at Posted at 2020-05-17

概要

今、温度センサーを使って、配達物の温度監視をするIoTシステムを作っています。
Xamarin.Formsで、まずはiPhoneアプリを作ってみようかと。
温度センサーには、Inkbird IBS-TH1 miniを使います。

ということで、iPhoneアプリでBLE通信を行うわけですが、
そのためにPlubin.BLEを使った話。

開発環境など

Macbook Air(macOS Catalina 10.15.4)
Visual Studio for Mac(8.5.5)
Xamarin.Forms

Plugin.BLEを入れる

  1. プロジェクトメニューから、NuGetパッケージの管理を選択します。
    スクリーンショット 2020-05-17 15.49.20.png

  2. 「Plugin.BLE」を検索し、チェックを入れ、パッケージの追加をクリックします。
    ※全てのプロジェクトに追加してください。
    スクリーンショット 2020-05-17 15.49.52.png

Plugin.BLEを使う

共通プロジェクトで画面を作成し、開始ボタンがクリックされたら、
BLE通信の処理を開始するようにしています。
今回はタイマー処理で、1分間に1度温度センサーからデータを取得するようにしています。

まずはボタンがクリックされた時の処理

MainPage.cs
        private IBluetoothLE _BluetoothLe;
        private IAdapter _Adapter;

        async void StartButton_Clicked(System.Object sender, System.EventArgs e)
        {

            _BluetoothLe = Plugin.BLE.CrossBluetoothLE.Current;
            _Adapter = _BluetoothLe.Adapter;

            // スキャン時間:5秒
            _Adapter.ScanTimeout = 5000;

            // スキャンでBLEデバイスが見つかった時の処理
            _Adapter.DeviceDiscovered += (s, ev) =>
            {
                // 温度計測処理
                TempMeasure(ev);
            };

            if (_BluetoothLe.State == BluetoothState.Off)
            {
                await DisplayAlert("Warning !", "Bluetoothが無効になっています。", "OK");
                return;
            }

            if (_Adapter.IsScanning)
            {
                await DisplayAlert("Warning !", "Bluetoothが別処理中です", "OK");
                return;
            }

            // タイマー処理開始
            _IsMeasure = true;
            Device.StartTimer(new TimeSpan(0, 1, 0), () =>
            {
                // BLEのスキャン開始
                _Adapter.StartScanningForDevicesAsync();
                return _IsMeasure;
            });
        }

StartScanningForDevicesAsyncを呼び出すと、BLEデバイスのスキャンが始まります。
BLEデバイスが見つかると、DeviceDiscoveredに登録した処理が呼び出されます。
ここでは、TempMeasureという関数を呼び出しています。

TempMeasure関数の処理はこんな感じ。

MainPage.cs
        private async void TempMeasure(DeviceEventArgs e)
        {
            // 接続対象デバイスのSystem ID
            byte[] targetSystemID = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };

            // Inkbird IBS-TH1シリーズは、デバイス名が「sps」となっている
            if (e.Device.Name != "sps")
            {
                return;
            }

            // デバイス接続
            await _Adapter.ConnectToKnownDeviceAsync(e.Device.Id);
            if (e.Device.State == DeviceState.Disconnected)
            {
                // 接続できなかった場合
                Debug.WriteLine("デバイスと接続できません。Device Id : " + e.Device.Id.ToString());
                return;
            }

            // Device Informationサービスの取得
            var service = await e.Device.GetServiceAsync(new Guid("0000180a-0000-1000-8000-00805f9b34fb"));

            // System IDの取得
            var characteristic = await service.GetCharacteristicAsync(new Guid("00002a23-0000-1000-8000-00805f9b34fb"));

            if (characteristic.CanRead)
            {
                // データ(System ID)の取得
                await characteristic.ReadAsync();

                // 取得対象デバイスかを確認
                if(targetSystemID.SequenceEqual(characteristic.Value))
                {
                    // AdvertisementRecordsから、温度データ取得
                    double Temp = BitConverter.ToInt16(e.Device.AdvertisementRecords[1].Data, 0) / 100.0;
                    Debug.WriteLine("Temp : " + Temp.ToString("0.00"));
                }
            }

            // 切断
            await _Adapter.DisconnectDeviceAsync(e.Device);
        }

ハマったこと

■ Bluetoothを使用したタイミングでアプリが落ちる
iPadで動かした時に、何故かアプリが落ちる現象が・・・。
iPhoneでは動いていたから、コードの問題じゃないだろうと思い、調べてみると、
Plugin.BLEのgithubのissueに、同様の書き込みをしている人が。
https://github.com/xabre/xamarin-bluetooth-le/issues/387

アプリのデプロイ先がiOS 13以降の場合、info.plistに
・NSBluetoothAlwaysUsageDescription
・NSBluetoothPeripheralUsageDescription
を加えなければいけないとのこと。

ということで、こんな感じに追加して再度試すと、無事動きました。
→「プライバシー - Bluetooth 周辺機器の利用状況の説明」と「NSBluetoothAlwaysUsageDescription」の行
スクリーンショット 2020-05-17 21.18.10.png

■ iOSでは、アドバタイズしてきたデバイスのMACアドレスが取得できない
これはどうやらPlugin.BLEの問題ではなくて、iOS側がMACアドレスを隠蔽しているらしいです。
デバイスの識別にMACアドレスを使用しようと思ってたんですが・・・。

もう一つハマったことがあって、デバイスの識別にMACアドレスが使えないから、
StartScanningForDevicesAsyncで検知された際のID(DeviceEventArgsのDevice.Id)で識別しようとしたら、
なぜか手持ちのiPhoneとiPadで、違うIDが渡ってくる・・・。
このID、どうやって生成されているものなんだろう・・・。

ということで、今回例示しているソースコードでは、
一旦デバイスと接続して、Device InformationサービスのSystem IDを取得し、
自分がターゲットとしているデバイスかどうかを判別しています。

なんか、内容がXamarin.FormsのTipsという感じじゃなくなっちゃったな(汗)。

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5