Bluetooth Low Energy Scanner: Discover Service Details
-
Hello,
I am trying to understand how BLE works by playing with the BLE Scanner example from Qt. So after discovering BLE devices, connecting to a device and selecting a service, the next step is to print the characteristics. For this purpose, there is the following code in the example:
void Device::connectToService(const QString &uuid) { QLowEnergyService *service = nullptr; for (auto s: qAsConst(m_services)) { auto serviceInfo = qobject_cast<ServiceInfo *>(s); if (!serviceInfo) continue; if (serviceInfo->getUuid() == uuid) { service = serviceInfo->service(); break; } } if (!service) return; qDeleteAll(m_characteristics); m_characteristics.clear(); emit characteristicsUpdated(); if (service->state() == QLowEnergyService::DiscoveryRequired) { //! [les-service-3] connect(service, &QLowEnergyService::stateChanged, this, &Device::serviceDetailsDiscovered); service->discoverDetails(); setUpdate("Back\n(Discovering details...)"); //! [les-service-3] return; } //discovery already done const QList<QLowEnergyCharacteristic> chars = service->characteristics(); for (const QLowEnergyCharacteristic &ch : chars) { auto cInfo = new CharacteristicInfo(ch); m_characteristics.append(cInfo); } QTimer::singleShot(0, this, &Device::characteristicsUpdated); }
void Device::serviceDetailsDiscovered(QLowEnergyService::ServiceState newState) { qDebug() << "service details discovered" << newState; //this line is from me for debugging if (newState != QLowEnergyService::ServiceDiscovered) { // do not hang in "Scanning for characteristics" mode forever // in case the service discovery failed // We have to queue the signal up to give UI time to even enter // the above mode if (newState != QLowEnergyService::DiscoveringServices) { QMetaObject::invokeMethod(this, "characteristicsUpdated", Qt::QueuedConnection); } return; } auto service = qobject_cast<QLowEnergyService *>(sender()); if (!service) return; //! [les-chars] const QList<QLowEnergyCharacteristic> chars = service->characteristics(); for (const QLowEnergyCharacteristic &ch : chars) { auto cInfo = new CharacteristicInfo(ch); m_characteristics.append(cInfo); } //! [les-chars] emit characteristicsUpdated(); }
So when I run the program with the code line I inserted for debugging in the serviceDetailsDiscovered - slot
qDebug() << "service details discovered" << newState;
This code is called twice and the output is:
"service details discovered QLowEnergyService::DiscoveringServices
service details discovered QLowEnergyService::ServiceDiscovered"But as I can see, the slot is only called once in the code, when the state changes. So how is it possible, that the slot is executed twice although it is only called once? if I debug with a breakpoint, it is not working because only when main is executed to end the UI is shown up..
-
@SpaceToon said in Bluetooth Low Energy Scanner: Discover Service Details:
But as I can see, the slot is only called once in the code, when the state changes
That method is a slot. It is called every time
QLowEnergyService::stateChanged()
signal is emitted. In this case, visibly, it is emitted twice: first when discovery is started, then when a service was discovered. -
@sierdzio said in Bluetooth Low Energy Scanner: Discover Service Details:
@SpaceToon said in Bluetooth Low Energy Scanner: Discover Service Details:
But as I can see, the slot is only called once in the code, when the state changes
That method is a slot. It is called every time
QLowEnergyService::stateChanged()
signal is emitted. In this case, visibly, it is emitted twice: first when discovery is started, then when a service was discovered.Hey, thank you for your response. That makes sense. The problem is, that in my code, the method is only called once so that means, that the state "ServiceDiscovered" is not reached at all. Do you have any clue why? This is my code:
void Scanner::discoveryFinished(){ qDebug() << "\nService Discovery finished. Following Services found:\n"; QList<QBluetoothUuid> serviceList = controller->services(); QLowEnergyService *uartService = controller->createServiceObject(adafruitServiceUuid); connect(uartService, &QLowEnergyService::stateChanged, this, &Scanner::printChars); uartService->discoverDetails(); } void Scanner::printChars(QLowEnergyService::ServiceState newState){ auto service = qobject_cast<QLowEnergyService *>(sender()); const QList<QLowEnergyCharacteristic> chars = service->characteristics(); qDebug()<< chars.size(); for (const QLowEnergyCharacteristic &ch : chars) { qDebug() << &ch; } }
My Slot printChars is only called once so the chars.size() gives me 0. But Why the state is not changing to ServiceDiscovered so that I can print the characteristics?
-
It's possible that your service has already discovered all the details, and it is not searching anymore. https://doc.qt.io/qt-5/qlowenergyservice.html#ServiceState-enum
What is the returned
state
at this point? -
@sierdzio said in Bluetooth Low Energy Scanner: Discover Service Details:
It's possible that your service has already discovered all the details, and it is not searching anymore. https://doc.qt.io/qt-5/qlowenergyservice.html#ServiceState-enum
What is the returned
state
at this point?It is "DiscoveringServices" - so it is not done discovering the details but I do not know why.
When I run the Scanner example and chose my BLE device, the characteristics are shown normally. But when I execute my own written code, the state "QLowEnergyService::ServiceDiscovered" is not reached, so I think the problem is not my BLE device but something in my code. -
No idea.
But notice that the example code specifically does not call
characteristics()
method when state isDiscoveringServices
. Perhaps try doing the same? -
@sierdzio said in Bluetooth Low Energy Scanner: Discover Service Details:
No idea.
But notice that the example code specifically does not call
characteristics()
method when state isDiscoveringServices
. Perhaps try doing the same?I made a switch statement in my slot so if state is Discovering i should only print the state and if the state is "ServiceDiscovered" then it shoul call characteristics(). But as I mentioned, the state "ServiceDiscovered" is never reached.
-
i had same error in my project.
this page helped me -> https://forum.qt.io/topic/117241/why-qlowenergyservice-unknownerror/2i have changed my code from
connect(controller, &QLowEnergyController::discoveryFinished, this, &Device::serviceScanDone);
to
connect(controller, &QLowEnergyController::discoveryFinished, this, &Device::serviceScanDone,Qt::QueuedConnection);
and problem disappeared.