From ac7972df35cde17ef119ed11ae7fb8ec44de555e Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 27 Sep 2022 09:07:20 +0200 Subject: [PATCH] Complete the OTA cluster implementation --- .../zigbeeclusterpowerconfiguration.cpp | 1 - libnymea-zigbee/zcl/ota/zigbeeclusterota.cpp | 206 ++++++++++++++++-- libnymea-zigbee/zcl/ota/zigbeeclusterota.h | 46 +++- libnymea-zigbee/zcl/zigbeecluster.cpp | 4 +- libnymea-zigbee/zcl/zigbeecluster.h | 2 +- libnymea-zigbee/zcl/zigbeeclusterlibrary.cpp | 3 +- libnymea-zigbee/zcl/zigbeeclusterreply.cpp | 2 +- .../zdo/zigbeedeviceobjectreply.cpp | 2 +- libnymea-zigbee/zigbeenetwork.cpp | 2 +- libnymea-zigbee/zigbeenetworkreply.cpp | 2 +- 10 files changed, 229 insertions(+), 41 deletions(-) diff --git a/libnymea-zigbee/zcl/general/zigbeeclusterpowerconfiguration.cpp b/libnymea-zigbee/zcl/general/zigbeeclusterpowerconfiguration.cpp index af166ff..951757a 100644 --- a/libnymea-zigbee/zcl/general/zigbeeclusterpowerconfiguration.cpp +++ b/libnymea-zigbee/zcl/general/zigbeeclusterpowerconfiguration.cpp @@ -48,7 +48,6 @@ ZigbeeClusterPowerConfiguration::BatteryAlarmMask ZigbeeClusterPowerConfiguratio void ZigbeeClusterPowerConfiguration::setAttribute(const ZigbeeClusterAttribute &attribute) { - qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast(attribute.id()) << attribute.dataType(); ZigbeeCluster::setAttribute(attribute); if (attribute.id() == AttributeBatteryPercentageRemaining) { diff --git a/libnymea-zigbee/zcl/ota/zigbeeclusterota.cpp b/libnymea-zigbee/zcl/ota/zigbeeclusterota.cpp index d8c4245..6b0ceba 100644 --- a/libnymea-zigbee/zcl/ota/zigbeeclusterota.cpp +++ b/libnymea-zigbee/zcl/ota/zigbeeclusterota.cpp @@ -39,19 +39,156 @@ ZigbeeClusterOta::ZigbeeClusterOta(ZigbeeNetwork *network, ZigbeeNode *node, Zig } +ZigbeeClusterReply *ZigbeeClusterOta::sendImageNotify(PayloadType payloadType, quint8 queryJitter, quint16 manufacturerCode, quint16 imageType, quint32 newFileVersion) +{ + if (queryJitter > 100) { + queryJitter = 100; + } + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(payloadType); + stream << queryJitter; + if (payloadType >= PayloadTypeQueryJitterAndManufacturerCode) { + stream << manufacturerCode; + } + if (payloadType >= PayloadTypeQueryJitterAndManufacturerCodeAndImageType) { + stream << imageType; + } + if (payloadType >= PayloadTypeQueryJitterAndManufacturerCodeAndImageTypeAndNewFileVersion) { + stream << newFileVersion; + } + ZigbeeClusterReply *reply = executeClusterCommand(CommandImageNotify, payload, ZigbeeClusterLibrary::DirectionServerToClient); + return reply; +} + +ZigbeeClusterReply *ZigbeeClusterOta::sendQueryNextImageResponse(quint8 transactionSequenceNumber, StatusCode statusCode, quint16 manufacturerCode, quint16 imageType, quint32 fileVersion, quint32 imageSize) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(statusCode); + if (statusCode == StatusCodeSuccess) { + stream << manufacturerCode; + stream << imageType; + stream << fileVersion; + stream << imageSize; + } + + ZigbeeClusterReply *reply = sendClusterServerResponse(CommandQueryNextImageResponse, transactionSequenceNumber, payload); + connect(reply, &ZigbeeClusterReply::finished, this, [reply](){ + if (reply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeeCluster()) << "OTA: Error sending query next image response:" << reply->error(); + return; + } + qCDebug(dcZigbeeCluster()) << "OTA: Query image response sent successfully."; + }); + return reply; +} + +ZigbeeClusterReply *ZigbeeClusterOta::sendImageBlockResponse(quint8 transactionSequenceNumber, quint16 manufacturerCode, quint16 imageType, quint32 fileVersion, quint32 fileOffset, const QByteArray &imageData) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(StatusCodeSuccess); + stream << manufacturerCode; + stream << imageType; + stream << fileVersion; + stream << fileOffset; + stream << static_cast(imageData.length()); + stream.writeRawData(imageData.data(), imageData.length()); + + ZigbeeClusterReply *reply = sendClusterServerResponse(CommandImageBlockResponse, transactionSequenceNumber, payload); + connect(reply, &ZigbeeClusterReply::finished, this, [reply](){ + if (reply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeeCluster()) << "OTA: Error sending image block response:" << reply->error(); + return; + } + qCDebug(dcZigbeeCluster()) << "OTA: Image block response sent successfully."; + }); + return reply; +} + +ZigbeeClusterReply *ZigbeeClusterOta::sendAbortImageBlockResponse(quint8 transactionSequenceNumber) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(StatusCodeAbort); + ZigbeeClusterReply *reply = sendClusterServerResponse(CommandImageBlockResponse, transactionSequenceNumber, payload); + connect(reply, &ZigbeeClusterReply::finished, this, [reply](){ + if (reply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeeCluster()) << "OTA: Error sending abort image block response:" << reply->error(); + return; + } + qCDebug(dcZigbeeCluster()) << "OTA: Abort image block response sent successfully."; + }); + return reply; + +} + +ZigbeeClusterReply *ZigbeeClusterOta::sendDelayImageBlockResponse(quint8 transactionSequenceNumber, const QDateTime &requestTime, quint16 minimumBlockPeriod) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << static_cast(StatusCodeWaitForData); + stream << static_cast(requestTime.toMSecsSinceEpoch() / 1000); + stream << minimumBlockPeriod; + + ZigbeeClusterReply *reply = sendClusterServerResponse(CommandImageBlockResponse, transactionSequenceNumber, payload); + connect(reply, &ZigbeeClusterReply::finished, this, [reply](){ + if (reply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeeCluster()) << "OTA: Error sending delay image block response:" << reply->error(); + return; + } + qCDebug(dcZigbeeCluster()) << "OTA: Delay image block response sent successfully."; + }); + return reply; + +} + +ZigbeeClusterReply *ZigbeeClusterOta::sendUpgradeEndResponse(quint8 transactionSequenceNumber, quint16 manufacturerCode, quint16 imageType, quint32 fileVersion, quint32 serverTime, quint32 requestTime) +{ + QByteArray payload; + QDataStream stream(&payload, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << manufacturerCode; + stream << imageType; + stream << fileVersion; + stream << serverTime; + stream << requestTime; + + ZigbeeClusterReply *reply = sendClusterServerResponse(CommandUpgradeEndResponse, transactionSequenceNumber, payload); + connect(reply, &ZigbeeClusterReply::finished, this, [reply](){ + if (reply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbeeCluster()) << "OTA: Error sending image block response:" << reply->error(); + return; + } + qCDebug(dcZigbeeCluster()) << "OTA: Query image block data successfully."; + }); + return reply; +} + +ZigbeeClusterReply *ZigbeeClusterOta::sendAbortUpgradeEndResponse(quint8 transactionSequenceNumber) +{ + return sendDefaultResponse(transactionSequenceNumber, ZigbeeClusterLibrary::CommandDefaultResponse, ZigbeeClusterLibrary::StatusSuccess); +} + ZigbeeClusterOta::FileVersion ZigbeeClusterOta::parseFileVersion(quint32 fileVersionValue) { FileVersion fileVersion; - fileVersion.applicationRelease = static_cast(fileVersionValue & 0xFF000000); - fileVersion.applicationBuild = static_cast(fileVersionValue & 0x00FF0000); - fileVersion.stackRelease = static_cast(fileVersionValue & 0x0000FF00); - fileVersion.stackBuild = static_cast(fileVersionValue & 0x000000FF); + fileVersion.applicationRelease = static_cast(fileVersionValue >> 24); + fileVersion.applicationBuild = static_cast(fileVersionValue >> 16); + fileVersion.stackRelease = static_cast(fileVersionValue >> 8); + fileVersion.stackBuild = static_cast(fileVersionValue); return fileVersion; } void ZigbeeClusterOta::processDataIndication(ZigbeeClusterLibrary::Frame frame) { - qCDebug(dcZigbeeCluster()) << "Processing cluster frame" << m_node << m_endpoint << this << frame; + qCDebug(dcZigbeeCluster()) << "OTA: Processing cluster frame" << m_node << m_endpoint << this << frame << frame.payload.toHex(); switch (m_direction) { case Client: @@ -70,37 +207,64 @@ void ZigbeeClusterOta::processDataIndication(ZigbeeClusterLibrary::Frame frame) QDataStream requestStream(&frame.payload, QIODevice::ReadOnly); requestStream.setByteOrder(QDataStream::LittleEndian); requestStream >> fieldControl >> manufacturerCode >> imageType >> currentVersion >> hardwareVersion; - qCDebug(dcZigbeeCluster()) << "OTA image request:" << (fieldControl == 0x0000 ? "Hardware version not present" : "Hardware version present"); + FileVersion currentFileVersion = parseFileVersion(currentVersion); + qCDebug(dcZigbeeCluster()) << "OTA image request:" << (fieldControl == 0x00 ? "Hardware version not present" : "Hardware version present"); qCDebug(dcZigbeeCluster()) << "OTA image request: Manufacturer code" << ZigbeeUtils::convertUint16ToHexString(manufacturerCode); qCDebug(dcZigbeeCluster()) << "OTA image request: Image type" << ZigbeeUtils::convertUint16ToHexString(imageType); - qCDebug(dcZigbeeCluster()) << "OTA image request: Current file version" << ZigbeeUtils::convertUint32ToHexString(currentVersion) << parseFileVersion(currentVersion); + qCDebug(dcZigbeeCluster()) << "OTA image request: Current file version" << ZigbeeUtils::convertUint32ToHexString(currentVersion) << currentFileVersion; qCDebug(dcZigbeeCluster()) << "OTA image request: Hardware version" << hardwareVersion; - // Respond with no image available until we implement the entire cluster for OTA updates - qCDebug(dcZigbeeCluster()) << "OTA mechanism not implemented yet. Tell the node there is no image available."; + emit queryNextImageRequestReceived(frame.header.transactionSequenceNumber, manufacturerCode, imageType, currentVersion, hardwareVersion); + break; + } + case CommandImageBlockRequest: { + quint8 fieldControl; + quint16 manufacturerCode; + quint16 imageType; + quint32 fileVersion; + quint32 fileOffset; + quint8 maximumDataSize; + quint64 requestNodeAddress = 0; + quint16 minimumBlockPerdiod = 0; - QByteArray payload; - QDataStream stream(&payload, QIODevice::WriteOnly); + QDataStream stream(frame.payload); stream.setByteOrder(QDataStream::LittleEndian); - stream << static_cast(StatuCodeNoImageAvailable); - - // Note: if there would be an image available, the response would be success, followed by manufacturer code, image type, file version of image and file size - - ZigbeeClusterReply *reply = sendClusterServerResponse(CommandQueryNextImageResponse, frame.header.transactionSequenceNumber, payload); - connect(reply, &ZigbeeClusterReply::finished, this, [](){ - qCDebug(dcZigbeeCluster()) << "OTA image request response for image query sent successfully to requested node."; - }); + stream >> fieldControl >> manufacturerCode >> imageType >> fileVersion >> fileOffset >> maximumDataSize; + if (fieldControl & 0x01) { + stream >> requestNodeAddress; + } + if (fieldControl & 0x02) { + stream >> minimumBlockPerdiod; + } + qCDebug(dcZigbeeCluster()) << "OTA: Image block request receved. FieldControl:" << fieldControl << "ManufacturerCode:" << manufacturerCode << "ImageType:" << imageType << "File version:" << fileVersion << "Offset:" << fileOffset << "Max size:" << maximumDataSize << "Request Address:" << ZigbeeAddress(requestNodeAddress) << "Min block period:" << minimumBlockPerdiod; + emit imageBlockRequestReceived(frame.header.transactionSequenceNumber, manufacturerCode, imageType, fileVersion, fileOffset, maximumDataSize, ZigbeeAddress(requestNodeAddress), minimumBlockPerdiod); break; } + case CommandUpgradeEndRequest: { + quint8 status; + quint16 manufacturerCode; + quint16 imageType; + quint32 fileVersion; + QDataStream stream(frame.payload); + stream.setByteOrder(QDataStream::LittleEndian); + stream >> status >> manufacturerCode >> imageType >> fileVersion; + emit upgradeEndRequestReceived(frame.header.transactionSequenceNumber, static_cast(status), manufacturerCode, imageType, fileVersion); + break; + } default: - qCWarning(dcZigbeeCluster()) << "Received command" << command << "which is not implemented yet from" << m_node << m_endpoint << this; + qCWarning(dcZigbeeCluster()) << "Received unhandled command" << command << "from" << m_node << m_endpoint << this; break; } } break; case Server: - qCWarning(dcZigbeeCluster()) << "Unhandled ZCL indication in" << m_node << m_endpoint << this << frame; + if (frame.header.frameControl.direction == ZigbeeClusterLibrary::DirectionServerToClient) { + Command command = static_cast(frame.header.command); + qCDebug(dcZigbeeCluster()) << "Received" << command << "from" << m_node << m_endpoint << this; + } else { + qCWarning(dcZigbeeCluster()) << "Unhandled ZCL indication in" << m_node << m_endpoint << this << frame; + } break; } } diff --git a/libnymea-zigbee/zcl/ota/zigbeeclusterota.h b/libnymea-zigbee/zcl/ota/zigbeeclusterota.h index eedb857..01f4e41 100644 --- a/libnymea-zigbee/zcl/ota/zigbeeclusterota.h +++ b/libnymea-zigbee/zcl/ota/zigbeeclusterota.h @@ -29,6 +29,7 @@ #define ZIGBEECLUSTEROTA_H #include +#include #include "zcl/zigbeecluster.h" #include "zcl/zigbeeclusterreply.h" @@ -76,18 +77,26 @@ public: Q_ENUM(Command) enum StatusCode { - StatuCodeSuccess = 0x00, - StatuCodeAbort = 0x95, - StatuCodeNotAuthorized = 0x7E, - StatuCodeInvalidImage = 0x96, - StatuCodeWaitForData = 0x97, - StatuCodeNoImageAvailable = 0x98, - StatuCodeMalformedCommand = 0x80, - StatuCodeUnsupportedClusterCommand = 0x81, - StatuCodeRequireMoreImage = 0x99 + StatusCodeSuccess = 0x00, + StatusCodeAbort = 0x95, + StatusCodeNotAuthorized = 0x7E, + StatusCodeInvalidImage = 0x96, + StatusCodeWaitForData = 0x97, + StatusCodeNoImageAvailable = 0x98, + StatusCodeMalformedCommand = 0x80, + StatusCodeUnsupportedClusterCommand = 0x81, + StatusCodeRequireMoreImage = 0x99 }; Q_ENUM(StatusCode) + enum PayloadType { + PayloadTypeQueryJitter = 0x00, + PayloadTypeQueryJitterAndManufacturerCode = 0x01, + PayloadTypeQueryJitterAndManufacturerCodeAndImageType = 0x02, + PayloadTypeQueryJitterAndManufacturerCodeAndImageTypeAndNewFileVersion = 0x03 + }; + Q_ENUM(PayloadType) + typedef struct FileVersion { quint8 applicationRelease; quint8 applicationBuild; @@ -95,13 +104,28 @@ public: quint8 stackBuild; } FileVersion; + explicit ZigbeeClusterOta(ZigbeeNetwork *network, ZigbeeNode *node, ZigbeeNodeEndpoint *endpoint, Direction direction, QObject *parent = nullptr); + ZigbeeClusterReply *sendImageNotify(PayloadType payloadType = PayloadTypeQueryJitter, quint8 queryJitter = 100, quint16 manufacturerCode = 0, quint16 imageType = 0, quint32 newFileVersion = 0); + ZigbeeClusterReply *sendQueryNextImageResponse(quint8 transactionSequenceNumber, StatusCode statusCode = StatusCodeNoImageAvailable, quint16 manufacturerCode = 0, quint16 imageType = 0, quint32 fileVersion = 0, quint32 imageSize = 0); + + ZigbeeClusterReply *sendImageBlockResponse(quint8 transactionSequenceNumber, quint16 manufacturerCode, quint16 imageType, quint32 fileVersion, quint32 fileOffset, const QByteArray &imageData); + ZigbeeClusterReply *sendAbortImageBlockResponse(quint8 transactionSequenceNumber); + ZigbeeClusterReply *sendDelayImageBlockResponse(quint8 transactionSequenceNumber, const QDateTime &requestTime, quint16 minimumBlockPeriod); + + ZigbeeClusterReply *sendUpgradeEndResponse(quint8 transactionSequenceNumber, quint16 manufacturerCode, quint16 imageType, quint32 fileVersion, quint32 serverTime = 0, quint32 requestTime = 1); + ZigbeeClusterReply *sendAbortUpgradeEndResponse(quint8 transactionSequenceNumber); + + static FileVersion parseFileVersion(quint32 fileVersionValue); + +signals: + void queryNextImageRequestReceived(quint8 transactionSequenceNumber, quint16 manufactuerCode, quint16 imageType, quint32 fileVersion, quint16 hardwareVersion); + void imageBlockRequestReceived(quint8 transactionSequenceNumber, quint16 manufacturerCode, quint16 imageType, quint32 fileVersion, quint32 fileOffset, quint8 maximumDataSize, const ZigbeeAddress &requestNodeAddress, quint16 minimumBlockPeriod); + void upgradeEndRequestReceived(quint8 transactionSequenceNumber, StatusCode statusCode, quint16 manufacturerCode, quint16 imageType, quint32 fileVersion); protected: void processDataIndication(ZigbeeClusterLibrary::Frame frame) override; -private: - FileVersion parseFileVersion(quint32 fileVersionValue); }; QDebug operator<<(QDebug debug, const ZigbeeClusterOta::FileVersion &fileVersion); diff --git a/libnymea-zigbee/zcl/zigbeecluster.cpp b/libnymea-zigbee/zcl/zigbeecluster.cpp index ef161c2..f0a3445 100644 --- a/libnymea-zigbee/zcl/zigbeecluster.cpp +++ b/libnymea-zigbee/zcl/zigbeecluster.cpp @@ -212,7 +212,7 @@ ZigbeeClusterReply *ZigbeeCluster::createClusterReply(const ZigbeeNetworkRequest return zclReply; } -ZigbeeClusterReply *ZigbeeCluster::executeClusterCommand(quint8 command, const QByteArray &payload) +ZigbeeClusterReply *ZigbeeCluster::executeClusterCommand(quint8 command, const QByteArray &payload, ZigbeeClusterLibrary::Direction direction) { ZigbeeNetworkRequest request = createGeneralRequest(); @@ -220,7 +220,7 @@ ZigbeeClusterReply *ZigbeeCluster::executeClusterCommand(quint8 command, const Q ZigbeeClusterLibrary::FrameControl frameControl; frameControl.frameType = ZigbeeClusterLibrary::FrameTypeClusterSpecific; frameControl.manufacturerSpecific = false; - frameControl.direction = ZigbeeClusterLibrary::DirectionClientToServer; + frameControl.direction = direction; frameControl.disableDefaultResponse = false; // Build ZCL header diff --git a/libnymea-zigbee/zcl/zigbeecluster.h b/libnymea-zigbee/zcl/zigbeecluster.h index d18c4b0..cab2470 100644 --- a/libnymea-zigbee/zcl/zigbeecluster.h +++ b/libnymea-zigbee/zcl/zigbeecluster.h @@ -112,7 +112,7 @@ protected: // Cluster specific ZigbeeClusterReply *createClusterReply(const ZigbeeNetworkRequest &request, ZigbeeClusterLibrary::Frame frame); - ZigbeeClusterReply *executeClusterCommand(quint8 command, const QByteArray &payload = QByteArray()); + ZigbeeClusterReply *executeClusterCommand(quint8 command, const QByteArray &payload = QByteArray(), ZigbeeClusterLibrary::Direction direction = ZigbeeClusterLibrary::DirectionClientToServer); ZigbeeClusterReply *sendClusterServerResponse(quint8 command, quint8 transactionSequenceNumber, const QByteArray &payload = QByteArray()); ZigbeeClusterReply *sendDefaultResponse(quint8 transactionSequenceNumber, quint8 command, quint8 status); diff --git a/libnymea-zigbee/zcl/zigbeeclusterlibrary.cpp b/libnymea-zigbee/zcl/zigbeeclusterlibrary.cpp index 6af02a2..b8d5ca5 100644 --- a/libnymea-zigbee/zcl/zigbeeclusterlibrary.cpp +++ b/libnymea-zigbee/zcl/zigbeeclusterlibrary.cpp @@ -265,8 +265,9 @@ QByteArray ZigbeeClusterLibrary::buildAttributeReportingConfiguration(const Zigb stream << reportingConfiguration.minReportingInterval; stream << reportingConfiguration.maxReportingInterval; - for (int i = 0; i < reportingConfiguration.reportableChange.count(); i++) + for (int i = 0; i < reportingConfiguration.reportableChange.count(); i++) { stream << static_cast(reportingConfiguration.reportableChange.at(i)); + } // Note: for reporting the timeoutPeriod is omitted if (reportingConfiguration.direction == ReportingDirectionReceiving) { diff --git a/libnymea-zigbee/zcl/zigbeeclusterreply.cpp b/libnymea-zigbee/zcl/zigbeeclusterreply.cpp index 510b162..2fb8753 100644 --- a/libnymea-zigbee/zcl/zigbeeclusterreply.cpp +++ b/libnymea-zigbee/zcl/zigbeeclusterreply.cpp @@ -32,7 +32,7 @@ ZigbeeClusterReply::ZigbeeClusterReply(const ZigbeeNetworkRequest &request, Zigb m_request(request), m_requestFrame(requestFrame) { - m_timeoutTimer.setInterval(10000); + m_timeoutTimer.setInterval(20000); connect(&m_timeoutTimer, &QTimer::timeout, this, [this](){ m_error = ErrorTimeout; emit finished(); diff --git a/libnymea-zigbee/zdo/zigbeedeviceobjectreply.cpp b/libnymea-zigbee/zdo/zigbeedeviceobjectreply.cpp index 515cfdc..671512c 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceobjectreply.cpp +++ b/libnymea-zigbee/zdo/zigbeedeviceobjectreply.cpp @@ -33,7 +33,7 @@ ZigbeeDeviceObjectReply::ZigbeeDeviceObjectReply(const ZigbeeNetworkRequest &req QObject(parent), m_request(request) { - m_timeoutTimer.setInterval(10000); + m_timeoutTimer.setInterval(20000); connect(&m_timeoutTimer, &QTimer::timeout, this, [this](){ m_error = ErrorTimeout; emit finished(); diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp index f769487..1723fad 100644 --- a/libnymea-zigbee/zigbeenetwork.cpp +++ b/libnymea-zigbee/zigbeenetwork.cpp @@ -401,7 +401,7 @@ void ZigbeeNetwork::addNodeInternally(ZigbeeNode *node) connect(node, &ZigbeeNode::clusterAdded, this, [this, node](ZigbeeCluster *cluster){ if (node->state() == ZigbeeNode::StateInitialized) { - qCWarning(dcZigbeeNetwork()) << node << cluster << "cluster added but the node has already been initialized. This node is out of spec. Save the node nether the less..."; + qCWarning(dcZigbeeNetwork()) << node << "cluster" << cluster << "added on endpoint" << cluster->endpoint()->endpointId() << "but the node has already been initialized. This node is out of spec. Saving the node nethertheless..."; m_database->saveNode(node); } }); diff --git a/libnymea-zigbee/zigbeenetworkreply.cpp b/libnymea-zigbee/zigbeenetworkreply.cpp index 4003eaa..1c01fc4 100644 --- a/libnymea-zigbee/zigbeenetworkreply.cpp +++ b/libnymea-zigbee/zigbeenetworkreply.cpp @@ -58,7 +58,7 @@ ZigbeeNetworkReply::ZigbeeNetworkReply(const ZigbeeNetworkRequest &request, QObj { m_timer = new QTimer(this); m_timer->setSingleShot(true); - m_timer->setInterval(10000); + m_timer->setInterval(20000); connect(m_timer, &QTimer::timeout, this, [this](){ m_error = ErrorTimeout; emit finished();