QBluetoothDeviceDiscoveryAgent类发现附近的蓝牙设备:

  • 创建一个QBluetoothDeviceDiscoveryAgent实体
  • connect信号deviceDiscovered()或finished()
  • 调用start()
1
2
3
4
5
6
7
8
9
10
11
void MyClass::startDeviceDiscovery()
{
QBluetoothDeviceDiscoveryAgent * discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
connect(discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)), this, SLOT(deviceDiscovered(QBluetoothDeviceInfo)));
discoveryAgent->start();
}

void MyClass::deviceDiscovered(const QBluetoothDeviceInfo &device)
{
qDebug()<<"Found new device:"<<device.name()<<'('<<device.address().toString()<<')';
}

要异步检索结果,则connect信号deviceDiscovered()。要获取发现设备的列表,在finished信号后调用discoveredDevices()。

该类能发现经典和低功耗蓝牙设备。单个设备类型可以通过QBluetoothDeviceInfo::coreConfigurations () 属性确定。在大多数情况下,由foundDevices () 返回的列表包含两种类型的设备。然而,并非每个平台都能检测到这两种类型的设备。在具有此限制的平台上(例如 iOS 仅支持低能耗发现),发现程序会将搜索限制为支持的类型。

其它示例:

第一步,扫描设备,发现所有外设。使用QBluetoothDeviceDiscoveryAgent类发现设备,使用start()函数开始,每个新设备通过deviceDiscovered()信号发现。

1
2
3
4
5
6
7
8
discoveryAgent = new QBluetoothDeviceDiscoveryAgent();
discoveryAgent->setLowEnergyDiscoveryTimeout(5000);
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
this, &Device::addDevice);
connect(discoveryAgent, QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(&QBluetoothDeviceDiscoveryAgent::error),
this, &Device::deviceScanError);
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &Device::deviceScanFinished);
discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);

addDevice()槽函数作为发现新设备的相应被触发,它过滤所有被发现的有QBluetoothDeviceInfo::LowEnergyCoreConfiguration标记的设备,并将它们加入列表展示给用户。

1
2
3
4
5
void Device::addDevice(const QBluetoothDeviceInfo &info)
{
if(info.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration)
setUpdate("Last device added: " + info.name());
}

注意:从 Android 6.0 开始,检测设备的能力需要 ACCESS_COARSE_LOCATION。

注意:由于 API 限制,只能在 Windows 上查找已使用 Windows 设置配对的设备。

注意: Win32 后端目前不支持接收信号强度指示器 (RSSI),以及制造商特定数据,或蓝牙 LE 设备在发现后公布的其他数据更新。

==经测,在win10下Qt 5.15版本,使用MinGW编译的软件搜索蓝牙只能搜到曾连过保存的蓝牙,使用MSVC2019 64bit则正常==

QBluetoothDeviceInfo类用来保存蓝牙设备的名称、地址和设备类

QBluetoothLocalDevice类提供获取和设置本地蓝牙设备支持

QLowEnergyController类提供访问低功耗蓝牙的功能

QLowEnergyController类充当低功耗蓝牙开发的入口。

低功耗蓝牙设备包含两种类型:外设型和中央型。每种支持不同的功能。外设型设备提供中央型设备所需的数据。例如湿度传感器检测冬景花园的水分湿度。诸如手机之类的设备可能会读取传感器的值,并将同一环境中更大背景下的所有传感器值显示给用户。在这种情况下,传感器是外围设备,手机充当中央设备。

createCentral()工厂方法创建中央型控制器。这样的对象本质上充当远程低能耗外围设备的占位符,支持服务发现和状态跟踪等功能。

在中心角色创建控制器对象后,第一步是通过connectToDevice ()建立连接。建立连接后,控制器的state () 将更改为QLowEnergyController::ConnectedState并发出connected () 信号。值得一提的是,某些平台(例如基于BlueZ的 Linux)无法将QLowEnergyController的两个连接实例维护到同一个远程设备。在这种情况下,第二次调用connectToDevice () 可能会失败。这种限制可能会在未来的某个阶段消失。disconnectFromDevice _() 函数用于断开现有连接。

建立连接后的第二步是发现远程外围设备提供的服务。这个过程通过discoverServices () 启动,并在discoveryFinished () 信号发出后完成。发现的服务可以通过services () 进行枚举。

最后一步是创建服务对象。createServiceObject () 函数充当每个服务对象的工厂,并期望服务 UUID 作为参数。调用上下文应该拥有返回的QLowEnergyService实例的所有权。

一旦控制器与远程低功耗蓝牙设备断开连接,以后从此控制器的连接创建的任何QLowEnergyService、QLowEnergyCharacteristic或QLowEnergyDescriptor实例都将变为无效。

外围角色的控制器是通过createPeripheral () 工厂方法创建的。这样的对象本身充当外围设备,支持广播服务等功能,并允许客户收到有关特征值更改的通知。

在外围角色中创建控制器对象后,第一步是填充通过调用addService () 提供给客户端设备的 GATT 服务集。之后,调用startAdvertising () 让设备广播一些数据,并且根据正在执行的广播类型,还监听来自 GATT 客户端的传入连接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//QBluetoothDeviceInfo remoteDevice;
//remoteDevice为扫描到的将要连接的设备
QLowEnergyController *m_control = new QLowEnergyController(remoteDevice, this);

connect(m_control, SIGNAL(serviceDiscovered(QBluetoothUuid)), this, SLOT(BlueServiceDiscovered(QBluetoothUuid)));

//正在运行的服务发现完成时发出此信号。
connect(m_control, SIGNAL(discoveryFinished()), this, SLOT(BlueServiceScanDone()));
//当控制器成功连接到远程Low Energy设备时,会发出此信号。
connect(m_control, SIGNAL(connected()), this, SLOT(BlueDeviceConnected()));
//当控制器从远程低功耗设备断开时发出此信号。
connect(m_control, SIGNAL(disconnected()), this, SLOT(BlueDeviceDisconnected()));
connect(m_control, static_cast<void(QLowEnergyController::(QLowEnergyController::Error)>(&QLowEnergyController::error),[=](QLowEnergyController::Error error) {
if (error == QLowEnergyController::NoError)
{
ui.plainTextEdit->setText(QSL("没有发生错误"));
}
else if (error == QLowEnergyController::UnknownError)
{
ui.plainTextEdit->setText(QSL("出现未知错误"));
}
else if (error == QLowEnergyController::UnknownRemoteDeviceError)
{
ui.plainTextEdit->setText(QSL("无法找到传递给此类构造函数的远程Bluetooth Low Energy设备"));
}
else if (error == QLowEnergyController::NetworkError)
{
ui.plainTextEdit->setText(QSL("尝试读取或写入远程设备失败"));
}
else if (error == QLowEnergyController::InvalidBluetoothAdapterError)
{
ui.plainTextEdit->setText(QSL("传递给此类构造函数的本地蓝牙设备无法找到,或者没有本地蓝牙设备"));
}
else if (error == QLowEnergyController::InvalidBluetoothAdapterError)
{
ui.plainTextEdit->setText(QSL("尝试连接到远程设备失败"));
}
//else
// ui.plainTextEdit->setText(QSL("*****未知错误!******\n"));
});

//连接到远程蓝牙低功耗设备。
m_control->connectToDevice();

connected()信号触发的槽函数(以上是BlueDeviceConnected())立即调用QLowEnergyController::discoverServices()来开始发现连接的设备的服务。

1
2
3
4
void BlueDeviceConnected()
{
m_control->discoverServices();
}

当服务被选择后,相关的QLowEnergyService实例被创建来允许与其交互:

1
2
3
4
5
QLowEnergyService *service = m_control->createServiceObject(serviceUuid);
if(!service){
qWarning()<<"Cannot create service for uuid";
return;
}

服务对象提供所需的信号和函数来发现服务细节,读写特征值和描述符,并且接收数据更改通知。更新通知将被捕获,通过写值或由设备上的内部逻辑的更新可能触发。在最初的详细信息搜索中,服务的state()从DiscoveryRequired到DiscoveringServices,并最终以ServiceDiscovered结束。

1
2
3
connect(service, &QLowEnergyService::stateChanged, this, &Device::serviceDetailsDiscovered);
service->discoverDetails();
setUpdate("Back\n(Discovering details...)");

通过QLowEnergyService::characteristics()检索服务的特征值,并且通过QLowEnergyCharacteristic::descriptors()获取每个描述符。

1
2
3
4
5
const QList<QLowEnergyCharacteristic>chars = service->characteristics();
for(const QLowEnergyCharacteristic &ch : chars){
auto cInfo = new CharacteristicInfo(ch);
m_characterisitics.append(cInfo);
}