한국어
Qt
 

Qt Bluetooth Low Energy API는 Qt 5.4에서 Central Role 장치를 위해 도입되었다. Qt 5.5 이후 API는 최종 버전이며 향후 릴리스에 대한 호환성 보장이 제공된다. Qt 5.7 이후로 Peripheral Role 장치를 지원하는 추가 API가 테크니컬 프리뷰로 추가되었으며 백엔드는 Linux/BlueZ, iOS 및 macOS용으로 구현되었다.

Bluetooth Smart라고도 하는 Bluetooth Low Energy는 2011년에 공식적으로 도입된 무선 컴퓨터 네트워크 기술이다. BLE 기술은 Bluetooth v4.0에서 도입되었으며 이 기술을 지원하는 장치를 Bluetooth Smart Ready 장치라고 한다. Classic Bluetooth와 동일한 2.4GHz 주파수에서 작동한다. 주요 차이점은 기술 이름에서 알 수 있듯이 저전력 소비 장치를 대상으로 한다는 점이다. 일반적으로 Bluetooth 저전력 장치는 코인 셀 배터리로 몇 달, 심지어 몇 년 동안 작동할 수 있다.

BLE 세계에서는 일반적으로 두역할로 나눠지는 디바이스가 있으며 다음과 같다.

  • Server(Peripheral 장치라고도 함) 예 : 온도 또는 심박수와 같은 서비스
  • Client(Central 장치라고 함) 예: 휴대폰이나 컴퓨터와 같은 환경 제어 응용 프로그램의 일부

또한 Bluetooth Low Energy는 ATT(속성 프로토콜) 및 GATT(일반 속성 프로필)의 두 가지 아주 중요한 프로토콜을 기반으로 한다. 모든 Bluetooth Smart Ready 장치에서 사용하는 통신 계층이다. 이와 관련해서는 별도의 Article 로 소개할 계획이다.

본 문서에서는 Qt에서 제공하는 Bluetooth Low Energy API를 사용하는 방법을 설명한다. 클라이언트 측에서 API는 주변 장치에 대한 연결 생성, 서비스 검색, 장치에 저장된 데이터 읽기 및 쓰기를 허용한다. 서버 측에서는 서비스를 설정하고, 광고하고, 클라이언트가 특성을 작성할 때 알림을 받을 수 있다.

클라이언트(Central Device)

주요 클래스

QLowEnergyController

QLowEnergyService

QLowEnergyCharacteristic

QLowEnergyDescriptor

디바이스 검색

근처에 있는 Bluetooth 장치를 검색하기 위해 QBluetoothDeviceDiscoveryAgent 생성한다.

QBluetoothDeviceDiscoveryAgent::start() 메서드를 호출하여 검색을 시작한다.

디바이스가 발견 될 때마다 deviceDiscovered(const QBluetoothDeviceInfo) 시그널이 방출된다.

완료되면 finished() 시그널이 방출 되며 이 때 discoveredDevices() 메서드를 호출하여 검색된 디바이스 정보를 리스트에 넣는다.

서비스 검색

BLE 디바이스는 QLowEnergyController 를 생성하여 엑세스 할 수 있다. QLowEnergyController::createCentral(const QBluetoothDeviceInfo &) 를 통해 QLowEnergyController 생성한다.

QLowEnergyController::connectToDevice() 메서드를 통해 디바이스 연결을 설정한다. 연결되면 connected 시그널이 방출된다.

디바이스에서 제공하는 서비스를 알기 위해 discoverServices() 메서드를 호출한다.

새 서비스가 발견될 때마다 serviceDiscovered() 시그널이 발생되고 매개변수에는 발견된 서비스의 UUID 가 포함된다.

서비스 검색이 완료되면 discoveryFinished() 시그널이 방출된다.

서비스 객체

QLowEnergyController::createServiceObject() 메서드에 서비스 UUID를 전달을 통해 QLowEnergyService 객체를 생성할 수 있다. 이 서비스 객체를 통해 서비스의 세부 정보에 대한 액세스를 제공한다.

서비스 개체가 처음 생성되면 해당 세부 정보가 아직 없으며 포함된 서비스, 특성 및 설명자의 검색은 discoverDetails() 를 호출할 때 트리거된다.

stateChanged() 또는 characteristicChanged() 시그널을 통해 모든 특성, Descriptor 및 include 서비스가 알려지고 읽거나 쓸 수 있는 시점을 알 수 있다.

...
    // If heartRateService found, create new service
    if (m_foundHeartRateService)
        m_service = m_control->createServiceObject(QBluetoothUuid(QBluetoothUuid::HeartRate), this);

    if (m_service) {
        connect(m_service, &QLowEnergyService::stateChanged, this, &DeviceHandler::serviceStateChanged);
        connect(m_service, &QLowEnergyService::characteristicChanged, this, &DeviceHandler::updateHeartRateValue);
        connect(m_service, &QLowEnergyService::descriptorWritten, this, &DeviceHandler::confirmedDescriptorWrite);
        m_service->discoverDetails();
    } else {
        setError("Heart Rate Service not found.");
    }
...

 

마지막으로 Bluetooth Low Energy 표준에 따라 HeartRate 특성 값을 처리한다.

void DeviceHandler::updateHeartRateValue(const QLowEnergyCharacteristic &c, const QByteArray &value)
{
    // ignore any other characteristic change -> shouldn't really happen though
    if (c.uuid() != QBluetoothUuid(QBluetoothUuid::HeartRateMeasurement))
        return;

    auto data = reinterpret_cast<const quint8 *>(value.constData());
    quint8 flags = *data;

    //Heart Rate
    int hrvalue = 0;
    if (flags & 0x1) // HR 16 bit? otherwise 8 bit
        hrvalue = static_cast<int>(qFromLittleEndian<quint16>(data[1]));
    else
        hrvalue = static_cast<int>(data[1]);

    addMeasurement(hrvalue);
}

 

일반적으로 특성 값은 일련의 바이트이다. 이러한 바이트의 정확한 해석은 특성 및 값 구조에 따라 다르다. 이미 상당 수는 Bluetooth SIG에 의해 표준화되었지만 사용자 정의 프로토콜을 구현할 수도 있다. 위의 예제 코드는 표준화된 HeartRate 값을 읽는 방법을 보여준다.

서버 (Peripheral Device)

주변 장치가 자신의 존재와 서비스를 알릴 필요가 있다. 주변 장치(슬레이브) 기능과 관련된 Qt Bluetooth Low Energy 클래스의 사용 방법을 보여준다.

주요 클래스

QLowEnergyAdvertisingData

QLowEnergyAdvertisingParameters

QLowEnergyServiceData

QLowEnergyCharacteristicData

QLowEnergyDescriptorData

QLowEnergyController

QLowEnergyService

서비스, 특성 및 Descriptor 정의

서비스 및 특성은 QLowEnergyServiceData, QLowEnergyCharacteristicDataQLowEnergyDescriptorData 클래스를 사용하여 달성할 수 있다. 정의될 BLE 서비스를 구성하는 필수 정보에 대한 컨테이너 또는 빌딩 블록 역할을 한다. 아래 코드 스니펫은 측정된 분당 비트를 게시하는 간단한 HeartRate 서비스를 정의한다. 이러한 서비스를 사용할 수 있는 예로 손목시계를 들 수 있다.

QLowEnergyCharacteristicData charData;
charData.setUuid(QBluetoothUuid::HeartRateMeasurement);
charData.setValue(QByteArray(2, 0));
charData.setProperties(QLowEnergyCharacteristic::Notify);
const QLowEnergyDescriptorData clientConfig(QBluetoothUuid::ClientCharacteristicConfiguration,
                                            QByteArray(2, 0));
charData.addDescriptor(clientConfig);

QLowEnergyServiceData serviceData;
serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
serviceData.setUuid(QBluetoothUuid::HeartRate);
serviceData.addCharacteristic(charData);

 

위의 예제코드에서 원하는 특성은 HeartRateMeasurement 이다. 애플리케이션은 심박수 변화를 측정하므로 특성에 대한 변경 알림을 활성화해야 한다. 모든 특성이 변경 알림을 제공하는 것은 아니다. HeartRate 특성이 표준화되었으므로 알림을 수신할 수 있다고 가정할 수 있다. 궁극적으로 QLowEnergyCharacteristic::properties() 에는 QLowEnergyCharacteristic::Notify 플래그가 설정되어 있어야 하며 적절한 알림의 가용성을 확인하기 위해 BluetoothUuid::ClientCharacteristicConfiguration 유형의 설명자가 있어야 한다.

서비스 광고

광고 프로세스를 구성하는 데 두 가지 클래스가 사용된다. QLowEnergyAdvertisingData에 포함된 정보는 현재 스캔 중인 다른 장치에서 볼 수 있다. 브로드캐스트할 정보를 지정하고 QLowEnergyAdvertisingParameters 는 광고 간격 설정 또는 연결이 허용되는 장치 제어와 같은 특정 측면을 위한 것이다. 광고 채널을 통해 전송된 실제 데이터 패킷은 31바이트를 초과할 수 없다.

주변 장치 객체는 QLowEnergyController::createPeripheral() 을 호출하여 생성한다. QLowEnergyController::startAdvertising() 을 호출하여 광고를 시작할 수 있다. 첫 번째 인수는 실제 광고 데이터 역할을 하고 두 번째 인수는 스캔 응답 데이터 역할을 한다.

QLowEnergyAdvertisingData advertisingData;
advertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral);
advertisingData.setIncludePowerLevel(true);
advertisingData.setLocalName("HeartRateServer");
advertisingData.setServices(QList<QBluetoothUuid>() << QBluetoothUuid::HeartRate);

const QScopedPointer<QLowEnergyController> leController(QLowEnergyController::createPeripheral());

QScopedPointer<QLowEnergyService> service(leController->addService(serviceData));

leController->startAdvertising(QLowEnergyAdvertisingParameters(),
                               advertisingData, advertisingData);

 

클라이언트가 광고된 서비스에 관심이 있으면 이제 장치에 연결할 수 있다. 클라이언트가 연결을 시도하면 QLowEnergyController::connected() 시그널이 방출된다. 클라이언트 연결이 끊어지면 광고가 자동으로 재개되지 않으므로 QLowEnergyController::disconnected() 시그널에 연결하고 해당 슬롯에서 QLowEnergyController::startAdvertising() 을 호출해야 한다.

데이터 제공

QLowEnergyController 로부터 받은 QLowEnergyService 객체의 각 특성 값을 정기적으로 업데이트함으로써 발생한다. 중요한 것은 QLowEnergyService::writeCharacteristic 에 대한 호출이다. 클라이언트가 현재 연결되어 있고 특성에 대한 알림 또는 표시를 활성화한 경우 해당 정보가 전송된다.

 

서버 예제: https://code.qt.io/cgit/qt/qtconnectivity.git/tree/examples/bluetooth/heartrate-server?h=5.15

클라이언트 예제: https://code.qt.io/cgit/qt/qtconnectivity.git/tree/examples/bluetooth/heartrate-game?h=5.15

번호 제목 글쓴이 날짜 조회 수
공지 Qt프로그래밍(QtQuick) Beginner를 위한 글 읽는 순서 운영자 2019.01.05 85782
158 Qt 6.4에 추가될 Qt Quick 3D Physics file makersweb 2022.08.07 343
157 HTTPS URL을 연결할 때 SslHandshakeFailedError 오류 makersweb 2022.07.31 353
156 단일 인스턴스 Qt 응용 프로그램(Single-instance Application) makersweb 2022.06.23 700
155 Qt로 작성된 iOS 앱에서 시리얼 통신 file makersweb 2022.04.30 842
154 VirtualKeyboard 스타일 커스터 마이징 makersweb 2022.03.13 462
153 성능 고려 및 제안 사항 makersweb 2022.03.07 504
152 Binding 타입으로 객체 속성 간 묶기 makersweb 2022.03.04 420
» Qt Bluetooth Low Energy 개요 makersweb 2022.02.13 660
150 Qt Android 앱에 AdMob 배너달기 file makersweb 2021.12.04 391
149 Qt 6의 C++ 프로퍼티 바인딩 예제 makersweb 2021.11.01 853
148 QML에서 앵커(anchors)로 위치 지정 file makersweb 2021.10.05 3776
147 안드로이드용 Qt 6.2 makersweb 2021.10.02 504
146 Qt 응용프로그램에서 PDF 문서 렌더링 file makersweb 2021.09.23 676
145 QML에서 Websocket 서버와 통신 file makersweb 2021.09.18 823
144 QML 코딩 규칙 makersweb 2021.09.05 3224
143 QML 에서 QR코드 생성 file makersweb 2021.08.20 892
142 앱을 종료할 때 QML 바인딩 오류를 피하는 방법 makersweb 2021.08.08 498
141 Qt 응용프로그램에서 Lottie Animation사용 file makersweb 2021.05.30 881
140 싱글 샷(Single-Shot) 시그널/슬롯 연결 makersweb 2021.05.12 748
139 응용프로그램 자동실행 설정 (on Windows) makersweb 2021.05.08 562