1、前述
Qt支持低功耗蓝牙仅限于Qt5.14以上版本,不支持win7;
需要在工程项目.pro文件中添加:
QT += bluetooth
详细介绍:https://doc.qt.io/qt-5/qtbluetooth-index.html
参考资料:https://doc.qt.io/qt-5/qtbluetooth-le-overview.html
本文源码:Qt5.15.2实现低功耗蓝牙调试助手源码-QT文档类资源-CSDN下载
低功耗蓝牙控制主要有三部分:
1、代理部分,涉及类:QBluetoothDeviceDiscoveryAgent,用于扫描设备;
2、控制器部分:涉及类:QLowEnergyController,用于连接设备、发现服务;
3、服务部分:涉及类:QLowEnergyService,用于连接服务、特征读写、Notify功能打开/关闭等;
2、代理-agent
agent.h头文件:
#ifndef AGENT_H
#define AGENT_H
#include <QObject>
#include <QBluetoothDeviceDiscoveryAgent>
class Agent : public QObject
{
Q_OBJECT
public:
explicit Agent(QObject *parent = nullptr);
void startScanDevice(uint32_t timeOut);
private:
void SendMessage(QString);
private slots:
void onDeviceDiscovered(const QBluetoothDeviceInfo &info);
void onError(QBluetoothDeviceDiscoveryAgent::Error err);
void onFinished(void);
void onCanceled(void);
signals:
void deviceDiscovered(const QBluetoothDeviceInfo &info);
void message(QString msg);
private:
QBluetoothDeviceDiscoveryAgent *m_agent;
};
#endif // AGENT_H
agent.cpp源码文件:
#include "agent.h"
Agent::Agent(QObject *parent) : QObject(parent)
{
m_agent = new QBluetoothDeviceDiscoveryAgent(this);
if(m_agent)
{
connect(m_agent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)), this, SLOT(onDeviceDiscovered(QBluetoothDeviceInfo)));
connect(m_agent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)), this, SLOT(onError(QBluetoothDeviceDiscoveryAgent::Error)));
connect(m_agent, SIGNAL(finished()), this, SLOT(onFinished()));
connect(m_agent, SIGNAL(canceled()), this, SLOT(onCanceled()));
}
}
void Agent::startScanDevice(uint32_t timeOut)
{
if(m_agent)
{
m_agent->setLowEnergyDiscoveryTimeout(timeOut);
m_agent->start();
if(m_agent->isActive())
{
SendMessage("scanning...");
}
}
}
void Agent::SendMessage(QString msg)
{
emit message(msg);
}
void Agent::onDeviceDiscovered(const QBluetoothDeviceInfo &info)
{
emit deviceDiscovered(info);
QString tmp = "发现设备:";
QString str = info.address().toString() + " - " + info.name();
SendMessage(tmp + str);
}
void Agent::onError(QBluetoothDeviceDiscoveryAgent::Error err)
{
QString str;
str = QString("Agent Error(%1):").arg(err);
str += m_agent->errorString();
SendMessage(str);
}
void Agent::onFinished()
{
SendMessage("Agent scan finished");
}
void Agent::onCanceled()
{
SendMessage("Agent scan canceled");
}
3、控制器-controller
controller.h头文件:
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <QObject>
#include <QLowEnergyController>
#include <QBluetoothDeviceInfo>
class Controller : public QObject
{
Q_OBJECT
public:
explicit Controller(QObject *parent = nullptr);
void ConnectDevice(QBluetoothDeviceInfo info);
void DisconnectDevice(void);
QLowEnergyService *CreateService(QBluetoothUuid);
private:
void SendMessage(QString);
private slots:
void onConnected();
void onDisconnected();
void onStateChanged(QLowEnergyController::ControllerState state);
void onError(QLowEnergyController::Error newError);
void onServiceDiscovered(QBluetoothUuid);
void onDiscoveryFinished();
void onConnectionUpdated(const QLowEnergyConnectionParameters ¶meters);
signals:
void message(QString msg);
void serviceDiscovered(const QBluetoothUuid &newService);
private:
QLowEnergyController *m_controller;
};
#endif // CONTROLLER_H
controller.cpp源码文件:
#include "controller.h"
Controller::Controller(QObject *parent) : QObject(parent)
{
m_controller = NULL;
}
void Controller::ConnectDevice(QBluetoothDeviceInfo info)
{
if(m_controller)
{
m_controller->disconnectFromDevice();
delete m_controller;
m_controller = NULL;
}
m_controller = QLowEnergyController::createCentral(info);
connect(m_controller, SIGNAL(connected()), this, SLOT(onConnected()));
connect(m_controller, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
connect(m_controller, SIGNAL(stateChanged(QLowEnergyController::ControllerState)), this, SLOT(onStateChanged(QLowEnergyController::ControllerState)));
connect(m_controller, SIGNAL(error(QLowEnergyController::Error)), this, SLOT(onError(QLowEnergyController::Error)));
connect(m_controller, SIGNAL(serviceDiscovered(QBluetoothUuid)), this, SLOT(onServiceDiscovered(QBluetoothUuid)));
connect(m_controller, SIGNAL(discoveryFinished()), this, SLOT(onDiscoveryFinished()));
connect(m_controller, SIGNAL(connectionUpdated(QLowEnergyConnectionParameters)), this, SLOT(onConnectionUpdated(QLowEnergyConnectionParameters)));
m_controller->connectToDevice();
}
void Controller::DisconnectDevice()
{
if(m_controller)
{
m_controller->disconnectFromDevice();
}
}
QLowEnergyService * Controller::CreateService(QBluetoothUuid serviceUUID)
{
if(m_controller)
{
return m_controller->createServiceObject(serviceUUID);
}
else
{
return NULL;
}
}
void Controller::SendMessage(QString str)
{
emit message(str);
}
void Controller::onConnected()
{
if(m_controller)
{
m_controller->discoverServices();
SendMessage("device connected");
}
}
void Controller::onDisconnected()
{
SendMessage("device disconnected");
}
void Controller::onStateChanged(QLowEnergyController::ControllerState state)
{
const QString stateString[] = {
"UnconnectedState",
"ConnectingState",
"ConnectedStatez",
"DiscoveringState",
"DiscoveredState",
"ClosingState",
"AdvertisingState",
};
if(state < stateString->size())
{
SendMessage(stateString[state]);
}
}
void Controller::onError(QLowEnergyController::Error newError)
{
if(m_controller)
{
QString str;
str = QString("Controller Error(%1):").arg(newError);
str += m_controller->errorString();
SendMessage(str);
}
}
void Controller::onServiceDiscovered(QBluetoothUuid serviceUUID)
{
emit serviceDiscovered(serviceUUID);
}
void Controller::onDiscoveryFinished()
{
SendMessage("service discovery finished");
}
void Controller::onConnectionUpdated(const QLowEnergyConnectionParameters ¶meters)
{
SendMessage("controller connect updated");
}
4、服务-service
service.h头文件:
#ifndef SERVICE_H
#define SERVICE_H
#include <QObject>
#include <QLowEnergyService>
class Service : public QObject
{
Q_OBJECT
public:
explicit Service(QObject *parent = nullptr);
void ConnectService(QLowEnergyService *);
void SendMessage(QString);
void OpenNotify(QLowEnergyCharacteristic ch, bool flag);
void ReadCharacteristic(QLowEnergyCharacteristic ch);
void WriteCharacteristic(QLowEnergyCharacteristic ch, QByteArray arr);
private slots:
void onStateChanged(QLowEnergyService::ServiceState newState);
void onCharacteristicChanged(const QLowEnergyCharacteristic &info,
const QByteArray &value);
void onCharacteristicRead(const QLowEnergyCharacteristic &info,
const QByteArray &value);
void onCharacteristicWritten(const QLowEnergyCharacteristic &info,
const QByteArray &value);
void onDescriptorRead(const QLowEnergyDescriptor &info,
const QByteArray &value);
void onDescriptorWritten(const QLowEnergyDescriptor &info,
const QByteArray &value);
void onError(QLowEnergyService::ServiceError error);
signals:
void discoveryCharacteristic(QLowEnergyCharacteristic);
void message(QString);
private:
QLowEnergyService * m_service;
};
#endif // SERVICE_H
service.cpp源码文件:
#include "service.h"
Service::Service(QObject *parent) : QObject(parent)
{
m_service = NULL;
}
void Service::ConnectService(QLowEnergyService * service)
{
m_service = service;
if(m_service)
{
if(m_service->state() == QLowEnergyService::ServiceDiscovered)
{
onStateChanged(QLowEnergyService::ServiceDiscovered);
}
else
{
connect(m_service, SIGNAL(stateChanged(QLowEnergyService::ServiceState)), this, SLOT(onStateChanged(QLowEnergyService::ServiceState)));
connect(m_service, SIGNAL(characteristicChanged(QLowEnergyCharacteristic, QByteArray)), this, SLOT(onCharacteristicChanged(QLowEnergyCharacteristic, QByteArray)));
connect(m_service, SIGNAL(characteristicRead(QLowEnergyCharacteristic, QByteArray)), this, SLOT(onCharacteristicRead(QLowEnergyCharacteristic, QByteArray)));
connect(m_service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic, QByteArray)), this, SLOT(onCharacteristicWritten(QLowEnergyCharacteristic, QByteArray)));
connect(m_service, SIGNAL(descriptorRead(QLowEnergyCharacteristic, QByteArray)), this, SLOT(onDescriptorRead(QLowEnergyCharacteristic, QByteArray)));
connect(m_service, SIGNAL(descriptorWritten(QLowEnergyCharacteristic, QByteArray)), this, SLOT(onDescriptorWritten(QLowEnergyCharacteristic, QByteArray)));
connect(m_service, SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(onError(QLowEnergyService::ServiceError)));
m_service->discoverDetails();
}
}
}
void Service::SendMessage(QString msg)
{
emit message(msg);
}
void Service::OpenNotify(QLowEnergyCharacteristic ch, bool flag)
{
if(m_service)
{
if(ch.isValid())
{
if(ch.properties() & QLowEnergyCharacteristic::Notify)
{
QLowEnergyDescriptor d = ch.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
if(d.isValid())
{
if(true == flag)
{
m_service->writeDescriptor(d, QByteArray::fromHex("0100"));
}
else
{
m_service->writeDescriptor(d, QByteArray::fromHex("0000"));
}
}
}
}
}
}
void Service::ReadCharacteristic(QLowEnergyCharacteristic ch)
{
if(m_service)
{
if(ch.isValid())
{
if(ch.properties() & QLowEnergyCharacteristic::Read)
{
m_service->readCharacteristic(ch);
}
}
}
}
void Service::WriteCharacteristic(QLowEnergyCharacteristic ch, QByteArray arr)
{
if(m_service)
{
if(ch.isValid())
{
if(ch.properties() & QLowEnergyCharacteristic::Write)
{
m_service->writeCharacteristic(ch, arr, QLowEnergyService::WriteWithResponse);
}
else if(ch.properties() & QLowEnergyCharacteristic::WriteNoResponse)
{
m_service->writeCharacteristic(ch, arr, QLowEnergyService::WriteWithoutResponse);
}
else if(ch.properties() & QLowEnergyCharacteristic::WriteSigned)
{
m_service->writeCharacteristic(ch, arr, QLowEnergyService::WriteSigned);
}
}
}
}
void Service::onStateChanged(QLowEnergyService::ServiceState newState)
{
if(m_service)
{
switch(newState)
{
case QLowEnergyService::DiscoveringServices:
{
SendMessage("Discovering services...");
}
break;
case QLowEnergyService::DiscoveryRequired:
{
SendMessage("require discover services...");
}
break;
case QLowEnergyService::ServiceDiscovered:
{
SendMessage("Discovered services");
QList<QLowEnergyCharacteristic> characteristics = m_service->characteristics();
foreach(QLowEnergyCharacteristic ch, characteristics)
{
emit discoveryCharacteristic(ch);
}
}
break;
default:
break;
}
}
}
void Service::onCharacteristicChanged(const QLowEnergyCharacteristic &info, const QByteArray &value)
{
QString ch = info.uuid().toString() + " - Characteristic Changed:" + QString(value);
SendMessage(ch);
}
void Service::onCharacteristicRead(const QLowEnergyCharacteristic &info, const QByteArray &value)
{
QString ch = info.uuid().toString() + " - Characteristic read:" + QString(value);
SendMessage(ch);
}
void Service::onCharacteristicWritten(const QLowEnergyCharacteristic &info, const QByteArray &value)
{
QString ch = info.uuid().toString() + " - Characteristic written:" + QString(value);
SendMessage(ch);
}
void Service::onDescriptorRead(const QLowEnergyDescriptor &info, const QByteArray &value)
{
QString ch = info.uuid().toString() + " - descriptor read:" + QString(value);
SendMessage(ch);
}
void Service::onDescriptorWritten(const QLowEnergyDescriptor &info, const QByteArray &value)
{
QString ch = info.uuid().toString() + " - descriptor written:" + QString(value);
SendMessage(ch);
}
void Service::onError(QLowEnergyService::ServiceError error)
{
const QString ServiceError[] {
"NoError",
"OperationError",
"CharacteristicWriteError",
"DescriptorWriteError",
"UnknownError",
"CharacteristicReadError",
"DescriptorReadError"
};
if(error < ServiceError->size())
{
QString str;
str = QString("service Error(%1):").arg(error);
str += ServiceError[error];
SendMessage(str);
}
}
5、实现界面: