Sur cette page

Scanner Bluetooth Low Energy

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

L'exemple de scanner Bluetooth Low Energy montre comment développer des applications Bluetooth Low Energy à l'aide de la Qt Bluetooth API. L’application permet de rechercher des périphériques Low Energy, d’analyser leurs services et de lire les caractéristiques et les descripteurs de ces services.

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

Cet exemple présente les classes Qt suivantes :

Cet 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, puis les présente à l'utilisateur. L'application offre ainsi un moyen simple de parcourir le contenu proposé par un périphérique.

Exécution de l'exemple

Vous pouvez exécuter l'exemple à partir de :

Demande d’autorisation d’utilisation du Bluetooth

Sur certaines plateformes, il est nécessaire d’accorder explicitement les autorisations requises pour utiliser le 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 s'affiche lorsque l'utilisateur tente de lancer la détection des appareils, et 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 recherche de périphériques démarre si l'utilisateur accorde l'autorisation. Dans le cas contraire, l'application ne fonctionne pas.

Recherche de périphériques

La première étape consiste à répertorier tous les périphériques. Ceux-ci peuvent être détectés à l'aide de la classe ` QBluetoothDeviceDiscoveryAgent `. Le processus de détection est lancé à l'aide de la méthode ` start()`. Chaque nouveau périphérique est signalé via 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éponse à la détection d’un nouveau périphérique. Il filtre tous les périphériques détectés qui portent l’indicateur QBluetoothDeviceInfo::LowEnergyCoreConfiguration et les ajoute à une liste affichée à l’utilisateur. Le signal deviceDiscovered() peut être émis plusieurs fois pour un même périphérique à mesure que de nouveaux détails sont détectés. Ici, nous regroupons ces détections de périphériques afin que l’utilisateur ne voie que les périphériques 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 périphériques peut ressembler à celle de l’image ci-dessous.

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

Appareils à proximité répertoriés dans le scanner BLE de Qt

Connexion aux services

Une fois que l'utilisateur a sélectionné un appareil dans la liste, l'application se connecte à celui-ci 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 se poursuit 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étection 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é. La vue répertorie les noms des services, en précisant s’il s’agit de services principaux ou secondaires, ainsi que l’UUID qui détermine le type de service.

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

Dès que le service est choisi, l’instance QLowEnergyService associée est créée pour permettre l’interaction avec celui-ci :

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

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

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

Lecture des données du service

Une fois un service sélectionné, ses détails s'affichent. Chaque caractéristique est répertoriée avec son nom, son UUID, sa valeur, son identifiant et ses propriétés.

Caractéristiques GATT répertoriées dans Qt BLE Scanner

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'application d'exemple n'affiche pas les descripteurs, elle les utilise pour obtenir le nom d'une caractéristique spécifique si celui-ci ne peut être déterminé à partir de son UUID. La deuxième façon d'obtenir le nom consiste à utiliser un descripteur de type QBluetoothUuid::DescriptorType::CharacteristicUserDescription. Le code ci-dessous montre comment procéder :

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.