블루투스 저에너지 스캐너
블루투스 저에너지(BLE) 주변 기기의 콘텐츠를 탐색하도록 설계된 애플리케이션입니다. 이 예제는 모든 Qt Bluetooth 저에너지 클래스를 모두 사용하는 방법을 보여줍니다.
이 '블루투스 저에너지 스캐너 예제'는 Qt Bluetooth API를 사용하여 블루투스 저에너지 애플리케이션을 개발하는 방법을 보여줍니다. 이 애플리케이션은 저에너지 장치 스캔, 해당 서비스 스캔, 서비스 특성 및 설명자 읽기 기능을 다룹니다.

이 예제에서는 다음과 같은 Qt 클래스를 소개합니다:
이 예제는 임의의 Bluetooth Low Energy 주변 기기와 함께 사용할 수 있습니다. 이 예제는 모든 서비스, 특성 및 설명자의 스냅샷을 생성하여 사용자에게 표시합니다. 따라서 이 애플리케이션은 주변 기기가 제공하는 내용을 손쉽게 탐색할 수 있는 방법을 제공합니다.
예제 실행하기
다음 위치에서 예제를 실행할 수 있습니다:
- Qt Creator
Welcome 모드를 열고 Examples 에서 예제를 선택하십시오. 자세한 내용은 Qt Creator: 튜토리얼: 빌드 및 실행을 참조하십시오.
- Qt Extension for Visual Studio Code
Command Palette 에서 Qt: Open Qt examples 명령을 실행한 후, 목록에서 예제를 선택하십시오. 자세한 내용은 Qt Extension for Visual Studio Code: 튜토리얼: 빌드 및 실행을 참조하십시오.
블루투스 사용 권한 요청
일부 플랫폼에서는 블루투스 사용을 위해 명시적으로 권한을 부여해야 합니다. 이 예제는 BluetoothPermission QML 객체를 사용하여 권한을 확인하고, 필요한 경우 권한을 요청합니다:
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()
}
}사용자가 기기 검색을 시작하려고 할 때 권한 요청 대화 상자가 표시되며, 권한 상태는 Undetermined 입니다:
onButtonClick: {
if (permission.status === Qt.PermissionStatus.Undetermined)
permission.request()
else if (permission.status === Qt.PermissionStatus.Granted)
devicesPage.toggleDiscovery()
}사용자가 권한을 허용하면 기기 검색이 시작됩니다. 그렇지 않으면 애플리케이션이 작동하지 않습니다.
기기 검색
첫 번째 단계는 모든 주변 장치를 찾는 것입니다. 장치는 ` QBluetoothDeviceDiscoveryAgent ` 클래스를 사용하여 찾을 수 있습니다. 탐색 프로세스는 ` start()`를 사용하여 시작됩니다. 새로운 장치가 발견될 때마다 ` deviceDiscovered()` 신호를 통해 알림이 전송됩니다:
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);아래의 ` addDevice() ` 슬롯은 새로운 장치가 발견되었을 때 반응하여 트리거됩니다. 이 슬롯은 ` QBluetoothDeviceInfo::LowEnergyCoreConfiguration ` 플래그가 설정된 모든 발견된 장치를 필터링하여 사용자에게 표시되는 목록에 추가합니다. ` deviceDiscovered()` 신호는 더 자세한 정보가 발견됨에 따라 동일한 장치에 대해 여러 번 발산될 수 있습니다. 여기서는 사용자가 개별 장치만 볼 수 있도록 이러한 장치 발견 정보를 매칭합니다:
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();
}
}기기 목록은 아래 이미지와 같이 표시될 수 있습니다.
참고: 원격 장치가 자신의 존재를 능동적으로 알리고 있어야합니다 .

서비스에 연결하기
사용자가 목록에서 장치를 선택하면 애플리케이션은 해당 장치에 연결하여 모든 서비스를 스캔합니다. 장치에 연결하는 데는 ` QLowEnergyController ` 클래스가 사용됩니다. ` QLowEnergyController::connectToDevice()` 함수는 연결 프로세스를 시작하며, 이 프로세스는 ` QLowEnergyController::connected()` 신호를 수신하거나 오류가 발생할 때까지 지속됩니다:
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();connected() 신호에 의해 트리거된 슬롯은 즉시 QLowEnergyController::discoverServices()을 호출하여 연결된 주변 기기에서 서비스 탐색을 시작합니다.
controller->discoverServices();그 결과로 생성된 목록이 사용자에게 표시됩니다. 아래 이미지는 SensorTag 장치를 선택했을 때의 결과를 보여줍니다. 이 화면에는 서비스 이름, 주 서비스인지 보조 서비스인지 여부, 그리고 서비스 유형을 결정하는 UUID가 나열되어 있습니다.

서비스가 선택되는 즉시, 해당 서비스와의 상호작용을 가능하게 하기 위해 관련 QLowEnergyService 인스턴스가 생성됩니다:
QLowEnergyService*service = controller->createServiceObject(serviceUuid);
if (!service) {
qWarning() << "Cannot create service for uuid";
return;
}서비스 객체는 서비스 세부 정보를 조회하고, 특성 및 설명자를 읽고 쓰며, 데이터 변경 알림을 수신하는 데 필요한 신호와 기능을 제공합니다. 변경 알림은 값을 쓰거나, 내부 로직에 의해 유발될 수 있는 기기 내 업데이트의 결과로 트리거될 수 있습니다. 초기 세부 정보 검색 과정에서 서비스의 state()는 RemoteService 에서 RemoteServiceDiscovering 로 전환된 후, 최종적으로 RemoteServiceDiscovered 로 종료됩니다:
connect(service, &QLowEnergyService::stateChanged,
this, &Device::serviceDetailsDiscovered);
service->discoverDetails();
setUpdate(u"Back\n(Discovering details...)"_s);서비스 데이터 읽기
서비스를 선택하면 서비스 세부 정보가 표시됩니다. 각 특성에는 이름, UUID, 값, 핸들 및 속성이 함께 나열됩니다.

QLowEnergyService::characteristics()을 통해 서비스의 특성을 조회할 수 있으며, 마찬가지로 QLowEnergyCharacteristic::descriptors()을 통해 각 디스크립터를 얻을 수 있습니다.
const QList<QLowEnergyCharacteristic> chars = service->characteristics();
for (const QLowEnergyCharacteristic &ch : chars) {
auto cInfo = new CharacteristicInfo(ch);
m_characteristics.append(cInfo);
}예제 애플리케이션은 디스크립터를 표시하지는 않지만, UUID만으로는 개별 특성의 이름을 파악할 수 없는 경우 디스크립터를 사용하여 해당 이름을 얻습니다. 이름을 얻는 두 번째 방법은 QBluetoothUuid::DescriptorType::CharacteristicUserDescription 유형의 디스크립터가 존재하는지 확인하는 것입니다. 아래 코드는 이를 구현하는 방법을 보여줍니다:
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;
}
}© 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.