Sur cette page

Scanner Bluetooth Low Energy

Une application conçue pour parcourir le contenu des périphériques Bluetooth Low Energy. L'exemple démontre l'utilisation de toutes les classes Qt Bluetooth Low Energy.

L'exemple du scanner Bluetooth Low Energy montre comment développer des applications Bluetooth Low Energy à l'aide de la classe Qt Bluetooth API. L'application couvre la recherche de dispositifs à faible énergie, l'analyse de leurs services et la lecture des caractéristiques et des descripteurs de service.

Services GATT trouvés à l'aide du scanner Qt BLE

L'exemple présente les classes Qt suivantes :

L'exemple peut être utilisé avec n'importe quel périphérique Bluetooth Low Energy. Il crée un instantané de tous les services, caractéristiques et descripteurs et les présente à l'utilisateur. L'application permet donc de parcourir facilement le contenu offert par un périphérique.

Exécution de l'exemple

Pour exécuter l'exemple à partir de Qt Creatorouvrez le mode Welcome et sélectionnez l'exemple à partir de Examples. Pour plus d'informations, voir Qt Creator: Tutoriel : Construire et exécuter.

Demander l'autorisation d'utiliser Bluetooth

Sur certaines plateformes, il est nécessaire d'accorder explicitement des autorisations pour l'utilisation de Bluetooth. L'exemple utilise l'objet QML BluetoothPermission pour vérifier et demander les autorisations, si nécessaire :

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()
    }
}

La boîte de dialogue de demande d'autorisation est déclenchée lorsque l'utilisateur tente de lancer la découverte de l'appareil et que l'état de l'autorisation est Undetermined:

onButtonClick: {
    if (permission.status === Qt.PermissionStatus.Undetermined)
        permission.request()
    else if (permission.status === Qt.PermissionStatus.Granted)
        devicesPage.toggleDiscovery()
}

La découverte de l'appareil démarre si l'autorisation est accordée par l'utilisateur. Dans le cas contraire, l'application n'est pas fonctionnelle.

Recherche de dispositifs

La première étape consiste à rechercher tous les périphériques. Les périphériques peuvent être trouvés à l'aide de la classe QBluetoothDeviceDiscoveryAgent. Le processus de découverte est lancé à l'aide de start(). Chaque nouveau périphérique est annoncé par le signal 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);

Le slot addDevice() ci-dessous est déclenché en réaction à la découverte d'un nouvel appareil. Il filtre tous les dispositifs trouvés qui ont le drapeau QBluetoothDeviceInfo::LowEnergyCoreConfiguration et les ajoute à une liste qui est affichée à l'utilisateur. Le signal deviceDiscovered() peut être émis plusieurs fois pour le même appareil au fur et à mesure que de nouveaux détails sont découverts. Ici, nous faisons correspondre ces découvertes d'appareils de sorte que l'utilisateur ne voit que les appareils individuels :

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();
    }
}

La liste des appareils peut ressembler à l'image ci-dessous.

Remarque : il est indispensable que les appareils distants annoncent activement leur présence.

Appareils à proximité listés dans le scanner Qt BLE

Connexion aux services

Une fois que l'utilisateur a sélectionné un appareil dans la liste, l'application se connecte à l'appareil et analyse tous les services. La classe QLowEnergyController est utilisée pour se connecter à l'appareil. La fonction QLowEnergyController::connectToDevice() déclenche le processus de connexion qui dure jusqu'à ce que le signal QLowEnergyController::connected() soit reçu ou qu'une erreur se produise :

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();

Le slot déclenché par le signal connected() appelle immédiatement QLowEnergyController::discoverServices() pour lancer la découverte des services sur le périphérique connecté.

controller->discoverServices();

La liste obtenue est présentée à l'utilisateur. L'image ci-dessous affiche les résultats lorsque le périphérique SensorTag est sélectionné. L'image ci-dessous affiche les résultats lorsque le périphérique SensorTag est sélectionné. La vue répertorie les noms des services, indique s'il s'agit de services primaires ou secondaires et indique l'UUID qui détermine le type de service.

Services GATT trouvés à l'aide du scanner Qt BLE

Dès que le service est choisi, l'instance QLowEnergyService correspondante est créée pour permettre l'interaction avec lui :

QLowEnergyService *service =  controller->createServiceObject(serviceUuid) ;if (!service) {    qWarning() << "Cannot create service for uuid";
   return; }

L'objet service fournit les signaux et les fonctions nécessaires pour découvrir les détails du service, lire et écrire les caractéristiques et les descripteurs, ainsi que pour recevoir les notifications de changement de données. Les notifications de changement peuvent être déclenchées à la suite de l'écriture d'une valeur ou d'une mise à jour de l'appareil potentiellement déclenchée par la logique interne. Au cours de la recherche initiale de détails, le service state() passe de RemoteService à RemoteServiceDiscovering et se termine par RemoteServiceDiscovered:

connect(service, &QLowEnergyService::stateChanged,
        this, &Device::serviceDetailsDiscovered);
service->discoverDetails();
setUpdate(u"Back\n(Discovering details...)"_s);

Lecture des données du service

La sélection d'un service permet d'afficher les détails du service. Chaque caractéristique est listée avec son nom, son UUID, sa valeur, son handle et ses propriétés.

Caractéristiques du GATT répertoriées dans le scanner Qt BLE

Il est possible de récupérer les caractéristiques du service via QLowEnergyService::characteristics() et, à son tour, chaque descripteur peut être obtenu via QLowEnergyCharacteristic::descriptors().

const QList<QLowEnergyCharacteristic> chars = service->characteristics();
for (const QLowEnergyCharacteristic &ch : chars) {
    auto cInfo = new CharacteristicInfo(ch);
    m_characteristics.append(cInfo);
}

Bien que l'exemple d'application n'affiche pas les descripteurs, il les utilise pour obtenir le nom d'une caractéristique individuelle si son nom ne peut être discerné sur la base de son UUID. La deuxième façon d'obtenir le nom est l'existence d'un descripteur du type QBluetoothUuid::DescriptorType::CharacteristicUserDescription. Le code ci-dessous montre comment cela peut être réalisé :

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;
    }
}

Exemple de projet @ code.qt.io

© 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.