한국어
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 85829
178 가상키보드(Qt Virtual Keyboard)를 사용하는 방법 [32] file makersweb 2019.05.03 220958
177 콘솔에서 사용자 입력받기 file makersweb 2020.03.22 51842
176 QString 문자열 다루기 예제 운영자 2019.01.26 40028
175 Windows에서 Qt 설치 따라하기 file makersweb 2019.10.14 30867
174 Qt의 시그널 슬롯 시스템 file makersweb 2015.10.20 23575
173 QThread 소개 및 예제 makersweb 2019.12.25 19431
172 QtCreator Design으로 GUI만들기 (QML로 만드는 Hello World -2) [1] file makersweb 2019.05.26 14864
171 초보자를 위한 첫번째 프로젝트 - QML로 만드는 Hello World file makersweb 2018.03.16 14445
170 Qt 프로그래밍의 시작 makersweb 2015.10.25 14363
169 Qml과 C++로 구현하는 GUI어플리케이션 file makersweb 2018.12.25 13930
168 QML과 QtQuick 모듈 개념과 기본 타입들 makersweb 2019.04.26 13386
167 Windows에서 라즈베리파이3용 Qt5.10.0 크로스컴파일 [20] file makersweb 2018.02.23 12910
166 Qt의 오픈소스 라이센스 소개 file makersweb 2019.12.15 12548
165 Qml 기본 컴포넌트 강좌 (1) file makersweb 2019.01.03 12059
164 QtSerialPort를 사용한 시리얼(Serial)통신 [3] makersweb 2019.05.21 11885
163 Qt Installer Framework - 패키징, 설치프로그램 제작 file makersweb 2018.10.14 11660
162 Qt 응용프로그램 배포(windows) file makersweb 2018.10.10 11308
161 Ubuntu Linux에서 Qt Creator 설치 file makersweb 2016.03.06 10667
160 Qt의 스레드간 시그널 슬롯의 커넥션타입 [1] makersweb 2015.10.24 10167
159 Qt애플리케이션 객체(QCoreApplication, QGuiApplication, QApplication) 에 대해서 makersweb 2019.11.11 10084