블루투스 저에너지 심박수 서버
GATT 서비스를 설정하고 광고하는 방법을 보여주는 예제입니다. 이 예는 주변 장치(슬레이브) 기능과 관련된 Qt Bluetooth 주변 장치(슬레이브) 기능과 관련된 저에너지 클래스의 사용을 보여줍니다.
Bluetooth 저에너지 심박수 서버는 명령줄 애플리케이션으로, Bluetooth GATT 서버를 개발하는 방법을 보여주는 Qt Bluetooth API. 이 애플리케이션은 서비스 설정, 서비스 광고 및 특성 값 변경에 대한 클라이언트 알림을 다룹니다.
이 예제에서는 다음 Qt 클래스를 사용합니다:
- QLowEnergyAdvertisingData
- QLowEnergyAdvertisingParameters
- QLowEnergyServiceData
- QLowEnergyCharacteristicData
- QLowEnergyDescriptorData
- QLowEnergyController
- QLowEnergyService
이 예제는 서버 애플리케이션을 구현하므로 그래픽 사용자 인터페이스가 없습니다. 이 애플리케이션이 수행하는 작업을 시각화하려면 기본적으로 이 애플리케이션의 클라이언트 측에 해당하는 심박수 게임 예제를 사용할 수 있습니다.
블루투스 권한 확인
애플리케이션이 서비스를 생성하고 광고를 시작하기 전에 애플리케이션에 블루투스 사용 권한이 있는지 확인해야 합니다.
auto permissionStatus = app.checkPermission(QBluetoothPermission{});
블루투스 권한 요청하기
블루투스 인증 상태가 확인되지 않으면 블루투스 사용 권한을 요청해야 합니다.
if (permissionStatus== == Qt::PermissionStatus::Undetermined) { qInfo("Requesting Bluetooth permission ..."); app.requestPermission(QBluetoothPermission{}, [&permissionStatus](const QPermission &permission){ qApp->exit(); permissionStatus = permission.status(); }); // 이제 권한 요청이 해결될 때까지 기다립니다.app.exec(); }
광고 데이터 및 파라미터 설정
광고 프로세스를 구성하는 데는 두 가지 클래스가 사용됩니다:
- QLowEnergyAdvertisingData 어떤 정보를 브로드캐스트할지 지정합니다.
- QLowEnergyAdvertisingParameters 광고 간격을 설정하거나 연결할 수 있는 디바이스를 제어하는 등 특정 측면에 사용됩니다.
이 예에서는 기본 매개변수를 사용합니다.
QLowEnergyAdvertisingData 에 포함된 정보는 현재 스캔 중인 다른 디바이스에 표시됩니다. 이 정보를 사용하여 연결을 설정할지 여부를 결정할 수 있습니다. 이 예에서는 제공하는 서비스 유형, 사람에게 디바이스를 적절하게 설명하는 이름, 디바이스의 전송 전력 레벨을 포함합니다. 후자는 수신된 신호 강도와 광고된 신호 강도를 비교하여 디바이스가 얼마나 멀리 떨어져 있는지 알 수 있기 때문에 잠재 고객에게 유용한 경우가 많습니다.
참고: 광고 데이터를 위한 공간은 매우 제한적이므로(총 31바이트에 불과) 디바이스 이름과 같은 가변 길이 데이터는 가능한 한 짧게 작성해야 합니다.
QLowEnergyAdvertisingData advertisingData; advertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral); advertisingData.setIncludePowerLevel(true); advertisingData.setLocalName("HeartRateServer"); advertisingData.setServices(QList<QBluetoothUuid>() << QBluetoothUuid::ServiceClassUuid::HeartRate);
서비스 데이터 설정하기
다음으로 제공할 서비스의 종류를 구성합니다. 블루투스 사양에 정의된 Heart Rate 서비스를 최소한의 형태, 즉 Heart Rate Measurement 특성으로만 구성된 형태로 사용합니다. 이 특성은 Notify 속성을 지원해야 하며(다른 특성은 지원하지 않음), 클라이언트가 특성 값 변경에 대한 알림을 받도록 등록할 수 있는 Client Characteristic Configuration 설명자를 가져야 합니다. 초기 심박수 값은 어차피 읽을 수 없으므로 0으로 설정했습니다(클라이언트가 이 값을 얻을 수 있는 유일한 방법은 알림을 통해서만 가능합니다).
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);
수신 연결에 대한 광고 및 수신 대기
이제 모든 데이터가 설정되었으므로 광고를 시작할 수 있습니다. 먼저 peripheral role 에 QLowEnergyController 객체를 만들고 이를 사용하여 (정적) QLowEnergyServiceData 에서 (동적) QLowEnergyService 객체를 만듭니다. 그런 다음 QLowEnergyController::startAdvertising()를 호출합니다. QLowEnergyAdvertisingData 인수를 두 번 전달하는데, 첫 번째 인수는 실제 광고 데이터로, 두 번째 인수는 스캔 응답 데이터로 사용됩니다. 다른 정보를 전달할 수도 있지만 여기서는 그럴 필요가 없습니다. 또한 기본 광고 매개변수로도 충분하기 때문에 QLowEnergyAdvertisingParameters 의 기본 구성 인스턴스를 전달합니다. 클라이언트가 광고된 서비스에 관심이 있다면 이제 디바이스에 연결을 설정할 수 있습니다. 이 경우 디바이스는 광고를 중지하고 QLowEnergyController::connected() 신호가 전송됩니다.
참고: 클라이언트가 연결을 끊으면 광고가 자동으로 재개되지 않습니다. 이를 원하면 QLowEnergyController::disconnected() 신호에 연결하고 해당 슬롯에서 QLowEnergyController::startAdvertising()을 호출해야 합니다.
bool errorOccurred = false;const std::unique_ptr<QLowEnergyController> leController(QLowEnergyController::createPeripheral());auto errorHandler = [&leController, &errorOccurred](QLowEnergyController::오류 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;
심박수 제공
지금까지는 괜찮습니다. 하지만 클라이언트는 실제로 심박수를 어떻게 알 수 있을까요? 이는 위의 코드 스니펫에서 QLowEnergyController 에서 받은 QLowEnergyService 객체의 각 특성 값을 정기적으로 업데이트함으로써 이루어집니다. 심박수의 소스는 일반적으로 일종의 센서이지만, 이 예에서는 60에서 100 사이에서 진동하도록 값을 구성합니다. 다음 코드 스니펫에서 가장 중요한 부분은 QLowEnergyService::writeCharacteristic 으로의 호출입니다. 클라이언트가 현재 연결되어 있고 앞서 언급한 Client Characteristic Configuration
에 글을 써서 알림을 활성화한 경우 새 값에 대한 알림을 받게 됩니다.
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.