ESP32のアプリケーション(2)
Bluetooth Low Energy(BLE)でブロードキャスト通信
BLEのブロードキャスト通信とは、ペリフェラル(データを送信するデバイス)が不特定多数に一方的に送信するものです。これは、デバイスがいわゆる接続待ちの状態になっていることを伝える信号です。
この仕組みのことを「アドバタイズ」と呼びます。アドバタイズ信号を受けて、セントラル(データを受信する側)が周囲のデバイスを認識できます。
今回は1対1の通信ではなく、このアドバタイズを利用して、センサーの測定値を送信するようにしました。アドバタイズであれば、複数の環境からデータを確認できます。
アドバタイズの設定
.NET nanoFrameworkで、BLEのアドバタイズを行うには、BluetoothLEAdvertisementPublisherクラスを利用します。アドバタイズの設定を行うInitializeAdvertiserメソッドは、次のようになります。
// アドバタイズ信号を送信するパブリッシャーオブジェクト
private static BluetoothLEAdvertisementPublisher _publisher;
public class Program
{
private static void InitializeAdvertiser()
{
// アドバタイズ信号のペイロードの設定(1)
BluetoothLEAdvertisement advertisement = new()
{
LocalName = "BME680"
};
// パブリッシャーオブジェクトの作成(2)
_publisher = new(advertisement);
// アドバタイズの開始(3)
_publisher.Start();
}
~中略~
}
まず、アドバタイズ信号のペイロード部分(制御情報を除いたデータ本体)は、BluetoothLEAdvertisementオブジェクトを利用して設定します(1)。ここでは、LocalNameプロパティを設定しています。
Local Nameはデバイスの名称となるもので、今回はこの名称を利用してデバイスを判別します。この段階では、Local Name以外は何も設定せずに、パブリッシャーオブジェクトを作成して(2)、アドバタイズを開始します(3)。
センサーデータを送信する
ReadSensorDataデリゲートから呼び出される、センサーの測定値を送信するSendSensorDataメソッドは、次のようになります。
このメソッドのなかで、アドバタイズ信号のペイロードを更新しています。
private static void SendSensorData(double temp, double humidity, double pressure, double gas)
{
// データをJSON形式に変換(1)
var jsonData =
$"{{\"d\":[{temp:F1},{humidity:F1},{pressure:F0},{gas:F0}]}}";
// 既存のManufacturerDataを更新(2)
DataWriter writer = new();
writer.WriteString(jsonData);
_publisher.Advertisement.ManufacturerData.Clear();
_publisher.Advertisement.ManufacturerData.Add(
new BluetoothLEManufacturerData(0xfffe, writer.DetachBuffer()
));
// アドバタイズをいったん停止して再開する(3)
_publisher.Stop();
_publisher.Start();
}
SendSensorDataメソッドでは、BME680の測定値それぞれが引数として設定されています。最初にこの測定値をJSON文字列に変換します。C#では、オブジェクトをJSONに変換するには、System.Text.Json名前空間のクラスを利用するのが一般的です。
ただここでは、JSON文字列をできる限り短くするために、文字列補間を利用して、直接次のJSON文字列を作成しています。
{"d": [27.9, 45.8,1010,250]}
このJSON文字列は、dという文字をキーとした数値(観測値)の配列データを意味するものです。
JSON文字列を短くする理由は、アドバタイズでの送信パケットのデータサイズに制限があるからです。アドバタイズ信号の全体のペイロードは最大31バイトであり、そのなかで、任意に設定できる領域であるManufacturer Specific Dataも収まるようにしなければなりません。
Manufacturer Specific Data(コードでは、ManufacturerDataプロパティ)は、先頭の2バイトに企業識別子と呼ばれる部分があり、その後が任意に設定できるデータ領域です。ここでは、BluetoothLEManufacturerDataオブジェクトを利用して、企業識別子の0xfffeと、JSON文字列を設定しています(2)。
なお、BluetoothLEManufacturerDataでは、送信データをBufferオブジェクトで指定する必要があるため、DataWriterクラスを利用しています。
ManufacturerDataの更新後、アドバタイズをいったん停止して再開します(3)。
JSON文字列以外の方法
JSON文字列では、可読性はよいものの、長くて可変長のデータとなります。限られた領域に納めるには、測定値をそのままバイナリで格納するほうがよい場合もあります。
C#では、float型は4バイト長なので、4つの測定値であれば16バイトで済みます。精度もfloatで十分でしょう。
測定値をflot型の値として格納する場合は、DataWriter.WriteStringの代わりに、WriteSingleメソッドを用います。
// 測定値をflot型の値で格納する writer.WriteSingle((float)temp); writer.WriteSingle((float)humidity); writer.WriteSingle((float)pressure); writer.WriteSingle((float)gas);
各観測値を、float型の4バイトで送信できます。なお、バイト配列からfloat型に変換するには、BitConverter.ToSingleメソッドを用います。
動作確認
今回のアプリのMainメソッドは、次のようになります。
public static void Main()
{
InitializeAdvertiser(); // アドバタイズ設定
InitializeBme680Sensor(); // センサー設定
Thread.Sleep(Timeout.Infinite);
}
動作の確認は、Android版の「LightBlue」アプリを利用しました。BME680という名前で、アドバタイズ信号が確認できます。Manufacturer Specific Dataデータには、JSON文字列が文字コードの16進数で表示されています。
