Bluetooth Low Energy Scanner
Eine Anwendung zum Durchsuchen des Inhalts von Bluetooth Low Energy Peripheriegeräten. Das Beispiel demonstriert die Verwendung aller Qt Bluetooth Low Energy Klassen.
Das Bluetooth Low Energy Scanner Beispiel zeigt, wie man Bluetooth Low Energy Anwendungen unter Verwendung der Qt Bluetooth API. Die Anwendung umfasst das Scannen nach Low Energy Geräten, das Scannen ihrer Dienste und das Lesen der Dienstmerkmale und Deskriptoren.
Das Beispiel stellt die folgenden Qt-Klassen vor:
Das Beispiel kann mit jedem beliebigen Bluetooth Low Energy Peripheriegerät verwendet werden. Es erstellt einen Schnappschuss aller Dienste, Eigenschaften und Deskriptoren und präsentiert sie dem Benutzer. Daher bietet die Anwendung eine einfache Möglichkeit, die von einem Peripheriegerät angebotenen Inhalte zu durchsuchen.
Ausführen des Beispiels
Zum Ausführen des Beispiels von Qt Creatorzu starten, öffnen Sie den Modus Welcome und wählen Sie das Beispiel unter Examples aus. Weitere Informationen finden Sie unter Erstellen und Ausführen eines Beispiels.
Anfordern der Erlaubnis zur Verwendung von Bluetooth
Auf bestimmten Plattformen ist es erforderlich, die Verwendung von Bluetooth ausdrücklich zu gestatten. Das Beispiel verwendet das BluetoothPermission
QML-Objekt, um die Berechtigungen zu prüfen und ggf. 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() } }
Das Dialogfeld für die Berechtigungsanforderung wird ausgelöst, wenn der Benutzer versucht, die Geräteerkennung 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 wird gestartet, wenn der Benutzer die Erlaubnis erteilt hat. Andernfalls ist die Anwendung nicht funktionsfähig.
Scannen nach Geräten
Der erste Schritt besteht darin, alle Peripheriegeräte zu finden. Die Geräte können mithilfe der Klasse QBluetoothDeviceDiscoveryAgent gefunden werden. Der Suchprozess wird mit start() gestartet. Jedes neue Gerät wird über das Signal deviceDiscovered() bekannt gegeben:
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 folgende addDevice()
Slot wird als Reaktion auf die Entdeckung eines neuen Geräts ausgelöst. Er filtert alle gefundenen Geräte, die das QBluetoothDeviceInfo::LowEnergyCoreConfiguration Flag haben und fügt sie zu einer Liste hinzu, die dem Benutzer angezeigt wird. Das Signal deviceDiscovered() kann mehrfach für dasselbe Gerät ausgegeben werden, wenn weitere Details entdeckt werden. Hier werden diese Gerätefunde abgeglichen, so dass 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 kann wie in der folgenden Abbildung aussehen.
Hinweis: Voraussetzung ist, dass die entfernten Geräte ihre Anwesenheit aktiv bekannt geben.
Verbinden mit Diensten
Nachdem der Benutzer ein Gerät aus der Liste ausgewählt hat, stellt die Anwendung eine Verbindung zum Gerät her und scannt alle Dienste. Die Klasse QLowEnergyController wird verwendet, um eine Verbindung zum Gerät herzustellen. Die Funktion QLowEnergyController::connectToDevice() löst den Verbindungsprozess aus, der so lange dauert, bis das Signal QLowEnergyController::connected() empfangen wird oder ein Fehler aufgetreten ist:
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 connected()-Signal ausgelöste Slot ruft sofort QLowEnergyController::discoverServices() auf, um die Dienstsuche auf dem angeschlossenen Peripheriegerät zu starten.
controller->discoverServices();
Die folgende Abbildung zeigt die Ergebnisse, wenn das SensorTag-Gerät ausgewählt ist. Die Ansicht listet die Namen der Dienste auf, ob es sich um primäre oder sekundäre Dienste handelt und die UUID, die den Diensttyp bestimmt.
Sobald der Dienst ausgewählt ist, wird die zugehörige Instanz QLowEnergyService erstellt, um die Interaktion mit dem Dienst zu ermöglichen:
QLowEnergyService *service = controller->createServiceObject(serviceUuid);if (!service) { qWarning() << "Cannot create service for uuid"; return; }
Das Dienstobjekt stellt die erforderlichen Signale und Funktionen zur Verfügung, um die Dienstdetails zu ermitteln, Merkmale und Deskriptoren zu lesen und zu schreiben sowie Benachrichtigungen über Datenänderungen zu empfangen. Änderungsbenachrichtigungen können durch das Schreiben eines Wertes oder durch eine geräteinterne Aktualisierung ausgelöst werden, die möglicherweise durch die interne Logik ausgelöst wird. Während der anfänglichen Suche nach Details wechselt der state() des Dienstes 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 mit seinem Namen, seiner UUID, seinem Wert, seinem Handle und seinen Eigenschaften aufgelistet.
Es ist möglich, die Merkmale des Dienstes über QLowEnergyService::characteristics() abzurufen, und jeder Deskriptor kann wiederum ü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, verwendet sie Deskriptoren, um den Namen eines einzelnen Merkmals zu erhalten, wenn sein Name nicht anhand seiner UUID erkannt werden kann. Die zweite Möglichkeit, den Namen zu erhalten, ist das Vorhandensein eines Deskriptors vom Typ QBluetoothUuid::DescriptorType::CharacteristicUserDescription. Der nachstehende 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; } }
© 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.