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データー可視化サービス)に送信し、グラフ化するところまで解説する予定です。
