蓝牙低能耗心率服务器
示例演示如何设置和宣传 GATT 服务。该示例演示了与外设(从属功能)相关的 Qt Bluetooth与外设(从属)功能相关的低能耗类。
蓝牙低能耗心率服务器是一个命令行应用程序,展示了如何使用.NET Framework 开发蓝牙 GATT 服务器。 Qt Bluetooth API.该应用程序包括设置服务、发布服务广告以及通知客户端特征值的变化。
该示例使用了以下 Qt 类:
- QLowEnergyAdvertisingData
- QLowEnergyAdvertisingParameters
- QLowEnergyServiceData
- QLowEnergyCharacteristicData
- QLowEnergyDescriptorData
- QLowEnergyController
- QLowEnergyService
该示例实现了一个服务器应用程序,这意味着它没有图形用户界面。要直观地了解它在做什么,可以使用心率游戏示例,它基本上是该应用程序的客户端对应程序。
检查蓝牙权限
在应用程序创建服务并开始发布广告之前,我们必须检查应用程序是否拥有使用蓝牙的权限。
auto permissionStatus = app.checkPermission(QBluetoothPermission{});
请求蓝牙权限
如果蓝牙授权状态未确定,我们就必须请求使用蓝牙的权限。
if(permissionStatus==Qt::PermissionStatus::Undetermined) { qInfo("Requesting Bluetooth permission ..."); app.requestPermission(QBluetoothPermission{}, [&permissionStatus](constQPermission权限){ qApp->exit(); permissionStatus=permission.status(); });// 现在,等待权限请求解析。app.exec(); }
设置广告数据和参数
有两个类用于配置广告流程:
- QLowEnergyAdvertisingData 指定要广播的信息
- QLowEnergyAdvertisingParameters 用于特定方面,如设置广告间隔或控制允许哪些设备连接。
在我们的示例中,我们只需使用默认参数。
QLowEnergyAdvertisingData 中包含的信息将对当前正在扫描的其他设备可见。它们可以利用这些信息决定是否要建立连接。在我们的示例中,我们包含了我们提供的服务类型、一个能向人类充分描述我们设备的名称以及设备的发射功率级别。后者通常对潜在客户很有用,因为他们可以通过比较接收到的信号强度和宣传的信号强度来判断我们的设备离他们有多远。
注意: 广告数据的空间非常有限(总共只有 31 字节),因此设备名称等长度可变的数据应尽量简短。
QLowEnergyAdvertisingData advertisingData; advertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral); advertisingData.setIncludePowerLevel(true); advertisingData.setLocalName("HeartRateServer"); advertisingData.setServices(QList<QBluetoothUuid>() << QBluetoothUuid::ServiceClassUuid::HeartRate);
设置服务数据
接下来,我们配置要提供的服务类型。我们使用蓝牙规范中定义的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 role 中创建一个QLowEnergyController 对象,并用它从我们的(静态)QLowEnergyServiceData 创建一个(动态)QLowEnergyService 对象。然后,我们调用QLowEnergyController::startAdvertising() 。请注意,我们将QLowEnergyAdvertisingData 提交了两次:第一个参数作为实际的广告数据,第二个参数作为扫描响应数据。它们可以传输不同的信息,但在这里我们并不需要。我们还传递了一个默认构建的QLowEnergyAdvertisingParameters 实例,因为默认的广告参数对我们来说没有问题。如果客户端对广告服务感兴趣,它现在就可以与我们的设备建立连接。此时,设备将停止广告,并发出QLowEnergyController::connected() 信号。
注意: 当客户端断开连接时,广告不会自动恢复。如果希望这样,则需要连接到QLowEnergyController::disconnected() 信号,并在相应的插槽中调用QLowEnergyController::startAdvertising() 。
boolerrorOccurred= false;conststd::unique_ptr<QLowEnergyController>leController(QLowEnergyController::createPeripheral());autoerrorHandler= [&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> 服务(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, ¤tHeartRate, &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);
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.