Bluetooth Low Energy通信(2)
基本のプログラム
まず基本的なサンプルから作成してみます。最初に、次のパッケージをインストールしておきます。
- nanoFramework.Device.Bluetooth
またサービスとキャラクタリスティックのUUIDは、あらかじめ上記サービスなど作成しておきます。コードは、次のようになります。これはセントラルに対して、固定の文字列の送信と定期的に通知を行うものです。
public static void Main() { // UUIDの定義(1) Guid serviceUuid = new("A6C00538-6373-4FC2-65B3-F43EAA9F9887"); Guid charUuid = new("6CB42289-2139-A2A9-960D-C9E6960E5988"); // BLEオブエジェクトの生成(シングルトン)(2) BluetoothLEServer server = BluetoothLEServer.Instance; // デバイス名の設定(3) server.DeviceName = "ESP32 BLE No.1"; // サービスオブジェクトの生成(4) var result = GattServiceProvider.Create(serviceUuid); if (result.Error != BluetoothError.Success) { return; } // キャラクタリスティックオブジェクトの生成(5) var characteristicResult = result.ServiceProvider.Service.CreateCharacteristic( charUuid, new GattLocalCharacteristicParameters() { // プロパティに読み取りと通知を設定する(6) CharacteristicProperties = GattCharacteristicProperties.Read | GattCharacteristicProperties.Notify, UserDescription = "ESP Read Characteristic" }); if (characteristicResult.Error != BluetoothError.Success) { return; } // 読み取り時のイベントハンドラ追加(7) characteristicResult.Characteristic.ReadRequested += (sender, ReadRequestEventArgs) => { var request = ReadRequestEventArgs.GetRequest(); DataWriter writer = new(); writer.WriteString("1.23"); // 固定値 request.RespondWithValue(writer.DetachBuffer()); }; // 通知のイベント作成(8) Timer notifyTimer = new((state) => { if (characteristicResult.Characteristic.SubscribedClients.Length > 0) { DataWriter writer = new(); writer.WriteBytes(new byte[] { 0, 1, 2 }); // 固定値 characteristicResult.Characteristic.NotifyValue( writer.DetachBuffer() ); } }, null, 3000, 5000); // 3秒後に5秒間隔で実行する // アドバタイズの開始(9) result.ServiceProvider.StartAdvertising( new GattServiceProviderAdvertisingParameters() { IsConnectable = true, IsDiscoverable = true } ); Thread.Sleep(Timeout.Infinite); }
まず使用するUUIDを定義します(1)。次に、BLE通信のメインオブジェクトとなるBluetoothLEServerオブジェクトを生成します(2)。このオブジェクトはシングルトンで、BluetoothLEServer.Instanceプロパティの最初の呼び出し時に、実際のインスタンスが生成されます。
設定したデバイス名は(3)、セントラルでのスキャン時に表示される名称となります。定義したUUIDを使ってサービスを生成し(4)、キャラクタリスティックのオブジェクトを生成します(5)。ここでのキャラクタリスティックのプロパティとして、読み取りと通知を設定しています(6)。
セントラルからの読み取り要求のイベントハンドラとして、固定の文字列を送信する処理をラムダ式で定義しています(7)。送信するデータは、バイト列を操作するためのBufferオブジェクトにする必要があります。ここでは、nanoFramework.Device.Bluetooth.DataWriterクラスを利用しています。DataWriterクラスは、文字列や数値などをBufferオブジェクトに変換するのに便利なクラスです。
セントラルへの通知は、ここではTimerクラスを利用して、定期的に実行されるようにしています(8)。ここでも実行される処理は、ラムダ式で記述しています。なお、ペリフェラルからの通知は、セントラルが受け取る許可(サブスクライブ)が必要です。サブスクライブしている場合のみ、通知するようにしています。
なお通知の場合は、送信できるデータの最大サイズが20バイト以下に制限されています。大きなサイズのデータを設定しても、20バイトしか送信できません。
最後に、アドバタイズを開始します(9)。IsDiscoverableは、デバイスを検出できるようにする、IsConnectableは、ペリフェラルとして接続可能とするプロパティです。
BLE通知の確認
サンプルコードを実行して実際の通信を試すには、セントラルとなるデバイスが必要です。このとき、PCよりもスマートフォンのアプリを利用するほうが手軽です。「LightBlue」「nRF Connect for Mobile」といったモバイルアプリが有名です。ここでは、Android版の「nRF Connect for Mobile」を利用しました。アプリを起動すると、アドバタイズしているペリフェラルの一覧が表示されます。設定した、「ESP32 BLE No.1」があるはずです。
CONNECTボタンをタップすると接続します。
接続の画面で、サービスのUUIDが表示されているはずです。そのUUIDをタップします。すると、サービス内のキャラクタリスティックの情報が表示されます。
データを受信するアイコンをタップすると、受信したデータが、16進数と文字列で表示されます。Subscribeのアイコンをタップすると、通知を受け入れて、通知のデータが5秒おきに表示されます。
ブロードキャスト通信
ペリフェラルがアドバタイズするだけのブロードキャスト通信では、もっとシンプルなコードとなります。例えば、ランダムの値を含むアドバタイズ信号を送信するコードは、次のようになります。
public static void Main() { var rnd = new Random(); while (true) { BluetoothLEAdvertisement advertisement = new() { LocalName = "ESP32Adv" }; DataWriter writer = new(); // ランダム値を設定する(1) writer.WriteInt32(rnd.Next()); writer.WriteInt32(rnd.Next()); writer.WriteInt32(rnd.Next()); // 識別子を不明として設定(2) advertisement.ManufacturerData.Add( new BluetoothLEManufacturerData(0xfffe, writer.DetachBuffer())); BluetoothLEAdvertisementPublisher publisher = new(advertisement); publisher.Start(); Thread.Sleep(1000); publisher.Stop(); } }
アドバタイズでの送信パケットのデータサイズは31バイトです。ただし、既定のデータが含まれるため、任意に設定できるのは21バイトになります。アドバタイズデータの識別子は、Bluetooth SIGが企業に発行した識別子で、特定の用途では有効な値を設定する必要がありますが、今回のような用途では、未定義(0xfffe)のままで問題ありません(2)。
実行すると、1秒ごとにアドバタイズ信号を送信します。
アドバタイズ信号には、ランダムのint型(4バイト)の3つの値12バイトが含まれています(1)。「nRF Connect for Mobile」を使うと、データの変化をリアルタイムで画面で確認することができます。
環境センサーの値の送信
最初のセンサーの値を取得する処理と組み合わせれば、BLE通信でデータを送信するプログラムは難しくはありません。例えば、BME680の測定値をJSON文字列にして送信すれば、受信側アプリでのデータ処理も簡単に行えます。
実際のソースコードは、次回に解説することにします。
最後に
環境データをモニタリングするプログラムの解説の前編となる今回は、センサーの計測処理の作成、そしてデータ送信処理としてBLE通信の基本プログラムを作成しました。後編では、環境データをモニタリングするAndroidアプリと、センサーデータをWi-Fi経由でAmbient(IoTデーター可視化サービス)に送信し、グラフ化するところまで解説する予定です。