蓝牙低功耗扫描仪
这是一款用于浏览蓝牙低功耗外围设备内容的应用程序。该示例演示了所有 Qt Bluetooth低能耗类。
蓝牙低功耗扫描仪示例展示了如何使用蓝牙低功耗类开发蓝牙低功耗应用程序。 Qt Bluetooth API.该应用程序包括扫描低能耗设备、扫描其服务以及读取服务特征和描述符。
该示例介绍了以下 Qt 类:
该示例可用于任意蓝牙低功耗外围设备。它创建了所有服务、特性和描述符的快照,并将其呈现给用户。因此,该应用程序提供了一种浏览外围设备所提供内容的简便方法。
运行示例
运行示例 Qt Creator,打开Welcome 模式,然后从Examples 中选择示例。更多信息,请参阅Qt Creator: 教程:构建和运行。
请求使用蓝牙的权限
在某些平台上,需要明确授予使用蓝牙的权限。该示例使用BluetoothPermission
QML 对象检查并在需要时请求权限:
BluetoothPermission { id: permission communicationModes: BluetoothPermission.Access onStatusChanged: { if (permission.status === Qt.PermissionStatus.Denied) Device.update = "Bluetooth permission required" else if (permission.status === Qt.PermissionStatus.Granted) devicesPage.toggleDiscovery() } }
当用户尝试启动设备发现时,会触发权限请求对话框,权限状态为Undetermined
:
onButtonClick: { if (permission.status === Qt.PermissionStatus.Undetermined) permission.request() else if (permission.status === Qt.PermissionStatus.Granted) devicesPage.toggleDiscovery() }
如果用户授予权限,则开始设备发现。否则应用程序无法运行。
扫描设备
第一步是查找所有外围设备。可以使用QBluetoothDeviceDiscoveryAgent 类查找设备。发现过程通过start() 启动。每个新设备都会通过deviceDiscovered() 信号发布广告:
discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this); discoveryAgent->setLowEnergyDiscoveryTimeout(25000); connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &Device::addDevice); connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::errorOccurred, this, &Device::deviceScanError); connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &Device::deviceScanFinished); connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::canceled, this, &Device::deviceScanFinished); discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
发现新设备后,会触发下面的addDevice()
slot。它会过滤所有带有QBluetoothDeviceInfo::LowEnergyCoreConfiguration 标记的设备,并将其添加到显示给用户的列表中。随着发现的设备越来越多,deviceDiscovered() 信号可能会对同一设备发出多次。在此,我们会匹配这些设备发现,以便用户只看到单个设备:
void Device::addDevice(const QBluetoothDeviceInfo &info) { if (info.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) { auto devInfo = new DeviceInfo(info); auto it = std::find_if(devices.begin(), devices.end(), [devInfo](DeviceInfo *dev) { return devInfo->getAddress() == dev->getAddress(); }); if (it == devices.end()) { devices.append(devInfo); } else { auto oldDev = *it; *it = devInfo; delete oldDev; } emit devicesUpdated(); } }
设备列表如下图所示。
注意: 前提条件是远程设备主动公布自己的存在。
连接到服务
用户从列表中选择设备后,应用程序将连接到设备并扫描所有服务。QLowEnergyController 类用于连接设备。QLowEnergyController::connectToDevice() 函数触发连接过程,直到收到QLowEnergyController::connected() 信号或发生错误为止:
if (!controller) { // Connecting signals and slots for connecting to LE services. controller = QLowEnergyController::createCentral(currentDevice.getDevice(), this); connect(controller, &QLowEnergyController::connected, this, &Device::deviceConnected); connect(controller, &QLowEnergyController::errorOccurred, this, &Device::errorReceived); connect(controller, &QLowEnergyController::disconnected, this, &Device::deviceDisconnected); connect(controller, &QLowEnergyController::serviceDiscovered, this, &Device::addLowEnergyService); connect(controller, &QLowEnergyController::discoveryFinished, this, &Device::serviceScanDone); } if (isRandomAddress()) controller->setRemoteAddressType(QLowEnergyController::RandomAddress); else controller->setRemoteAddressType(QLowEnergyController::PublicAddress); controller->connectToDevice();
connected() 信号触发的插槽会立即调用QLowEnergyController::discoverServices() 以开始在所连接的外围设备上发现服务。
controller->discoverServices();
下图显示了选择 SensorTag 设备时的结果。下图显示了选择 SensorTag 设备时的结果。该视图列出了服务名称、主要服务或次要服务以及决定服务类型的 UUID。
一旦选择了服务,就会创建相关的QLowEnergyService 实例,以便与其进行交互:
QLowEnergyService*service = controller->createServiceObject(serviceUuid);if(!service) { qWarning() << "Cannot create service for uuid"; return; }
服务对象提供所需的信号和函数,用于发现服务细节、读写特征和描述符,以及接收数据变更通知。变化通知可能是写入数值的结果,也可能是由内部逻辑触发的设备更新。在初始细节搜索期间,服务的state() 会从RemoteService 过渡到RemoteServiceDiscovering ,并最终以RemoteServiceDiscovered 结束:
connect(service, &QLowEnergyService::stateChanged, this, &Device::serviceDetailsDiscovered); service->discoverDetails(); setUpdate(u"Back\n(Discovering details...)"_s);
读取服务数据
选择一项服务后,服务详细信息就会显示出来。每个特性都会连同其名称、UUID、值、句柄和属性一起列出。
可以通过QLowEnergyService::characteristics() 获取服务特征,反过来,也可以通过QLowEnergyCharacteristic::descriptors() 获取每个描述符。
const QList<QLowEnergyCharacteristic> chars = service->characteristics(); for (const QLowEnergyCharacteristic &ch : chars) { auto cInfo = new CharacteristicInfo(ch); m_characteristics.append(cInfo); }
虽然示例应用程序不显示描述符,但如果根据 UUID 无法辨别单个特性的名称,则可使用描述符获取该特性的名称。获取名称的第二种方法是存在QBluetoothUuid::DescriptorType::CharacteristicUserDescription 类型的描述符。下面的代码演示了如何实现这一点:
QString name = m_characteristic.name(); if (!name.isEmpty()) return name; // find descriptor with CharacteristicUserDescription const QList<QLowEnergyDescriptor> descriptors = m_characteristic.descriptors(); for (const QLowEnergyDescriptor &descriptor : descriptors) { if (descriptor.type() == QBluetoothUuid::DescriptorType::CharacteristicUserDescription) { name = descriptor.value(); break; } }
© 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.