Rework nuki to use indications
parent
6f46c2c16a
commit
c1da14fd55
|
|
@ -37,13 +37,6 @@
|
|||
#include <QDataStream>
|
||||
#include <QTimer>
|
||||
|
||||
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<quint16>(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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<NukiUtils::Command>(command);
|
||||
if (m_debug) qCDebug(dcNuki()) << "Authenticator data received: <--" << static_cast<NukiUtils::Command>(command) << "|" << NukiUtils::convertByteArrayToHexStringCompact(value);
|
||||
|
||||
switch (command) {
|
||||
case NukiUtils::CommandErrorReport:
|
||||
|
|
@ -500,9 +478,6 @@ 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
|
||||
|
|
@ -513,12 +488,8 @@ void NukiAuthenticator::onPairingDataCharacteristicChanged(const QByteArray &val
|
|||
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.";
|
||||
|
|
@ -536,12 +507,8 @@ void NukiAuthenticator::onPairingDataCharacteristicChanged(const QByteArray &val
|
|||
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) {
|
||||
case NukiUtils::CommandAuthorizationId: {
|
||||
qCDebug(dcNuki()) << "Authenticator: Nuki authorization ID message received" << (m_debug ? NukiUtils::convertByteArrayToHexStringCompact(m_currentReceivingData) : "");
|
||||
|
||||
if (!NukiUtils::validateMessageCrc(m_currentReceivingData)) {
|
||||
|
|
@ -561,7 +528,7 @@ void NukiAuthenticator::onPairingDataCharacteristicChanged(const QByteArray &val
|
|||
stream >> m_authorizationId;
|
||||
|
||||
m_uuid = message.mid(36, 16);
|
||||
Q_ASSERT_X(m_uuid.count() == 16, "data length", "UUIS has not the correct length.");
|
||||
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.");
|
||||
|
|
@ -573,8 +540,8 @@ void NukiAuthenticator::onPairingDataCharacteristicChanged(const QByteArray &val
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<quint16>(NukiUtils::CommandRequestConfig);
|
||||
for (int i = 0; i < m_nukiNonce.length(); i++) {
|
||||
stream << static_cast<quint8>(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<quint16>(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,17 +593,8 @@ 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();
|
||||
|
|
@ -529,7 +605,6 @@ void NukiController::onUserDataCharacteristicChanged(const QByteArray &value)
|
|||
// 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);
|
||||
|
||||
|
|
@ -541,14 +616,4 @@ void NukiController::onUserDataCharacteristicChanged(const QByteArray &value)
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue