From a004724b0fc035b0cde2be55f3db7583c30e6159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 25 Jan 2021 14:24:11 +0100 Subject: [PATCH 1/6] Try to enable also indications if possible with bluez version --- nuki/bluez/bluetoothgattcharacteristic.cpp | 11 ++++ nuki/bluez/bluetoothgattcharacteristic.h | 2 +- nuki/bluez/bluetoothgattdescriptor.cpp | 7 +++ nuki/nuki.cpp | 60 +++++++++++++++++++--- nuki/nuki.h | 1 + 5 files changed, 73 insertions(+), 8 deletions(-) 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); From 6f46c2c16a7fe250624cc89aab8175862b520b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 27 Jan 2021 14:17:55 +0100 Subject: [PATCH 2/6] Experiment with enable indication instead of notification --- nuki/bluez/bluetoothgattdescriptor.cpp | 4 +++- nuki/bluez/bluetoothmanager.cpp | 2 ++ nuki/nuki.cpp | 14 ++++++++------ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/nuki/bluez/bluetoothgattdescriptor.cpp b/nuki/bluez/bluetoothgattdescriptor.cpp index bb59f32c..35531c9a 100644 --- a/nuki/bluez/bluetoothgattdescriptor.cpp +++ b/nuki/bluez/bluetoothgattdescriptor.cpp @@ -76,6 +76,8 @@ BluetoothGattDescriptor::BluetoothGattDescriptor(const QDBusObjectPath &path, co processProperties(properties); + readValue(); + // QDBusPendingCall readingCall = m_descriptorInterface->asyncCall("GetAll", QVariantMap()); // QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(readingCall, this); // connect(watcher, &QDBusPendingCallWatcher::finished, this, [=](){ @@ -158,11 +160,11 @@ void BluetoothGattDescriptor::onReadingFinished(QDBusPendingCallWatcher *call) void BluetoothGattDescriptor::onWritingFinished(QDBusPendingCallWatcher *call) { + QByteArray value = m_asyncWrites.take(call); QDBusPendingReply reply = *call; if (reply.isError()) { qCWarning(dcBluez()) << "Could not write descriptor" << m_uuid.toString() << reply.error().name() << reply.error().message(); } else { - QByteArray value = m_asyncWrites.take(call); qCDebug(dcBluez()) << "Async descriptor writing finished for" << m_uuid.toString() << value; emit writingFinished(value); } diff --git a/nuki/bluez/bluetoothmanager.cpp b/nuki/bluez/bluetoothmanager.cpp index 7facc9d8..01d21df3 100644 --- a/nuki/bluez/bluetoothmanager.cpp +++ b/nuki/bluez/bluetoothmanager.cpp @@ -181,6 +181,7 @@ void BluetoothManager::processInterfaceList(const QDBusObjectPath &objectPath, c QDBusObjectPath serviceObjectPath = qvariant_cast(properties.value("Service")); BluetoothGattService *service = findService(serviceObjectPath); if (service) + qCDebug(dcBluez()) << "Add characteristic" << serviceObjectPath.path() << properties << service; service->addCharacteristicInternally(objectPath, properties); } @@ -196,6 +197,7 @@ void BluetoothManager::processInterfaceList(const QDBusObjectPath &objectPath, c QDBusObjectPath characterisitcObjectPath = qvariant_cast(properties.value("Characteristic")); BluetoothGattCharacteristic *characteristic = findCharacteristic(characterisitcObjectPath); if (characteristic) + qCDebug(dcBluez()) << "Add descriptor" << characterisitcObjectPath.path() << properties << characteristic; characteristic->addDescriptorInternally(objectPath, properties); } diff --git a/nuki/nuki.cpp b/nuki/nuki.cpp index 30f3f946..2ee562dc 100644 --- a/nuki/nuki.cpp +++ b/nuki/nuki.cpp @@ -214,18 +214,18 @@ bool Nuki::enableNotificationsIndications(BluetoothGattCharacteristic *character return false; } - qCDebug(dcNuki()) << "Enable notifications on" << characteristic; - if (!characteristic->startNotifications()) { - qCDebug(dcNuki()) << "Failed to start notifications on" << characteristic; - 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); + stream << static_cast(2); if (!clientConfiguration->writeValue(configuration)) { qCWarning(dcNuki()) << "Failed to write client configuration descriptor on" << characteristic; return false; @@ -590,6 +590,8 @@ void Nuki::setAvailable(bool available) if (m_available) { executeCurrentAction(); + + } else { // Finish any running actions finishCurrentAction(false); From c1da14fd55a317c8bda62083ae5ecc2ec763a810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 18 Mar 2021 10:37:27 +0100 Subject: [PATCH 3/6] Rework nuki to use indications --- nuki/bluez/bluetoothgattcharacteristic.cpp | 2 +- nuki/nuki.cpp | 63 ++------- nuki/nuki.h | 7 +- nuki/nukiauthenticator.cpp | 152 ++++++++------------- nuki/nukiauthenticator.h | 1 - nuki/nukicontroller.cpp | 147 ++++++++++++++------ nuki/nukicontroller.h | 8 ++ nuki/nukiutils.h | 8 +- 8 files changed, 197 insertions(+), 191 deletions(-) diff --git a/nuki/bluez/bluetoothgattcharacteristic.cpp b/nuki/bluez/bluetoothgattcharacteristic.cpp index 69ccd658..422bd246 100644 --- a/nuki/bluez/bluetoothgattcharacteristic.cpp +++ b/nuki/bluez/bluetoothgattcharacteristic.cpp @@ -336,7 +336,7 @@ QDebug operator<<(QDebug debug, BluetoothGattCharacteristic *characteristic) debug.noquote().nospace() << " B"; if (characteristic->properties().testFlag(BluetoothGattCharacteristic::Read)) - debug.noquote().nospace() << " R "; + debug.noquote().nospace() << " R"; if (characteristic->properties().testFlag(BluetoothGattCharacteristic::WriteNoResponse)) debug.noquote().nospace() << " WNR"; diff --git a/nuki/nuki.cpp b/nuki/nuki.cpp index 2ee562dc..1c5cef66 100644 --- a/nuki/nuki.cpp +++ b/nuki/nuki.cpp @@ -37,13 +37,6 @@ #include #include -static QBluetoothUuid initializationServiceUuid = QBluetoothUuid(QUuid("a92ee000-5501-11e4-916c-0800200c9a66")); -static QBluetoothUuid pairingServiceUuid = QBluetoothUuid(QUuid("a92ee100-5501-11e4-916c-0800200c9a66")); -static QBluetoothUuid pairingDataCharacteristicUuid = QBluetoothUuid(QUuid("a92ee101-5501-11e4-916c-0800200c9a66")); -static QBluetoothUuid keyturnerServiceUuid = QBluetoothUuid(QUuid("a92ee200-5501-11e4-916c-0800200c9a66")); -static QBluetoothUuid keyturnerDataCharacteristicUuid = QBluetoothUuid(QUuid("a92ee201-5501-11e4-916c-0800200c9a66")); -static QBluetoothUuid keyturnerUserDataCharacteristicUuid = QBluetoothUuid(QUuid("a92ee202-5501-11e4-916c-0800200c9a66")); - Nuki::Nuki(Thing *thing, BluetoothDevice *bluetoothDevice, QObject *parent) : QObject(parent), m_thing(thing), @@ -204,40 +197,12 @@ 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"; + qCDebug(dcNuki()) << "Enable notifications on" << characteristic; + if (!characteristic->startNotifications()) { + qCDebug(dcNuki()) << "Failed to start notifications on" << characteristic; 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(2); - 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; } @@ -451,12 +416,12 @@ bool Nuki::init() return false; } - if (!m_bluetoothDevice->hasService(pairingServiceUuid)) { + if (!m_bluetoothDevice->hasService(pairingServiceUuid())) { qCWarning(dcNuki()) << "Could not find pairing service on device" << m_bluetoothDevice; return false; } - if (!m_bluetoothDevice->hasService(keyturnerServiceUuid)) { + if (!m_bluetoothDevice->hasService(keyturnerServiceUuid())) { qCWarning(dcNuki()) << "Could not find key turner service on device" << m_bluetoothDevice; return false; } @@ -467,25 +432,25 @@ bool Nuki::init() connect(m_deviceInformationService, &BluetoothGattService::characteristicReadFinished, this, &Nuki::onDeviceInfoCharacteristicReadFinished); // Keyturner service - m_keyturnerService = m_bluetoothDevice->getService(keyturnerServiceUuid); - if (!m_keyturnerService->hasCharacteristic(keyturnerUserDataCharacteristicUuid)) { + m_keyturnerService = m_bluetoothDevice->getService(keyturnerServiceUuid()); + if (!m_keyturnerService->hasCharacteristic(keyturnerUserDataCharacteristicUuid())) { 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)) { + 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); + m_keyturnerUserDataCharacteristic = m_keyturnerService->getCharacteristic(keyturnerUserDataCharacteristicUuid()); if (!enableNotificationsIndications(m_keyturnerUserDataCharacteristic)) { qCWarning(dcNuki()) << "Could not enable notifications/indications for user data characteristic."; return false; } - m_keyturnerDataCharacteristic = m_keyturnerService->getCharacteristic(keyturnerDataCharacteristicUuid); + m_keyturnerDataCharacteristic = m_keyturnerService->getCharacteristic(keyturnerDataCharacteristicUuid()); if (!enableNotificationsIndications(m_keyturnerDataCharacteristic)) { qCWarning(dcNuki()) << "Could not enable notifications/indications for key turner data characteristic."; return false; @@ -494,13 +459,13 @@ bool Nuki::init() // Pairing service - m_pairingService = m_bluetoothDevice->getService(pairingServiceUuid); - if (!m_pairingService->hasCharacteristic(pairingDataCharacteristicUuid)) { + 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); + m_pairingDataCharacteristic = m_pairingService->getCharacteristic(pairingDataCharacteristicUuid()); if (!enableNotificationsIndications(m_pairingDataCharacteristic)) { qCWarning(dcNuki()) << "Could not enable notifications for pairing characteristic."; return false; @@ -590,8 +555,6 @@ void Nuki::setAvailable(bool available) if (m_available) { executeCurrentAction(); - - } else { // Finish any running actions finishCurrentAction(false); diff --git a/nuki/nuki.h b/nuki/nuki.h index 3754c647..8d664260 100644 --- a/nuki/nuki.h +++ b/nuki/nuki.h @@ -50,7 +50,6 @@ class Nuki : public QObject { - Q_OBJECT public: @@ -78,6 +77,12 @@ public: void clearSettings(); + static QBluetoothUuid initializationServiceUuid() { return QBluetoothUuid(QUuid("a92ee000-5501-11e4-916c-0800200c9a66")); } + static QBluetoothUuid pairingServiceUuid() { return QBluetoothUuid(QUuid("a92ee100-5501-11e4-916c-0800200c9a66")); } + static QBluetoothUuid pairingDataCharacteristicUuid() { return QBluetoothUuid(QUuid("a92ee101-5501-11e4-916c-0800200c9a66")); } + static QBluetoothUuid keyturnerServiceUuid() { return QBluetoothUuid(QUuid("a92ee200-5501-11e4-916c-0800200c9a66")); } + static QBluetoothUuid keyturnerDataCharacteristicUuid() { return QBluetoothUuid(QUuid("a92ee201-5501-11e4-916c-0800200c9a66")); } + static QBluetoothUuid keyturnerUserDataCharacteristicUuid() { return QBluetoothUuid(QUuid("a92ee202-5501-11e4-916c-0800200c9a66")); } private: Thing *m_thing = nullptr; diff --git a/nuki/nukiauthenticator.cpp b/nuki/nukiauthenticator.cpp index fed0ae8d..cbbd2a6f 100644 --- a/nuki/nukiauthenticator.cpp +++ b/nuki/nukiauthenticator.cpp @@ -58,6 +58,7 @@ NukiAuthenticator::NukiAuthenticator(const QBluetoothHostInfo &hostInfo, Bluetoo // Check if we have authentication data for this thing and set initial state loadData(); if (isValid()) { + qCDebug(dcNuki()) << "Found valid authroization data for" << hostInfo.address().toString(); setState(AuthenticationStateAuthenticated); } else { setState(AuthenticationStateUnauthenticated); @@ -81,7 +82,7 @@ bool NukiAuthenticator::isValid() const return !m_privateKey.isEmpty() && !m_publicKey.isEmpty() && !m_publicKeyNuki.isEmpty() && - !m_authorizationId == 0 && + m_authorizationId != 0 && !m_authorizationIdRawData.isEmpty() && !m_uuid.isEmpty(); } @@ -208,7 +209,6 @@ void NukiAuthenticator::setState(NukiAuthenticator::AuthenticationState state) switch (m_state) { case AuthenticationStateUnauthenticated: - resetExpectedData(); break; case AuthenticationStateAuthenticated: qCDebug(dcNuki()) << "Device" << m_hostInfo.address().toString() << "authenticated."; @@ -218,47 +218,37 @@ void NukiAuthenticator::setState(NukiAuthenticator::AuthenticationState state) if (m_debug) qCDebug(dcNuki()) << " Authorization ID:" << NukiUtils::convertByteArrayToHexStringCompact(m_authorizationIdRawData) << m_authorizationId; break; case AuthenticationStateRequestPublicKey: - resetExpectedData(NukiUtils::CommandPublicKey, 2); requestPublicKey(); break; case AuthenticationStateGenerateKeyPair: - resetExpectedData(); generateKeyPair(); setState(AuthenticationStateSendPublicKey); break; case AuthenticationStateSendPublicKey: - resetExpectedData(NukiUtils::CommandChallenge, 2); sendPublicKey(); setState(AuthenticationStateReadChallenge); break; case AuthenticationStateReadChallenge: - resetExpectedData(NukiUtils::CommandChallenge, 2); break; case AuthenticationStateAutorization: sendAuthorizationAuthenticator(); setState(AuthenticationStateReadSecondChallenge); break; case AuthenticationStateReadSecondChallenge: - resetExpectedData(NukiUtils::CommandChallenge, 2); break; case AuthenticationStateAuthenticateData: - resetExpectedData(); sendAuthenticateData(); setState(AuthenticationStateAuthorizationId); break; case AuthenticationStateAuthorizationId: - resetExpectedData(NukiUtils::CommandAuthorizationId, 5); break; case AuthenticationStateAuthorizationIdConfirm: - resetExpectedData(); sendAuthoizationIdConfirm(); setState(AuthenticationStateStatus); break; case AuthenticationStateStatus: - resetExpectedData(NukiUtils::CommandStatus); break; case AuthenticationStateError: - resetExpectedData(); emit errorOccured(m_error); emit authenticationProcessFinished(false); break; @@ -268,14 +258,6 @@ void NukiAuthenticator::setState(NukiAuthenticator::AuthenticationState state) } } -void NukiAuthenticator::resetExpectedData(NukiUtils::Command command, int expectedCount) -{ - m_currentReceivingCommand = command; - m_currentReceivingCurrentCount = 0; - m_currentReceivingExpectedCount = expectedCount; - m_currentReceivingData.clear(); -} - bool NukiAuthenticator::createAuthenticator(const QByteArray content) { // Create shared key @@ -469,7 +451,6 @@ void NukiAuthenticator::loadData() void NukiAuthenticator::onPairingDataCharacteristicChanged(const QByteArray &value) { - if (m_debug) qCDebug(dcNuki()) << "Authenticator data received: <--" << NukiUtils::convertByteArrayToHexStringCompact(value); // Process pairing characteristic data QByteArray data = QByteArray(value); @@ -478,12 +459,9 @@ void NukiAuthenticator::onPairingDataCharacteristicChanged(const QByteArray &val quint16 command; stream >> command; - // Check if we are collecting data for multi part notification - if (m_currentReceivingCurrentCount > 0) { - command = m_currentReceivingCommand; - } + m_currentReceivingData = value; - if (m_debug) qCDebug(dcNuki()) << static_cast(command); + if (m_debug) qCDebug(dcNuki()) << "Authenticator data received: <--" << static_cast(command) << "|" << NukiUtils::convertByteArrayToHexStringCompact(value); switch (command) { case NukiUtils::CommandErrorReport: @@ -500,81 +478,70 @@ void NukiAuthenticator::onPairingDataCharacteristicChanged(const QByteArray &val setState(AuthenticationStateError); break; case NukiUtils::CommandPublicKey: - m_currentReceivingCurrentCount++; - m_currentReceivingData.append(value); - if (m_currentReceivingCurrentCount == m_currentReceivingExpectedCount) { - if (!NukiUtils::validateMessageCrc(m_currentReceivingData)) { - qCWarning(dcNuki()) << "Invalid CRC CCITT value for public key message."; - // FIXME: check what to do if crc is invalid - } - - qCDebug(dcNuki()) << "Authenticator: Nuki public key message received" << (m_debug ? NukiUtils::convertByteArrayToHexStringCompact(m_currentReceivingData) : ""); - m_publicKeyNuki = m_currentReceivingData.mid(2, 32); - if (m_debug) qCDebug(dcNuki()) << "Authenticator: --> Nuki public key:" << NukiUtils::convertByteArrayToHexStringCompact(m_publicKeyNuki); - - setState(AuthenticationStateGenerateKeyPair); + if (!NukiUtils::validateMessageCrc(m_currentReceivingData)) { + qCWarning(dcNuki()) << "Invalid CRC CCITT value for public key message."; + // FIXME: check what to do if crc is invalid } + + qCDebug(dcNuki()) << "Authenticator: Nuki public key message received" << (m_debug ? NukiUtils::convertByteArrayToHexStringCompact(m_currentReceivingData) : ""); + m_publicKeyNuki = m_currentReceivingData.mid(2, 32); + if (m_debug) qCDebug(dcNuki()) << "Authenticator: --> Nuki public key:" << NukiUtils::convertByteArrayToHexStringCompact(m_publicKeyNuki); + + setState(AuthenticationStateGenerateKeyPair); break; case NukiUtils::CommandChallenge: - m_currentReceivingCurrentCount++; - m_currentReceivingData.append(value); - if (m_currentReceivingCurrentCount == m_currentReceivingExpectedCount) { - qCDebug(dcNuki()) << "Authenticator: Nuki challenge message received" << (m_debug ? NukiUtils::convertByteArrayToHexStringCompact(m_currentReceivingData) : ""); - if (!NukiUtils::validateMessageCrc(m_currentReceivingData)) { - qCWarning(dcNuki()) << "Invalid CRC CCITT value for challenge message."; - // FIXME: check what to do if crc is invalid - } + qCDebug(dcNuki()) << "Authenticator: Nuki challenge message received" << (m_debug ? NukiUtils::convertByteArrayToHexStringCompact(m_currentReceivingData) : ""); + if (!NukiUtils::validateMessageCrc(m_currentReceivingData)) { + qCWarning(dcNuki()) << "Invalid CRC CCITT value for challenge message."; + // FIXME: check what to do if crc is invalid + } - m_nonceNuki = m_currentReceivingData.mid(2, 32); - if (m_debug) qCDebug(dcNuki()) << "Authenticator: --> Nuki nonce:" << NukiUtils::convertByteArrayToHexStringCompact(m_nonceNuki); - // Check if this was from the first challenge read or the second - if (m_state == AuthenticationStateReadChallenge) { - setState(AuthenticationStateAutorization); - } else if (m_state == AuthenticationStateReadSecondChallenge) { - setState(AuthenticationStateAuthenticateData); - } else { - qCWarning(dcNuki()) << "Received a challenge without expecting one."; - setState(AuthenticationStateError); - } + m_nonceNuki = m_currentReceivingData.mid(2, 32); + if (m_debug) qCDebug(dcNuki()) << "Authenticator: --> Nuki nonce:" << NukiUtils::convertByteArrayToHexStringCompact(m_nonceNuki); + // Check if this was from the first challenge read or the second + if (m_state == AuthenticationStateReadChallenge) { + setState(AuthenticationStateAutorization); + } else if (m_state == AuthenticationStateReadSecondChallenge) { + setState(AuthenticationStateAuthenticateData); + } else { + qCWarning(dcNuki()) << "Received a challenge without expecting one."; + setState(AuthenticationStateError); } break; - case NukiUtils::CommandAuthorizationId: - m_currentReceivingCurrentCount++; - m_currentReceivingData.append(value); - if (m_currentReceivingCurrentCount == m_currentReceivingExpectedCount) { - qCDebug(dcNuki()) << "Authenticator: Nuki authorization ID message received" << (m_debug ? NukiUtils::convertByteArrayToHexStringCompact(m_currentReceivingData) : ""); + case NukiUtils::CommandAuthorizationId: { + qCDebug(dcNuki()) << "Authenticator: Nuki authorization ID message received" << (m_debug ? NukiUtils::convertByteArrayToHexStringCompact(m_currentReceivingData) : ""); - if (!NukiUtils::validateMessageCrc(m_currentReceivingData)) { - qCWarning(dcNuki()) << "Invalid CRC CCITT value for challenge message."; - // FIXME: check what to do if crc is invalid - } - - // Parse data - QByteArray message = m_currentReceivingData.mid(2, m_currentReceivingData.count() - 4); - QByteArray authenticator = message.left(32); - Q_ASSERT_X(authenticator.count() == 32, "data length", "Nuki nonce has not the correct length."); - - // Read authorization ID - m_authorizationIdRawData = message.mid(32, 4); - QDataStream stream(&m_authorizationIdRawData, QIODevice::ReadOnly); - stream.setByteOrder(QDataStream::LittleEndian); - stream >> m_authorizationId; - - m_uuid = message.mid(36, 16); - Q_ASSERT_X(m_uuid.count() == 16, "data length", "UUIS has not the correct length."); - - m_nonceNuki = message.mid(52, 32); - Q_ASSERT_X(m_nonceNuki.count() == 32, "data length", "Nuki nonce has not the correct length."); - - if (m_debug) qCDebug(dcNuki()) << " Full message :" << NukiUtils::convertByteArrayToHexStringCompact(message); - if (m_debug) qCDebug(dcNuki()) << " Authenticator :" << NukiUtils::convertByteArrayToHexStringCompact(authenticator); - if (m_debug) qCDebug(dcNuki()) << " Authorization ID:" << NukiUtils::convertByteArrayToHexStringCompact(m_authorizationIdRawData) << m_authorizationId; - if (m_debug) qCDebug(dcNuki()) << " UUID data :" << NukiUtils::convertByteArrayToHexStringCompact(m_uuid); - if (m_debug) qCDebug(dcNuki()) << " Nuki nonce :" << NukiUtils::convertByteArrayToHexStringCompact(m_nonceNuki); - - setState(AuthenticationStateAuthorizationIdConfirm); + if (!NukiUtils::validateMessageCrc(m_currentReceivingData)) { + qCWarning(dcNuki()) << "Invalid CRC CCITT value for challenge message."; + // FIXME: check what to do if crc is invalid } + + // Parse data + QByteArray message = m_currentReceivingData.mid(2, m_currentReceivingData.count() - 4); + QByteArray authenticator = message.left(32); + Q_ASSERT_X(authenticator.count() == 32, "data length", "Nuki nonce has not the correct length."); + + // Read authorization ID + m_authorizationIdRawData = message.mid(32, 4); + QDataStream stream(&m_authorizationIdRawData, QIODevice::ReadOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream >> m_authorizationId; + + m_uuid = message.mid(36, 16); + Q_ASSERT_X(m_uuid.count() == 16, "data length", "UUID has not the correct length."); + + m_nonceNuki = message.mid(52, 32); + Q_ASSERT_X(m_nonceNuki.count() == 32, "data length", "Nuki nonce has not the correct length."); + + if (m_debug) qCDebug(dcNuki()) << " Full message :" << NukiUtils::convertByteArrayToHexStringCompact(message); + if (m_debug) qCDebug(dcNuki()) << " Authenticator :" << NukiUtils::convertByteArrayToHexStringCompact(authenticator); + if (m_debug) qCDebug(dcNuki()) << " Authorization ID:" << NukiUtils::convertByteArrayToHexStringCompact(m_authorizationIdRawData) << m_authorizationId; + if (m_debug) qCDebug(dcNuki()) << " UUID data :" << NukiUtils::convertByteArrayToHexStringCompact(m_uuid); + if (m_debug) qCDebug(dcNuki()) << " Nuki nonce :" << NukiUtils::convertByteArrayToHexStringCompact(m_nonceNuki); + + setState(AuthenticationStateAuthorizationIdConfirm); break; + } case NukiUtils::CommandStatus: { quint8 status; stream >> status; @@ -604,7 +571,6 @@ void NukiAuthenticator::onPairingDataCharacteristicChanged(const QByteArray &val } default: qCWarning(dcNuki()) << "Authenticator: Unhandled command identifier for parining charateristic" << NukiUtils::convertUint16ToHexString(command); - resetExpectedData(); break; } } diff --git a/nuki/nukiauthenticator.h b/nuki/nukiauthenticator.h index 679489bc..740d7e02 100644 --- a/nuki/nukiauthenticator.h +++ b/nuki/nukiauthenticator.h @@ -110,7 +110,6 @@ private: // State machine void setState(AuthenticationState state); - void resetExpectedData(NukiUtils::Command command = NukiUtils::CommandRequestData, int expectedCount = 1); // Helper methods bool createAuthenticator(const QByteArray content); diff --git a/nuki/nukicontroller.cpp b/nuki/nukicontroller.cpp index 21ffde80..895f6dad 100644 --- a/nuki/nukicontroller.cpp +++ b/nuki/nukicontroller.cpp @@ -88,6 +88,23 @@ bool NukiController::readLockState() return true; } +bool NukiController::readConfiguration() +{ + if (m_state != NukiControllerStateIdle) { + // TODO: maybe queue commands + qCWarning(dcNuki()) << "Controller: Could not read lock state, Nuki is currenty busy"; + return false; + } + + if (!m_nukiAuthenticator->isValid()) { + qCWarning(dcNuki()) << "Invalid authenticator. Please authenticate the thing first."; + return false; + } + + setState(NukiControllerStateReadingConfiguration); + return true; +} + bool NukiController::lock() { if (m_state != NukiControllerStateIdle) { @@ -154,6 +171,15 @@ void NukiController::setState(NukiController::NukiControllerState state) case NukiControllerStateReadingLockStates: sendReadLockStateRequest(); break; + case NukiControllerStateReadingConfigurationRequestChallange: + sendRequestChallengeRequest(); + break; + case NukiControllerStateReadingConfigurationExecute: + sendReadConfigurationRequest(); + setState(NukiControllerStateReadingConfiguration); + break; + case NukiControllerStateReadingConfiguration: + break; case NukiControllerStateLockActionRequestChallange: sendRequestChallengeRequest(); break; @@ -235,6 +261,12 @@ void NukiController::processNukiStatesData(const QByteArray &data) emit nukiStatesChanged(); } +void NukiController::processNukiConfigData(const QByteArray &data) +{ + qCDebug(dcNuki()) << "Processing config data from nuki" << data; + +} + void NukiController::processNukiErrorReport(const QByteArray &data) { qint8 errorCode; @@ -280,6 +312,20 @@ void NukiController::processUserDataNotification(const QByteArray nonce, quint32 if (command == NukiUtils::CommandNukiStates) { processNukiStatesData(payload); emit readNukiStatesFinished(true); + setState(NukiControllerStateReadingConfigurationRequestChallange); + return; + } + break; + case NukiControllerStateReadingConfigurationRequestChallange: + if (command == NukiUtils::CommandChallenge) { + m_nukiNonce = payload; + setState(NukiControllerStateReadingConfigurationExecute); + return; + } + break; + case NukiControllerStateReadingConfiguration: + if (command == NukiUtils::CommandConfig) { + processNukiConfigData(payload); setState(NukiControllerStateIdle); return; } @@ -424,6 +470,45 @@ void NukiController::sendReadLockStateRequest() m_userDataCharacteristic->writeCharacteristic(message); } +void NukiController::sendReadConfigurationRequest() +{ + qCDebug(dcNuki()) << "Controller: Reading configurations"; + + // Create data for encryption + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(NukiUtils::CommandRequestConfig); + for (int i = 0; i < m_nukiNonce.length(); i++) { + stream << static_cast(m_nukiNonce.at(i)); + } + + // Create unencrypted PDATA + QByteArray unencryptedMessage = NukiUtils::createRequestMessageForUnencryptedForEncryption(m_nukiAuthenticator->authorizationId(), NukiUtils::CommandRequestData, payload); + + // Encrypt PDATA + QByteArray nonce = m_nukiAuthenticator->generateNonce(crypto_box_NONCEBYTES); + QByteArray encryptedMessage = m_nukiAuthenticator->encryptData(unencryptedMessage, nonce); + + // Create ADATA + QByteArray header; + header.append(nonce); + header.append(m_nukiAuthenticator->authorizationIdRawData()); + header.append(NukiUtils::converUint16ToByteArrayLittleEndian(static_cast(encryptedMessage.length()))); + + // Message ADATA + PDATA + QByteArray message; + message.append(header); + message.append(encryptedMessage); + + // Send data + qCDebug(dcNuki()) << "Controller: Sending get config request"; + if (m_debug) qCDebug(dcNuki()) << " Nonce :" << NukiUtils::convertByteArrayToHexStringCompact(nonce); + if (m_debug) qCDebug(dcNuki()) << " Header :" << NukiUtils::convertByteArrayToHexStringCompact(header); + if (m_debug) qCDebug(dcNuki()) << "Controller: -->" << NukiUtils::convertByteArrayToHexStringCompact(message); + m_userDataCharacteristic->writeCharacteristic(message); +} + void NukiController::sendRequestChallengeRequest() { qCDebug(dcNuki()) << "Controller: Request challenge"; @@ -508,47 +593,27 @@ void NukiController::onUserDataCharacteristicChanged(const QByteArray &value) { if (m_debug) qCDebug(dcNuki()) << "Controller: Data received: <--" << NukiUtils::convertByteArrayToHexStringCompact(value); - if (m_messageBufferCounter <= 0) { - // New data arrived - m_messageBuffer.append(value); - m_messageBufferCounter++; - } else { - // We are currently collecting - m_messageBuffer.append(value); - m_messageBufferCounter++; + m_messageBuffer = value; - // In the second buffer message is the complete message length - if (m_messageBufferCounter == 2) { - if (m_messageBuffer.count() < 30) { - qCWarning(dcNuki()) << "Controller: Cannot understand message. Rejecting."; - resetMessageBuffer(); - return; - } - - // Parse message length - // ADATA: 24 byte nonce, 4 byte autorization, 2 byte encrypted message length - m_messageBufferAData = m_messageBuffer.left(30); - m_messageBufferPData = m_messageBuffer.right(m_messageBuffer.count() - 30); - - m_messageBufferNonce = m_messageBufferAData.left(24); - QByteArray messageInformation = m_messageBufferAData.right(6); - - QDataStream stream(&messageInformation, QIODevice::ReadOnly); - stream.setByteOrder(QDataStream::LittleEndian); - stream >> m_messageBufferIdentifier >> m_messageBufferLength; - if (m_messageBufferPData.count() == m_messageBufferLength) { - processUserDataNotification(m_messageBufferNonce, m_messageBufferIdentifier, m_messageBufferPData); - resetMessageBuffer(); - } - - } else { - // We already know the message length and are still collecting p data - m_messageBufferPData.append(value); - if (m_messageBufferPData.count() == m_messageBufferLength) { - // Message finished - processUserDataNotification(m_messageBufferNonce, m_messageBufferIdentifier, m_messageBufferPData); - resetMessageBuffer(); - } - } + if (m_messageBuffer.count() < 30) { + qCWarning(dcNuki()) << "Controller: Cannot understand message. Rejecting."; + resetMessageBuffer(); + return; } + + // Parse message length + // ADATA: 24 byte nonce, 4 byte autorization, 2 byte encrypted message length + m_messageBufferAData = m_messageBuffer.left(30); + m_messageBufferPData = m_messageBuffer.right(m_messageBuffer.count() - 30); + m_messageBufferNonce = m_messageBufferAData.left(24); + QByteArray messageInformation = m_messageBufferAData.right(6); + + QDataStream stream(&messageInformation, QIODevice::ReadOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream >> m_messageBufferIdentifier >> m_messageBufferLength; + if (m_messageBufferPData.count() == m_messageBufferLength) { + processUserDataNotification(m_messageBufferNonce, m_messageBufferIdentifier, m_messageBufferPData); + resetMessageBuffer(); + } + } diff --git a/nuki/nukicontroller.h b/nuki/nukicontroller.h index ebc4b37f..2414f60f 100644 --- a/nuki/nukicontroller.h +++ b/nuki/nukicontroller.h @@ -49,6 +49,11 @@ public: // Read state NukiControllerStateReadingLockStates, + // Read configuration + NukiControllerStateReadingConfigurationRequestChallange, + NukiControllerStateReadingConfigurationExecute, + NukiControllerStateReadingConfiguration, + // Lock action NukiControllerStateLockActionRequestChallange, NukiControllerStateLockActionExecute, @@ -80,6 +85,7 @@ public: // Actions bool readLockState(); + bool readConfiguration(); bool lock(); bool unlock(); bool unlatch(); @@ -119,11 +125,13 @@ private: // Data processors void processNukiStatesData(const QByteArray &data); + void processNukiConfigData(const QByteArray &data); void processNukiErrorReport(const QByteArray &data); void processUserDataNotification(const QByteArray nonce, quint32 authorizationIdentifier, const QByteArray &privateData); // State action methods void sendReadLockStateRequest(); + void sendReadConfigurationRequest(); void sendRequestChallengeRequest(); void sendLockActionRequest(NukiUtils::LockAction lockAction, quint8 flag = 0); diff --git a/nuki/nukiutils.h b/nuki/nukiutils.h index 315c911e..1abf36c1 100644 --- a/nuki/nukiutils.h +++ b/nuki/nukiutils.h @@ -143,9 +143,9 @@ public: CommandOpeningsClosingsSummary = 0x0010, CommandBatteryReport = 0x0011, CommandErrorReport = 0x0012, - CommandSetConG = 0x0013, - CommandRequestConG = 0x0014, - CommandConG = 0x0015, + CommandSetConfig = 0x0013, + CommandRequestConfig = 0x0014, + CommandConfig = 0x0015, CommandSetSecurityPIN = 0x0019, CommandRequestCalibration = 0x001A, CommandRequestReboot = 0x001D, @@ -190,7 +190,7 @@ public: // Message helper static QByteArray createRequestMessageForUnencrypted(NukiUtils::Command command, const QByteArray &payload); - static QByteArray createRequestMessageForUnencryptedForEncryption(quint32 authenticationId, NukiUtils::Command command, const QByteArray &payload); + static QByteArray createRequestMessageForUnencryptedForEncryption(quint32 authenticationId, NukiUtils::Command command, const QByteArray &payload = QByteArray()); }; From 7b1b5620e11bb9f8f0f10fce866fbea3777a9484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 22 Mar 2021 09:53:30 +0100 Subject: [PATCH 4/6] Clean up if setup failes for nuki --- nuki/integrationpluginnuki.cpp | 77 +++++++++++++++++----------------- nuki/integrationpluginnuki.h | 4 -- nuki/nuki.cpp | 1 + nuki/nukicontroller.cpp | 3 +- 4 files changed, 42 insertions(+), 43 deletions(-) diff --git a/nuki/integrationpluginnuki.cpp b/nuki/integrationpluginnuki.cpp index 203ddb34..cf0ff92f 100644 --- a/nuki/integrationpluginnuki.cpp +++ b/nuki/integrationpluginnuki.cpp @@ -129,7 +129,6 @@ void IntegrationPluginNuki::discoverThings(ThingDiscoveryInfo *info) m_bluetoothAdapter->startDiscovering(); QTimer::singleShot(5000, info, [this, info]() { onBluetoothDiscoveryFinished(info); }); - } void IntegrationPluginNuki::startPairing(ThingPairingInfo *info) @@ -159,14 +158,48 @@ void IntegrationPluginNuki::confirmPairing(ThingPairingInfo *info, const QString return info->finish(Thing::ThingErrorThingNotFound); } + // Create a temporary nuki for authentication BluetoothDevice *bluetoothDevice = m_bluetoothAdapter->getDevice(address); - m_asyncSetupNuki = new Nuki(nullptr, bluetoothDevice, this); - connect(m_asyncSetupNuki, &Nuki::authenticationProcessFinished, this, &IntegrationPluginNuki::onNukiAuthenticationProcessFinished); - connect(m_asyncSetupNuki, &Nuki::availableChanged, this, &IntegrationPluginNuki::onAsyncSetupNukiAvailableChanged); + connect(m_asyncSetupNuki, &Nuki::authenticationProcessFinished, this, [=](const PairingTransactionId &pairingId, bool success){ + if (m_asyncSetupNuki) { + qCDebug(dcNuki()) << "Deleting the temporary pairing device"; + m_asyncSetupNuki->deleteLater(); + m_asyncSetupNuki = nullptr; + } + + if (!m_pairingInfo) { + qCWarning(dcNuki()) << "Authentication process finished, but have not valid pairing translaction id"; + return; + } + + if (m_pairingInfo->transactionId() != pairingId) { + qCWarning(dcNuki()) << "Authentication process finished, but have not valid pairing translaction id"; + return; + } + + m_pairingInfo->finish(success ? Thing::ThingErrorNoError : Thing::ThingErrorHardwareFailure); + m_pairingInfo = nullptr; + }); + + connect(m_asyncSetupNuki, &Nuki::availableChanged, this, [=](bool available){ + // Remove possibly running Nuki setup devices on disconnected + if (m_asyncSetupNuki && !available) { + qCDebug(dcNuki()) << "Deleting the temporary pairing device"; + m_asyncSetupNuki->deleteLater(); + m_asyncSetupNuki = nullptr; + + // Lost connection during authentication + if (m_pairingInfo) { + qCWarning(dcNuki()) << "Device disconnected during pairing."; + m_pairingInfo->finish(Thing::ThingErrorHardwareFailure); + m_pairingInfo = nullptr; + } + } + }); - m_asyncSetupNuki->startAuthenticationProcess(info->transactionId()); m_pairingInfo = info; + m_asyncSetupNuki->startAuthenticationProcess(info->transactionId()); connect(info, &ThingPairingInfo::destroyed, this, [this] { m_pairingInfo = nullptr; }); } @@ -225,7 +258,7 @@ void IntegrationPluginNuki::thingRemoved(Thing *thing) Nuki *nuki = m_nukiDevices.key(thing); nuki->clearSettings(); - // FIXME: deauthenticate nymea from nuki thing + // TODO: deauthenticate nymea from nuki qCDebug(dcNuki()) << "Delete pairing information from bluez" << nuki->bluetoothDevice(); m_bluetoothAdapter->removeDevice(nuki->bluetoothDevice()->address()); @@ -298,35 +331,3 @@ void IntegrationPluginNuki::onBluetoothDiscoveryFinished(ThingDiscoveryInfo *inf info->finish(Thing::ThingErrorNoError); } - -void IntegrationPluginNuki::onAsyncSetupNukiAvailableChanged(bool available) -{ - // Remove possibly running Nuki setup devices on disconnected - if (!available && m_asyncSetupNuki) { - qCDebug(dcNuki()) << "Deleting the temporary pairing device"; - m_asyncSetupNuki->deleteLater(); - m_asyncSetupNuki = nullptr; - } -} - -void IntegrationPluginNuki::onNukiAuthenticationProcessFinished(const PairingTransactionId &pairingTransactionId, bool success) -{ - if (m_asyncSetupNuki) { - qCDebug(dcNuki()) << "Deleting the temporary pairing device"; - m_asyncSetupNuki->deleteLater(); - m_asyncSetupNuki = nullptr; - } - - if (!m_pairingInfo) { - qCWarning(dcNuki()) << "Authentication process finished, but have not valid pairing translaction id"; - return; - } - - if (m_pairingInfo->transactionId() != pairingTransactionId) { - qCWarning(dcNuki()) << "Authentication process finished, but have not valid pairing translaction id"; - return; - } - - m_pairingInfo->finish(success ? Thing::ThingErrorNoError : Thing::ThingErrorHardwareFailure); - m_pairingInfo = nullptr; -} diff --git a/nuki/integrationpluginnuki.h b/nuki/integrationpluginnuki.h index 27e6a719..08dcf05d 100644 --- a/nuki/integrationpluginnuki.h +++ b/nuki/integrationpluginnuki.h @@ -76,10 +76,6 @@ private slots: void onBluetoothEnabledChanged(const bool &enabled); void onBluetoothDiscoveryFinished(ThingDiscoveryInfo *info); - void onAsyncSetupNukiAvailableChanged(bool available); - - void onNukiAuthenticationProcessFinished(const PairingTransactionId &pairingTransactionId, bool success); - }; #endif // INTEGRATIONPLUGINNUKI_H diff --git a/nuki/nuki.cpp b/nuki/nuki.cpp index 1c5cef66..6c7d7390 100644 --- a/nuki/nuki.cpp +++ b/nuki/nuki.cpp @@ -153,6 +153,7 @@ void Nuki::printServices() void Nuki::readDeviceInformationCharacteristics() { + qCDebug(dcNuki()) << "Start reading device information"; m_initUuidsToRead.append(QBluetoothUuid::SerialNumberString); m_initUuidsToRead.append(QBluetoothUuid::HardwareRevisionString); m_initUuidsToRead.append(QBluetoothUuid::FirmwareRevisionString); diff --git a/nuki/nukicontroller.cpp b/nuki/nukicontroller.cpp index 895f6dad..3bfd6265 100644 --- a/nuki/nukicontroller.cpp +++ b/nuki/nukicontroller.cpp @@ -312,7 +312,8 @@ void NukiController::processUserDataNotification(const QByteArray nonce, quint32 if (command == NukiUtils::CommandNukiStates) { processNukiStatesData(payload); emit readNukiStatesFinished(true); - setState(NukiControllerStateReadingConfigurationRequestChallange); + // TODO: read configuration + setState(NukiControllerStateIdle); return; } break; From 971ec9a75cb961511549be2dad487613b9a60551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 22 Mar 2021 11:18:30 +0100 Subject: [PATCH 5/6] Undo initial testing descriptor read --- nuki/bluez/bluetoothgattdescriptor.cpp | 12 +++++------- nuki/integrationpluginnuki.cpp | 6 ++++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/nuki/bluez/bluetoothgattdescriptor.cpp b/nuki/bluez/bluetoothgattdescriptor.cpp index 35531c9a..c50c1410 100644 --- a/nuki/bluez/bluetoothgattdescriptor.cpp +++ b/nuki/bluez/bluetoothgattdescriptor.cpp @@ -76,13 +76,11 @@ BluetoothGattDescriptor::BluetoothGattDescriptor(const QDBusObjectPath &path, co processProperties(properties); - readValue(); - -// QDBusPendingCall readingCall = m_descriptorInterface->asyncCall("GetAll", QVariantMap()); -// QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(readingCall, this); -// connect(watcher, &QDBusPendingCallWatcher::finished, this, [=](){ -// qCDebug(dcBluez()) << "Get descriptor properties finished"; -// }); + 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) diff --git a/nuki/integrationpluginnuki.cpp b/nuki/integrationpluginnuki.cpp index cf0ff92f..915283b7 100644 --- a/nuki/integrationpluginnuki.cpp +++ b/nuki/integrationpluginnuki.cpp @@ -308,8 +308,9 @@ void IntegrationPluginNuki::onBluetoothDiscoveryFinished(ThingDiscoveryInfo *inf m_bluetoothAdapter->stopDiscovering(); foreach (BluetoothDevice *thing, m_bluetoothAdapter->devices()) { - if (!bluetoothDeviceAlreadyAdded(thing->address()) && thing->name().contains("Nuki")) { - ThingDescriptor descriptor(nukiThingClassId, "Nuki", thing->address().toString()); + qCDebug(dcNuki()) << "Found bluetooth device" << thing->name() << thing->address().toString(); + if (!bluetoothDeviceAlreadyAdded(thing->address()) && thing->name().toLower().contains("nuki")) { + qCDebug(dcNuki()) << "Found nuki smart lock which has not been added yet"; // Get serial number from name QString serialNumber; @@ -320,6 +321,7 @@ void IntegrationPluginNuki::onBluetoothDiscoveryFinished(ThingDiscoveryInfo *inf qCWarning(dcNuki()) << "Could not read serial number from bluetooth thing name" << thing->name(); } + ThingDescriptor descriptor(nukiThingClassId, "Nuki", thing->address().toString()); ParamList params; params.append(Param(nukiThingNameParamTypeId, thing->name())); params.append(Param(nukiThingMacParamTypeId, thing->address().toString())); From 72b99e0415c02238923c670b858bb528f854c10a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 22 Mar 2021 11:28:37 +0100 Subject: [PATCH 6/6] Make sure the setup thing for nuki gets cleaned up everywhere --- nuki/integrationpluginnuki.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nuki/integrationpluginnuki.cpp b/nuki/integrationpluginnuki.cpp index 915283b7..d922a739 100644 --- a/nuki/integrationpluginnuki.cpp +++ b/nuki/integrationpluginnuki.cpp @@ -200,7 +200,14 @@ void IntegrationPluginNuki::confirmPairing(ThingPairingInfo *info, const QString m_pairingInfo = info; m_asyncSetupNuki->startAuthenticationProcess(info->transactionId()); - connect(info, &ThingPairingInfo::destroyed, this, [this] { m_pairingInfo = nullptr; }); + connect(info, &ThingPairingInfo::destroyed, this, [this] { + m_pairingInfo = nullptr; + if (m_asyncSetupNuki) { + qCDebug(dcNuki()) << "Deleting the temporary pairing device"; + m_asyncSetupNuki->deleteLater(); + m_asyncSetupNuki = nullptr; + } + }); } void IntegrationPluginNuki::postSetupThing(Thing *thing)