Bluetooth Low Energy Herzfrequenz-Server
Ein Beispiel, das zeigt, wie man einen GATT-Dienst einrichtet und bewirbt. Das Beispiel veranschaulicht die Verwendung der Qt Bluetooth Low Energy-Klassen im Zusammenhang mit der Peripherie (Slave) Funktionalität.
Der Bluetooth Low Energy Heart Rate Server ist eine Kommandozeilenanwendung, die zeigt, wie man einen Bluetooth GATT Server unter Verwendung der Qt Bluetooth API. Die Anwendung deckt die Einrichtung eines Dienstes, seine Bekanntmachung und die Benachrichtigung von Clients über Änderungen von Kennwerten ab.
Das Beispiel nutzt die folgenden Qt-Klassen:
- QLowEnergyAdvertisingData
- QLowEnergyAdvertisingParameters
- QLowEnergyServiceData
- QLowEnergyCharacteristicData
- QLowEnergyDescriptorData
- QLowEnergyController
- QLowEnergyService
Das Beispiel implementiert eine Serveranwendung, das heißt, es hat keine grafische Benutzeroberfläche. Um zu visualisieren, was es tut, können Sie das Beispiel Heart Rate Game verwenden, das im Grunde das clientseitige Gegenstück zu dieser Anwendung ist.
Prüfen der Bluetooth-Berechtigung
Bevor die Anwendung einen Dienst erstellen und mit der Werbung beginnen kann, müssen wir prüfen, ob die Anwendung die Erlaubnis hat, Bluetooth zu verwenden.
auto permissionStatus = app.checkPermission(QBluetoothPermission{});
Bluetooth-Erlaubnis anfordern
Wenn der Bluetooth-Autorisierungsstatus unbestimmt ist, müssen wir eine Genehmigung für die Verwendung von Bluetooth anfordern.
if (permissionStatus == Qt::PermissionStatus::Unbestimmt) { qInfo("Requesting Bluetooth permission ..."); app.requestPermission(QBluetoothPermission{}, [&permissionStatus](const QPermission &permission){ qApp->exit(); permissionStatus = permission.status(); }); // Warten Sie jetzt auf die Auflösung der Genehmigungsanfrage.app.exec(); }
Einrichten von Werbedaten und Parametern
Zwei Klassen werden verwendet, um den Werbeprozess zu konfigurieren:
- QLowEnergyAdvertisingData gibt an, welche Informationen gesendet werden sollen
- QLowEnergyAdvertisingParameters wird für bestimmte Aspekte verwendet, wie z. B. die Einstellung des Werbeintervalls oder die Steuerung der Geräte, die eine Verbindung herstellen dürfen.
In unserem Beispiel verwenden wir einfach die Standardparameter.
Die in QLowEnergyAdvertisingData enthaltenen Informationen sind für andere Geräte, die gerade scannen, sichtbar. Sie können sie nutzen, um zu entscheiden, ob sie eine Verbindung herstellen wollen oder nicht. In unserem Beispiel geben wir die Art des von uns angebotenen Dienstes, einen Namen, der unser Gerät für Menschen angemessen beschreibt, und die Sendeleistung des Geräts an. Letzteres ist für potenzielle Kunden oft nützlich, da sie durch den Vergleich der empfangenen Signalstärke mit der angekündigten feststellen können, wie weit unser Gerät entfernt ist.
Hinweis: Der Platz für die Werbedaten ist sehr begrenzt (insgesamt nur 31 Byte), daher sollten Daten mit variabler Länge wie der Gerätename so kurz wie möglich gehalten werden.
QLowEnergyAdvertisingData advertisingData; advertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral); advertisingData.setIncludePowerLevel(true); advertisingData.setLocalName("HeartRateServer"); advertisingData.setServices(QList<QBluetoothUuid>() << QBluetoothUuid::ServiceClassUuid::HeartRate);
Einrichten von Dienstdaten
Als nächstes konfigurieren wir die Art des Dienstes, den wir anbieten wollen. Wir verwenden den Dienst Heart Rate, wie er in der Bluetooth-Spezifikation in seiner Minimalform definiert ist, d. h. er besteht nur aus dem Merkmal Heart Rate Measurement. Dieses Merkmal muss die Eigenschaft Notify (und keine anderen) unterstützen, und es muss einen Client Characteristic Configuration Deskriptor haben, der es Kunden ermöglicht, sich zu registrieren, um über Änderungen der Merkmalswerte benachrichtigt zu werden. Wir setzen den anfänglichen Herzfrequenzwert auf Null, da er ohnehin nicht gelesen werden kann (der einzige Weg, wie der Kunde den Wert erhalten kann, ist über Benachrichtigungen).
QLowEnergyCharacteristicData charData; charData.setUuid(QBluetoothUuid::CharacteristicType::HeartRateMeasurement); charData.setValue(QByteArray(2, 0)); charData.setProperties(QLowEnergyCharacteristic::Notify); const QLowEnergyDescriptorData clientConfig(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration, QByteArray(2, 0)); charData.addDescriptor(clientConfig); QLowEnergyServiceData serviceData; serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary); serviceData.setUuid(QBluetoothUuid::ServiceClassUuid::HeartRate); serviceData.addCharacteristic(charData);
Werbung und Abhören auf eingehende Verbindungen
Nun, da alle Daten eingerichtet sind, können wir mit der Werbung beginnen. Zuerst erstellen wir ein QLowEnergyController Objekt in peripheral role und verwenden es, um ein (dynamisches) QLowEnergyService Objekt aus unserem (statischen) QLowEnergyServiceData zu erstellen. Dann rufen wir QLowEnergyController::startAdvertising() auf. Beachten Sie, dass wir unser QLowEnergyAdvertisingData zweimal übergeben: Das erste Argument dient als die eigentlichen Werbedaten, das zweite als die Scan-Antwortdaten. Sie könnten unterschiedliche Informationen transportieren, aber das brauchen wir hier nicht. Wir übergeben auch eine standardmäßig erstellte Instanz von QLowEnergyAdvertisingParameters, da die Standard-Werbeparameter für uns in Ordnung sind. Wenn ein Client an dem beworbenen Dienst interessiert ist, kann er nun eine Verbindung zu unserem Gerät herstellen. Wenn dies geschieht, beendet das Gerät die Werbung und das Signal QLowEnergyController::connected() wird ausgegeben.
Hinweis: Wenn ein Client die Verbindung trennt, wird die Werbung nicht automatisch wieder aufgenommen. Wenn Sie dies wünschen, müssen Sie sich mit dem Signal QLowEnergyController::disconnected() verbinden und QLowEnergyController::startAdvertising() in dem entsprechenden Slot aufrufen.
bool errorOccurred = false;const std::unique_ptr<QLowEnergyController> leController(QLowEnergyController::createPeripheral());auto errorHandler = [&leController, &errorOccurred](QLowEnergyController::Error errorCode) { qWarning().noquote().nospace() << errorCode << " occurred: " << leController->errorString(); if (errorCode ! = QLowEnergyController::RemoteHostClosedError) { qWarning("Heartrate-server quitting due to the error."); errorOccurred = true; QCoreApplication::quit(); } };QObject::connect(leController.get(), &QLowEnergyController::errorOccurred, errorHandler); std::unique_ptr<QLowEnergyService> service(leController->addService(serviceData)); leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData,advertisingData);if (errorOccurred) return-1;
Bereitstellen der Herzfrequenz
So weit, so gut. Aber wie kommt ein Client eigentlich an die Herzfrequenz? Dies geschieht durch regelmäßiges Aktualisieren des Wertes des entsprechenden Merkmals im Objekt QLowEnergyService, das wir im obigen Codeschnipsel von QLowEnergyController erhalten haben. Die Quelle für die Herzfrequenz wäre normalerweise eine Art Sensor, aber in unserem Beispiel denken wir uns einfach Werte aus, die wir zwischen 60 und 100 pendeln lassen. Der wichtigste Teil im folgenden Codeschnipsel ist der Aufruf von QLowEnergyService::writeCharacteristic. Wenn ein Client gerade verbunden ist und Benachrichtigungen durch Schreiben in das oben erwähnte Client Characteristic Configuration
aktiviert hat, wird er über den neuen Wert benachrichtigt.
QTimer heartbeatTimer; quint8 currentHeartRate = 60; enum ValueChange { ValueUp, ValueDown } valueChange = ValueUp; const auto heartbeatProvider = [&service, ¤tHeartRate, &valueChange]() { QByteArray value; value.append(char(0)); // Flags that specify the format of the value. value.append(char(currentHeartRate)); // Actual value. QLowEnergyCharacteristic characteristic = service->characteristic(QBluetoothUuid::CharacteristicType::HeartRateMeasurement); Q_ASSERT(characteristic.isValid()); service->writeCharacteristic(characteristic, value); // Potentially causes notification. if (currentHeartRate == 60) valueChange = ValueUp; else if (currentHeartRate == 100) valueChange = ValueDown; if (valueChange == ValueUp) ++currentHeartRate; else --currentHeartRate; }; QObject::connect(&heartbeatTimer, &QTimer::timeout, heartbeatProvider); heartbeatTimer.start(1000);
© 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.