diff --git a/nuki/bluez/bluetoothgattcharacteristic.cpp b/nuki/bluez/bluetoothgattcharacteristic.cpp index 038f2485..69ccd658 100644 --- a/nuki/bluez/bluetoothgattcharacteristic.cpp +++ b/nuki/bluez/bluetoothgattcharacteristic.cpp @@ -72,6 +72,17 @@ QList BluetoothGattCharacteristic::descriptors() cons return m_descriptors; } +BluetoothGattDescriptor *BluetoothGattCharacteristic::getDescriptor(const QBluetoothUuid &desciptorUuid) const +{ + foreach (BluetoothGattDescriptor *descriptor, m_descriptors) { + if (descriptor->uuid() == desciptorUuid) { + return descriptor; + } + } + + return nullptr; +} + BluetoothGattCharacteristic::BluetoothGattCharacteristic(const QDBusObjectPath &path, const QVariantMap &properties, QObject *parent) : QObject(parent), m_path(path), diff --git a/nuki/bluez/bluetoothgattcharacteristic.h b/nuki/bluez/bluetoothgattcharacteristic.h index d935a61c..23c3a5ac 100644 --- a/nuki/bluez/bluetoothgattcharacteristic.h +++ b/nuki/bluez/bluetoothgattcharacteristic.h @@ -82,7 +82,7 @@ public: Properties properties() const; QByteArray value() const; QList descriptors() const; - + BluetoothGattDescriptor *getDescriptor(const QBluetoothUuid &desciptorUuid) const; private: explicit BluetoothGattCharacteristic(const QDBusObjectPath &path, const QVariantMap &properties, QObject *parent = 0); diff --git a/nuki/bluez/bluetoothgattdescriptor.cpp b/nuki/bluez/bluetoothgattdescriptor.cpp index 69a6dc05..bb59f32c 100644 --- a/nuki/bluez/bluetoothgattdescriptor.cpp +++ b/nuki/bluez/bluetoothgattdescriptor.cpp @@ -75,10 +75,17 @@ BluetoothGattDescriptor::BluetoothGattDescriptor(const QDBusObjectPath &path, co QDBusConnection::systemBus().connect(orgBluez, m_path.path(), "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList))); processProperties(properties); + +// QDBusPendingCall readingCall = m_descriptorInterface->asyncCall("GetAll", QVariantMap()); +// QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(readingCall, this); +// connect(watcher, &QDBusPendingCallWatcher::finished, this, [=](){ +// qCDebug(dcBluez()) << "Get descriptor properties finished"; +// }); } void BluetoothGattDescriptor::processProperties(const QVariantMap &properties) { + qCDebug(dcBluez()) << "Descriptor properties" << properties; foreach (const QString &propertyName, properties.keys()) { if (propertyName == "UUID") { m_uuid = QBluetoothUuid(properties.value(propertyName).toString()); diff --git a/nuki/nuki.cpp b/nuki/nuki.cpp index 7328ed85..30f3f946 100644 --- a/nuki/nuki.cpp +++ b/nuki/nuki.cpp @@ -150,9 +150,9 @@ void Nuki::printServices() foreach (BluetoothGattService *service, m_bluetoothDevice->services()) { qCDebug(dcNuki()) << service; foreach (BluetoothGattCharacteristic *characteristic, service->characteristics()) { - qCDebug(dcNuki()) << " " << characteristic->chararcteristicName() << characteristic->uuid().toString(); + qCDebug(dcNuki()) << " " << characteristic; foreach (BluetoothGattDescriptor *descriptor, characteristic->descriptors()) { - qCDebug(dcNuki()) << " " << descriptor->name() << descriptor->uuid().toString(); + qCDebug(dcNuki()) << " " << descriptor; } } } @@ -202,6 +202,45 @@ void Nuki::executeCurrentAction() } } +bool Nuki::enableNotificationsIndications(BluetoothGattCharacteristic *characteristic) +{ + qCDebug(dcNuki()) << "Start enable notifications/indications for" << characteristic; + + // Get the client configuration descriptor + // https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Descriptors/org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml + BluetoothGattDescriptor *clientConfiguration = characteristic->getDescriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + if (!clientConfiguration) { + qCWarning(dcNuki()) << "Could not start notification/indications for" << characteristic << "because the client configuration descriptor is missing"; + return false; + } + + qCDebug(dcNuki()) << "Enable notifications on" << characteristic; + if (!characteristic->startNotifications()) { + qCDebug(dcNuki()) << "Failed to start notifications on" << characteristic; + return false; + } + + if (characteristic->properties().testFlag(BluetoothGattCharacteristic::Indicate)) { + qCDebug(dcNuki()) << "Enable indications on" << characteristic; + QByteArray configuration; + QDataStream stream(&configuration, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(0x02); + if (!clientConfiguration->writeValue(configuration)) { + qCWarning(dcNuki()) << "Failed to write client configuration descriptor on" << characteristic; + return false; + } + + } else { + qCWarning(dcNuki()) << "Could not enable notifications. Access properties do not allow indicate or notify" << characteristic; + return false; + } + + clientConfiguration->readValue(); + + return true; +} + void Nuki::onBluetoothDeviceStateChanged(const BluetoothDevice::State &state) { qCDebug(dcNuki()) << m_bluetoothDevice << "state changed --> " << state; @@ -433,29 +472,36 @@ bool Nuki::init() qCWarning(dcNuki()) << "Could not find user data characteristc on device" << m_bluetoothDevice; return false; } + // Set key turner characteristics for data and user data if (!m_keyturnerService->hasCharacteristic(keyturnerDataCharacteristicUuid)) { qCWarning(dcNuki()) << "Could not find data characteristc on device" << m_bluetoothDevice; return false; } + + // Enable notifications/indications m_keyturnerUserDataCharacteristic = m_keyturnerService->getCharacteristic(keyturnerUserDataCharacteristicUuid); - if (!m_keyturnerUserDataCharacteristic->startNotifications()) { - qCWarning(dcNuki()) << "Could not enable notifications for user data characteristic."; + if (!enableNotificationsIndications(m_keyturnerUserDataCharacteristic)) { + qCWarning(dcNuki()) << "Could not enable notifications/indications for user data characteristic."; return false; } + m_keyturnerDataCharacteristic = m_keyturnerService->getCharacteristic(keyturnerDataCharacteristicUuid); - if (!m_keyturnerDataCharacteristic->startNotifications()) { - qCWarning(dcNuki()) << "Could not enable notifications for data characteristic."; + if (!enableNotificationsIndications(m_keyturnerDataCharacteristic)) { + qCWarning(dcNuki()) << "Could not enable notifications/indications for key turner data characteristic."; return false; } + + // Pairing service m_pairingService = m_bluetoothDevice->getService(pairingServiceUuid); if (!m_pairingService->hasCharacteristic(pairingDataCharacteristicUuid)) { qCWarning(dcNuki()) << "Could not find pairing data characteristc on device" << m_bluetoothDevice; return false; } + m_pairingDataCharacteristic = m_pairingService->getCharacteristic(pairingDataCharacteristicUuid); - if (!m_pairingDataCharacteristic->startNotifications()) { + if (!enableNotificationsIndications(m_pairingDataCharacteristic)) { qCWarning(dcNuki()) << "Could not enable notifications for pairing characteristic."; return false; } diff --git a/nuki/nuki.h b/nuki/nuki.h index 365f1e94..3754c647 100644 --- a/nuki/nuki.h +++ b/nuki/nuki.h @@ -115,6 +115,7 @@ private: void readDeviceInformationCharacteristics(); void executeCurrentAction(); + bool enableNotificationsIndications(BluetoothGattCharacteristic *characteristic); signals: void availableChanged(bool available);