한국어
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 85684
178 Qt Creator 에서 GitHub Copilot 사용하기 file makersweb 2024.04.13 59
177 QtQuick 애플리케이션에 Rive 애니메이션 통합 makersweb 2024.03.31 218
176 클라우드용 Qt file makersweb 2024.01.16 593
175 QRhi 에 대해서 file makersweb 2023.12.29 466
174 Android 애플리케이션 서명 구성 file makersweb 2023.12.17 430
173 QML의 사용자 정의 Image makersweb 2023.09.17 487
172 Base64로 인코딩된 파일을 복원 makersweb 2023.08.06 386
171 QML에서 D-Bus 통신 file makersweb 2023.03.15 605
170 Qt 하이브리드 애플리케이션(Hybrid App) 개발 file makersweb 2023.02.08 818
169 Widgets(C++) 기반의 기본 스타일을 Dark 테마 및 Material 디자인 스타일로 바꾸기 file makersweb 2023.01.28 1084
168 OpacityMask 예제 file makersweb 2023.01.26 519
167 QProcess 예제 (프로그램 재시작) file makersweb 2023.01.25 824
166 하드디스크 드라이브 여유 공간 계산 file makersweb 2023.01.15 448
165 Qt Property(속성) 시스템 makersweb 2023.01.08 1673
164 VTK 를 사용해서 강력한 시각화(3D, Plotting, Chart)Qt 응용프로그램 개발하기 file makersweb 2022.10.16 1536
163 QProcess 보안 권고 리뷰 file makersweb 2022.09.18 558
162 QMake 프로젝트를 CMake 프로젝트로 변환 with qmake2cmake makersweb 2022.09.17 976
161 Qt Safe Renderer 개요 file makersweb 2022.09.08 503
160 clazy 로 13개의 시그널, 슬롯 오류 해결 makersweb 2022.08.23 551
159 Qt 스마트 포인터 (QSharedPointer, QScopedPointer, QPointer) makersweb 2022.08.18 1092