Auf dieser Seite

Bluetooth Low Energy-Scanner

Eine Anwendung zum Durchsuchen der Inhalte von Bluetooth-Low-Energy-Peripheriegeräten. Das Beispiel veranschaulicht die Verwendung aller Qt Bluetooth Low-Energy-Klassen.

Das Beispiel „Bluetooth Low Energy Scanner“ zeigt, wie man Bluetooth Low Energy-Anwendungen mithilfe der Qt Bluetooth API. Die Anwendung umfasst das Scannen nach Low-Energy-Geräten, das Abfragen ihrer Dienste sowie das Auslesen der Dienstmerkmale und -deskriptoren.

Mit dem Qt-BLE-Scanner gefundene GATT-Dienste

Das Beispiel stellt die folgenden Qt-Klassen vor:

Das Beispiel kann mit jedem beliebigen Bluetooth-Low-Energy-Peripheriegerät verwendet werden. Es erstellt eine Momentaufnahme aller Dienste, Merkmale und Deskriptoren und stellt diese dem Benutzer dar. Somit bietet die Anwendung eine einfache Möglichkeit, die von einem Peripheriegerät angebotenen Inhalte zu durchsuchen.

Ausführen des Beispiels

Sie können das Beispiel ausführen unter:

Einholen der Berechtigung zur Nutzung von Bluetooth

Auf bestimmten Plattformen müssen Berechtigungen für die Nutzung von Bluetooth ausdrücklich erteilt werden. Das Beispiel verwendet das QML-Objekt „ BluetoothPermission “, um die Berechtigungen zu prüfen und gegebenenfalls anzufordern:

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()
    }
}

Der Dialog zur Berechtigungsanforderung wird ausgelöst, wenn der Benutzer versucht, die Gerätesuche zu starten, und der Berechtigungsstatus lautet „ Undetermined “:

onButtonClick: {
    if (permission.status === Qt.PermissionStatus.Undetermined)
        permission.request()
    else if (permission.status === Qt.PermissionStatus.Granted)
        devicesPage.toggleDiscovery()
}

Die Geräteerkennung startet, wenn der Benutzer die Berechtigung erteilt. Andernfalls ist die Anwendung nicht funktionsfähig.

Nach Geräten suchen

Der erste Schritt besteht darin, alle Peripheriegeräte zu finden. Die Geräte können mithilfe der Klasse „ QBluetoothDeviceDiscoveryAgent “ ermittelt werden. Der Erkennungsprozess wird mit der Methode „ start()“ gestartet. Jedes neue Gerät wird über das Signal „ deviceDiscovered()“ gemeldet:

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);

Der unten stehende Slot „ addDevice() “ wird als Reaktion auf die Erkennung eines neuen Geräts ausgelöst. Er filtert alle gefundenen Geräte heraus, die das Flag „ QBluetoothDeviceInfo::LowEnergyCoreConfiguration “ tragen, und fügt sie einer Liste hinzu, die dem Benutzer angezeigt wird. Das Signal „ deviceDiscovered()“ kann für dasselbe Gerät mehrfach ausgegeben werden, sobald weitere Details erkannt werden. Hier ordnen wir diese Geräteerkennungen ein, sodass der Benutzer nur die einzelnen Geräte sieht:

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();
    }
}

Die Liste der Geräte könnte wie in der Abbildung unten aussehen.

Hinweis: Voraussetzungist , dass die Remote-Geräte ihre Präsenz aktiv bekanntgeben.

Im Qt-BLE-Scanner aufgelistete Geräte in der Nähe

Verbindung zu Diensten herstellen

Nachdem der Benutzer ein Gerät aus der Liste ausgewählt hat, stellt die Anwendung eine Verbindung zu dem Gerät her und scannt alle Dienste. Zur Herstellung der Verbindung zum Gerät wird die Klasse „ QLowEnergyController “ verwendet. Die Funktion „ QLowEnergyController::connectToDevice()“ löst den Verbindungsprozess aus, der so lange andauert, bis das Signal „ QLowEnergyController::connected()“ empfangen wird oder ein Fehler auftritt:

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();

Der durch das Signal „ connected()“ ausgelöste Slot ruft sofort „ QLowEnergyController::discoverServices()“ auf, um die Dienstermittlung auf dem verbundenen Peripheriegerät zu starten.

controller->discoverServices();

Die resultierende Liste wird dem Benutzer angezeigt. Die folgende Abbildung zeigt die Ergebnisse, wenn das SensorTag-Gerät ausgewählt wird. Die Ansicht listet die Namen der Dienste auf, gibt an, ob es sich um primäre oder sekundäre Dienste handelt, und enthält die UUID, die den Diensttyp bestimmt.

Mit dem Qt-BLE-Scanner gefundene GATT-Dienste

Sobald der Dienst ausgewählt wurde, wird die zugehörige QLowEnergyService -Instanz erstellt, um die Interaktion mit ihm zu ermöglichen:

QLowEnergyService*service = controller->createServiceObject(serviceUuid);
if (!service) {
    qWarning() << "Cannot create service for uuid";
   return;
}

Das Service-Objekt stellt die erforderlichen Signale und Funktionen bereit, um die Service-Details zu ermitteln, Merkmale und Deskriptoren zu lesen und zu schreiben sowie Benachrichtigungen über Datenänderungen zu empfangen. Änderungsbenachrichtigungen können durch das Schreiben eines Werts oder aufgrund einer geräteinternen Aktualisierung ausgelöst werden, die möglicherweise durch die interne Logik veranlasst wird. Während der anfänglichen Detailsuche wechselt der Status des Dienstes „ state()“ von „ RemoteService “ zu „ RemoteServiceDiscovering “ und endet schließlich mit „ RemoteServiceDiscovered “:

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

Lesen von Dienstdaten

Nach Auswahl eines Dienstes werden die Dienstdetails angezeigt. Jedes Merkmal wird zusammen mit seinem Namen, seiner UUID, seinem Wert, seinem Handle und seinen Eigenschaften aufgelistet.

Im Qt BLE Scanner aufgeführte GATT-Merkmale

Es ist möglich, die Merkmale des Dienstes über ` QLowEnergyService::characteristics()` abzurufen, und wiederum kann jeder Deskriptor über ` QLowEnergyCharacteristic::descriptors()` abgerufen werden.

const QList<QLowEnergyCharacteristic> chars = service->characteristics();
for (const QLowEnergyCharacteristic &ch : chars) {
    auto cInfo = new CharacteristicInfo(ch);
    m_characteristics.append(cInfo);
}

Obwohl die Beispielanwendung keine Deskriptoren anzeigt, nutzt sie diese, um den Namen eines einzelnen Merkmals abzurufen, falls dieser nicht anhand der UUID ermittelt werden kann. Eine zweite Möglichkeit, den Namen zu ermitteln, ist das Vorhandensein eines Deskriptors vom Typ „ QBluetoothUuid::DescriptorType::CharacteristicUserDescription “. Der folgende Code zeigt, wie dies erreicht werden kann:

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;
    }
}

Beispielprojekt @ code.qt.io

© 2026 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.