Bluetooth低エネルギー心拍数サーバー

GATT サービスのセットアップとアドバタイズ方法を示すサンプルです。この例では、ペリフェラル(スレーブ)機能に関連するQt BluetoothLow Energy クラスの使用方法を示しています。

Bluetooth Low Energy Heart Rate Server は、Qt Bluetooth API を使用して Bluetooth GATT サーバーを開発する方法を示すコマンドラインアプリケーションです。 このアプリケーションでは、サービスのセットアップ、広告、特性値の変更をクライアントに通知する方法について説明します。

この例では、以下の Qt クラスを使用しています:

つまり、グラフィカル・ユーザー・インターフェイスはありません。この例ではサーバーアプリケーションを実装しているため、グラフィカルなユーザーインターフェースはありません。このアプリケーションの動作を視覚化するには、Heart Rate Gameの例を使用します。

Bluetooth許可のチェック

アプリケーションがサービスを作成し、広告を開始する前に、アプリケーションがBluetoothの使用許可を持っているかどうかをチェックする必要があります。

auto permissionStatus = app.checkPermission(QBluetoothPermission{});

Bluetooth許可リクエスト

Bluetoothの許可ステータスが未確定の場合、Bluetoothの使用許可をリクエストする必要があります。

if (permissionStatus == Qt::PermissionStatus::Undetermined) {
    qInfo("Requesting Bluetooth permission ...");
    app.requestPermission(QBluetoothPermission{}, [&permissionStatus](const QPermission &permission){
        qApp->exit();
        permissionStatus = permission.status();
    });
    // Now, wait for permission request to resolve.
    app.exec();
}

広告データとパラメータの設定

アドバタイジングプロセスの設定には2つのクラスを使用します:

この例では、デフォルトのパラメータを使用する。

QLowEnergyAdvertisingData に含まれる情報は、現在スキャン中の他のデバイスにも見える。この情報を使って、接続を確立するかどうかを決めることができます。この例では、当社が提供するサービスのタイプ、当社のデバイスを人間に適切に説明する名前、およびデバイスの送信パワー・レベルを含めています。後者は、潜在的な顧客にとって有用であることが多い。なぜなら、顧客は、受信した信号強度と広告された信号強度を比較することで、当社のデバイスがどの程度離れているかを知ることができるからである。

注: 広告データのスペースは非常に限られているので(合計31バイトのみ)、デバイス名のような可変長のデータはできるだけ短くする必要があります。

QLowEnergyAdvertisingData advertisingData;
advertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral);
advertisingData.setIncludePowerLevel(true);
advertisingData.setLocalName("HeartRateServer");
advertisingData.setServices(QList<QBluetoothUuid>() << QBluetoothUuid::ServiceClassUuid::HeartRate);

サービスデータの設定

次に、提供したいサービスの種類を設定する。ここでは、Bluetooth仕様で定義されているHeart Rate サービスを最小限の形、つまりHeart Rate Measurement 特性のみで構成される形で使用します。この特性は、Notify プロパティをサポートする必要があり(その他はサポートしない)、Client Characteristic Configuration 記述子を持つ必要があります。この記述子は、クライアントが特性値の変更について通知を受けるために登録することを可能にします。心拍数の初期値は、いずれにせよ読み取ることができないため、ゼロに設定する(クライアントが値を取得できる唯一の方法は、通知を介することである)。

QLowEnergyCharacteristicData charData;
charData.setUuid(QBluetoothUuid::CharacteristicType::HeartRateMeasurement);
charData.setValue(QByteArray(2, 0));
charData.setProperties(QLowEnergyCharacteristic::Notify);
const QLowEnergyDescriptorData clientConfig(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration,
                                            QByteArray(2, 0));
charData.addDescriptor(clientConfig);

QLowEnergyServiceData serviceData;
serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
serviceData.setUuid(QBluetoothUuid::ServiceClassUuid::HeartRate);
serviceData.addCharacteristic(charData);

広告と着信接続のリスニング

これですべてのデータがセットアップされたので、広告を開始できる。まず、peripheral roleQLowEnergyController オブジェクトを作成し、それを使って(静的な)QLowEnergyServiceData から(動的な)QLowEnergyService オブジェクトを作成する。そして、QLowEnergyController::startAdvertising ()を呼び出す。QLowEnergyAdvertisingData 最初の引数は実際の広告データとして機能し、2番目の引数はスキャン応答データとして機能する。最初の引数は実際の広告データとして機能し、2番目の引数はスキャン・レスポンスのデータとして機能する。これらは異なる情報を転送することもできるが、ここではその必要はない。また、QLowEnergyAdvertisingParameters のデフォルトで構築されたインスタンスも渡す。なぜなら、デフォルトの広告パラメータでよいからである。クライアントが広告されたサービスに興味を持 つと、デバイスへの接続を確立することができる。接続が確立されると、デバイスは広告を停止し、QLowEnergyController::connected()シグナルが発信される。

注意: クライアントが切断すると、広告は自動的に再開されない。そのようにしたい場合は、QLowEnergyController::disconnected ()シグナルに接続し、それぞれのスロットでQLowEnergyController::startAdvertising ()を呼び出す必要があります。

bool errorOccurred = false;
const std::unique_ptr<QLowEnergyController> leController(QLowEnergyController::createPeripheral());
auto errorHandler = [&leController, &errorOccurred](QLowEnergyController::Error errorCode) {
        qWarning().noquote().nospace() << errorCode << " occurred: "
            << leController->errorString();
        if (errorCode != QLowEnergyController::RemoteHostClosedError) {
            qWarning("Heartrate-server quitting due to the error.");
            errorOccurred = true;
            QCoreApplication::quit();
        }
};
QObject::connect(leController.get(), &QLowEnergyController::errorOccurred, errorHandler);

std::unique_ptr<QLowEnergyService> service(leController->addService(serviceData));
leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData,
                               advertisingData);
if (errorOccurred)
    return -1;

心拍数の提供

ここまではいい。しかし、クライアントはどうやって実際に心拍数を取得するのでしょうか?これは、上のコードスニペットでQLowEnergyController から受け取ったQLowEnergyService オブジェクトの各特性の値を定期的に更新することで実現します。通常、心拍数のソースは何らかのセンサーになるはずだが、この例では60から100の間で振動する値を作るだけだ。以下のコード・スニペットで最も重要なのは、QLowEnergyService::writeCharacteristic への呼び出しです。現在クライアントが接続しており、前述のClient Characteristic Configuration に書き込むことで通知を有効にしている場合、新しい値について通知が届きます。

QTimer heartbeatTimer;
quint8 currentHeartRate = 60;
enum ValueChange { ValueUp, ValueDown } valueChange = ValueUp;
const auto heartbeatProvider = [&service, &currentHeartRate, &valueChange]() {
    QByteArray value;
    value.append(char(0)); // Flags that specify the format of the value.
    value.append(char(currentHeartRate)); // Actual value.
    QLowEnergyCharacteristic characteristic
            = service->characteristic(QBluetoothUuid::CharacteristicType::HeartRateMeasurement);
    Q_ASSERT(characteristic.isValid());
    service->writeCharacteristic(characteristic, value); // Potentially causes notification.
    if (currentHeartRate == 60)
        valueChange = ValueUp;
    else if (currentHeartRate == 100)
        valueChange = ValueDown;
    if (valueChange == ValueUp)
        ++currentHeartRate;
    else
        --currentHeartRate;
};
QObject::connect(&heartbeatTimer, &QTimer::timeout, heartbeatProvider);
heartbeatTimer.start(1000);

プロジェクト例 @ code.qt.io

©2024 The Qt Company Ltd. 本書に含まれる文書の著作権は、それぞれの所有者に帰属します。 ここで提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。