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、实现界面:











