From 0992028a8afc73316ff08d94abb8d2bdcecf9982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Sat, 6 Jun 2020 14:09:11 +0200 Subject: [PATCH] Rework entire uart communication flow and prepare level cluster command execution signals --- .../interface/zigbeeinterfacedeconz.cpp | 2 +- .../interface/zigbeeinterfacedeconzreply.cpp | 31 +- .../interface/zigbeeinterfacedeconzreply.h | 10 +- .../deconz/zigbeebridgecontrollerdeconz.cpp | 268 +++++++++--------- .../deconz/zigbeebridgecontrollerdeconz.h | 28 +- .../zcl/general/zigbeeclusterlevelcontrol.cpp | 21 +- .../lighting/zigbeeclustercolorcontrol.cpp | 6 +- libnymea-zigbee/zigbeedatatype.cpp | 12 +- libnymea-zigbee/zigbeenetwork.cpp | 6 + libnymea-zigbee/zigbeenetworkdatabase.cpp | 29 +- libnymea-zigbee/zigbeenode.cpp | 8 +- libnymea-zigbee/zigbeenode.h | 1 + 12 files changed, 242 insertions(+), 180 deletions(-) diff --git a/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp index cb18849..505b106 100644 --- a/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp +++ b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconz.cpp @@ -227,7 +227,7 @@ void ZigbeeInterfaceDeconz::sendPackage(const QByteArray &package) qCWarning(dcZigbeeInterface()) << "Could not stream byte" << ZigbeeUtils::convertByteArrayToHexString(data); } - //m_serialPort->flush(); + m_serialPort->flush(); } bool ZigbeeInterfaceDeconz::enable(const QString &serialPort, qint32 baudrate) diff --git a/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.cpp b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.cpp index 0506fd1..cd46c24 100644 --- a/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.cpp +++ b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.cpp @@ -32,6 +32,11 @@ ZigbeeNetworkRequest ZigbeeInterfaceDeconzReply::networkRequest() const return m_networkRequest; } +QString ZigbeeInterfaceDeconzReply::requestName() +{ + return m_requestName; +} + Deconz::Command ZigbeeInterfaceDeconzReply::command() const { return m_command; @@ -42,6 +47,11 @@ quint8 ZigbeeInterfaceDeconzReply::sequenceNumber() const return m_sequenceNumber; } +QByteArray ZigbeeInterfaceDeconzReply::requestData() const +{ + return m_requestData; +} + QByteArray ZigbeeInterfaceDeconzReply::responseData() const { return m_responseData; @@ -64,24 +74,37 @@ bool ZigbeeInterfaceDeconzReply::aborted() const void ZigbeeInterfaceDeconzReply::abort() { + m_timer->stop(); m_aborted = true; emit finished(); } -ZigbeeInterfaceDeconzReply::ZigbeeInterfaceDeconzReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent) : +ZigbeeInterfaceDeconzReply::ZigbeeInterfaceDeconzReply(Deconz::Command command, QObject *parent) : QObject(parent), m_timer(new QTimer(this)), - m_command(command), - m_sequenceNumber(sequenceNumber) + m_command(command) { - m_timer->setInterval(5000); + m_timer->setInterval(3000); m_timer->setSingleShot(true); connect(m_timer, &QTimer::timeout, this, &ZigbeeInterfaceDeconzReply::onTimeout); } +void ZigbeeInterfaceDeconzReply::setSequenceNumber(quint8 sequenceNumber) +{ + m_sequenceNumber = sequenceNumber; + // Put the sequence number into the request data payload, it's always the second byte + m_requestData[1] = m_sequenceNumber; +} + void ZigbeeInterfaceDeconzReply::onTimeout() { m_timeout = true; emit timeout(); emit finished(); } + +QDebug operator<<(QDebug debug, ZigbeeInterfaceDeconzReply *reply) +{ + debug.nospace() << "InterfaceReply(" << reply->requestName() << ", " << reply->sequenceNumber() << ")"; + return debug.space(); +} diff --git a/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.h b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.h index db9ab39..c12932f 100644 --- a/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.h +++ b/libnymea-zigbee/backends/deconz/interface/zigbeeinterfacedeconzreply.h @@ -43,8 +43,10 @@ class ZigbeeInterfaceDeconzReply : public QObject public: // Request content ZigbeeNetworkRequest networkRequest() const; + QString requestName(); Deconz::Command command() const; quint8 sequenceNumber() const; + QByteArray requestData() const; QByteArray responseData() const; // Response content @@ -55,15 +57,19 @@ public: void abort(); private: - explicit ZigbeeInterfaceDeconzReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent = nullptr); + explicit ZigbeeInterfaceDeconzReply(Deconz::Command command, QObject *parent = nullptr); ZigbeeNetworkRequest m_networkRequest; QTimer *m_timer = nullptr; bool m_timeout = false; bool m_aborted = false; + void setSequenceNumber(quint8 sequenceNumber); + // Request content + QString m_requestName; Deconz::Command m_command; quint8 m_sequenceNumber = 0; + QByteArray m_requestData; // Response content Deconz::StatusCode m_statusCode = Deconz::StatusCodeError; @@ -78,4 +84,6 @@ signals: }; +QDebug operator<<(QDebug debug, ZigbeeInterfaceDeconzReply *reply); + #endif // ZIGBEEINTERFACEDECONZREPLY_H diff --git a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp index a07614a..7712c15 100644 --- a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp +++ b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.cpp @@ -69,81 +69,57 @@ Deconz::NetworkState ZigbeeBridgeControllerDeconz::networkState() const ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestVersion() { - quint8 sequenceNumber = generateSequenceNumber(); - qCDebug(dcZigbeeController()) << "Request version. SQN:" << sequenceNumber; QByteArray message; QDataStream stream(&message, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream << static_cast(Deconz::CommandVersion); - stream << static_cast(sequenceNumber); + stream << static_cast(0); // SQN will be generated right before sending stream << static_cast(0); // Reserverd stream << static_cast(5); // Frame length - ZigbeeInterfaceDeconzReply *reply = new ZigbeeInterfaceDeconzReply(Deconz::CommandVersion, sequenceNumber, this); - connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater, Qt::QueuedConnection); - m_pendingReplies.insert(sequenceNumber, reply); - - m_interface->sendPackage(message); - return reply; + return createReply(Deconz::CommandVersion, "Request controller version", message, this); } ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestDeviceState() { - quint8 sequenceNumber = generateSequenceNumber(); - qCDebug(dcZigbeeController()) << "Request device state. SQN:" << sequenceNumber; - QByteArray message; QDataStream stream(&message, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream << static_cast(Deconz::CommandDeviceState); - stream << static_cast(sequenceNumber); + stream << static_cast(0); // SQN will be generated right before sending stream << static_cast(0); // Reserverd stream << static_cast(8); // Frame length stream << static_cast(0); // Reserverd stream << static_cast(0); // Reserverd stream << static_cast(0); // Reserverd - ZigbeeInterfaceDeconzReply *reply = new ZigbeeInterfaceDeconzReply(Deconz::CommandDeviceState, sequenceNumber, this); - connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater, Qt::QueuedConnection); - m_pendingReplies.insert(sequenceNumber, reply); - - m_interface->sendPackage(message); - - return createReply(Deconz::CommandDeviceState, sequenceNumber, this); + return createReply(Deconz::CommandDeviceState, "Request controller device state", message, this); } ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestReadParameter(Deconz::Parameter parameter) { - quint8 sequenceNumber = generateSequenceNumber(); - qCDebug(dcZigbeeController()) << "Request read parameter. SQN:" << sequenceNumber << parameter; - QByteArray message; QDataStream stream(&message, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream << static_cast(Deconz::CommandReadParameter); - stream << static_cast(sequenceNumber); + stream << static_cast(0); // SQN will be generated right before sending stream << static_cast(0); // Reserverd stream << static_cast(8); // Frame length 7 + 1 payload stream << static_cast(1); // Payload length stream << static_cast(parameter); - m_interface->sendPackage(message); - - return createReply(Deconz::CommandReadParameter, sequenceNumber, this); + return createReply(Deconz::CommandReadParameter, "Request controller read parameter", message, this); } ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestWriteParameter(Deconz::Parameter parameter, const QByteArray &data) { - quint8 sequenceNumber = generateSequenceNumber(); - qCDebug(dcZigbeeController()) << "Request write parameter. SQN:" << sequenceNumber << parameter << ZigbeeUtils::convertByteArrayToHexString(data); - quint16 payloadLength = static_cast(1 + data.length()); QByteArray message; QDataStream stream(&message, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream << static_cast(Deconz::CommandWriteParameter); - stream << static_cast(sequenceNumber); + stream << static_cast(0); // SQN will be generated right before sending stream << static_cast(0); // Reserverd stream << static_cast(7 + payloadLength); // Frame length 7 + payload length stream << static_cast(payloadLength); // 1 parameter + parameter data length @@ -152,35 +128,25 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestWriteParameter( stream << static_cast(data.at(i)); } - m_interface->sendPackage(message); - - return createReply(Deconz::CommandWriteParameter, sequenceNumber, this); + return createReply(Deconz::CommandWriteParameter, "Request controller write parameter", message, this); } ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestChangeNetworkState(Deconz::NetworkState networkState) { - quint8 sequenceNumber = generateSequenceNumber(); - qCDebug(dcZigbeeController()) << "Request change network state. SQN:" << sequenceNumber << networkState; - QByteArray message; QDataStream stream(&message, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream << static_cast(Deconz::CommandChangeNetworkState); - stream << static_cast(sequenceNumber); + stream << static_cast(0); // SQN will be generated right before sending stream << static_cast(0); // Reserverd stream << static_cast(6); // Frame length stream << static_cast(networkState); - m_interface->sendPackage(message); - - return createReply(Deconz::CommandChangeNetworkState, sequenceNumber, this); + return createReply(Deconz::CommandChangeNetworkState, "Request controller write parameter", message, this); } ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestReadReceivedDataIndication(Deconz::SourceAddressMode sourceAddressMode) { - quint8 sequenceNumber = generateSequenceNumber(); - qCDebug(dcZigbeeController()) << "Request read received data indication. SQN:" << sequenceNumber << ZigbeeUtils::convertByteToHexString(sourceAddressMode); - quint16 payloadLength = 0; if (sourceAddressMode != Deconz::SourceAddressModeNone) { payloadLength = 1; @@ -190,45 +156,32 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestReadReceivedDat QDataStream stream(&message, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream << static_cast(Deconz::CommandApsDataIndication); - stream << static_cast(sequenceNumber); + stream << static_cast(0); // SQN will be generated right before sending stream << static_cast(0); // Reserverd stream << static_cast(7 + payloadLength); // Frame length + payload length stream << static_cast(payloadLength); // payload length if (payloadLength > 0) stream << static_cast(sourceAddressMode); - m_interface->sendPackage(message); - - return createReply(Deconz::CommandApsDataIndication, sequenceNumber, this); + return createReply(Deconz::CommandApsDataIndication, "Request read received data indication", message, this); } ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestQuerySendDataConfirm() { - quint8 sequenceNumber = generateSequenceNumber(); - qCDebug(dcZigbeeController()) << "Request query send data confirm. SQN:" << sequenceNumber; - QByteArray message; QDataStream stream(&message, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream << static_cast(Deconz::CommandApsDataConfirm); - stream << static_cast(sequenceNumber); + stream << static_cast(0); // SQN will be generated right before sending stream << static_cast(0); // Reserverd stream << static_cast(7); // Frame length stream << static_cast(0); // Payload length - m_interface->sendPackage(message); - - return createReply(Deconz::CommandApsDataConfirm, sequenceNumber, this); + return createReply(Deconz::CommandApsDataConfirm, "Request query send data confirm", message, this); } ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestSendRequest(const ZigbeeNetworkRequest &request) { - // Send the request only if there are free slots on the device, otherwise enque request - // if (m_apsFreeSlotsAvailable) { - - // } - - qCDebug(dcZigbeeAps()) << "APSDE-DATA.request" << request; ZigbeeInterfaceDeconzReply *interfaceReply = nullptr; switch (request.destinationAddressMode()) { case Zigbee::DestinationAddressModeGroup: @@ -251,44 +204,73 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestSendRequest(con return interfaceReply; } -quint8 ZigbeeBridgeControllerDeconz::generateSequenceNumber() +void ZigbeeBridgeControllerDeconz::sendNextRequest() { - m_sequenceNumber += 3; - return m_sequenceNumber; + // Check if there is a reply request to send + if (m_replyQueue.isEmpty()) + return; + + // Check if there is currently a running reply + if (m_currentReply) + return; + +// // If the controler request queue is full, wait until it's free again +// if (!m_apsFreeSlotsAvailable) +// return; + + // Get the next reply, set the sequence number, send the request data over the interface and start waiting + m_currentReply = m_replyQueue.dequeue(); + m_currentReply->setSequenceNumber(generateSequenceNumber()); + qCDebug(dcZigbeeController()) << "Send request" << m_currentReply; + m_interface->sendPackage(m_currentReply->requestData()); + m_currentReply->m_timer->start(); } -ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::createReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent) +quint8 ZigbeeBridgeControllerDeconz::generateSequenceNumber() +{ + return m_sequenceNumber++; +} + +ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::createReply(Deconz::Command command, const QString &requestName, const QByteArray &requestData, QObject *parent) { // Create the reply - ZigbeeInterfaceDeconzReply *reply = new ZigbeeInterfaceDeconzReply(command, sequenceNumber, parent); + ZigbeeInterfaceDeconzReply *reply = new ZigbeeInterfaceDeconzReply(command, parent); + reply->m_requestName = requestName; + reply->m_requestData = requestData; + + // Make sure we clean up on timeout connect(reply, &ZigbeeInterfaceDeconzReply::timeout, this, [this, reply](){ - qCWarning(dcZigbeeController()) << "Reply timeout" << reply->command() << "SQN:" << reply->sequenceNumber(); - if (m_pendingReplies.contains(reply->sequenceNumber())) { - m_pendingReplies.remove(reply->sequenceNumber()); - // Note: will be deleted with the finished signal + qCWarning(dcZigbeeController()) << "Reply timeout" << reply; + if (m_currentReply == reply) { + m_currentReply = nullptr; + QMetaObject::invokeMethod(this, "sendNextRequest", Qt::QueuedConnection); } }); // Auto delete the object on finished - connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, &ZigbeeInterfaceDeconzReply::deleteLater, Qt::QueuedConnection); - - // Add it to the pending list - m_pendingReplies.insert(sequenceNumber, reply); - - // Fixme: start the timer once actually sent to the interface - reply->m_timer->start(); + connect(reply, &ZigbeeInterfaceDeconzReply::finished, reply, [this, reply](){ + reply->deleteLater(); + if (m_currentReply == reply) { + m_currentReply = nullptr; + QMetaObject::invokeMethod(this, "sendNextRequest", Qt::QueuedConnection); + } + }); + // Enqueu this reply and send it once the current reply slot is free + m_replyQueue.enqueue(reply); + qCDebug(dcZigbeeController()) << "Enqueue request:" << reply->requestName(); + QMetaObject::invokeMethod(this, "sendNextRequest", Qt::QueuedConnection); return reply; } ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataGroup(quint8 requestId, quint16 groupAddress, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius) { - quint8 sequenceNumber = generateSequenceNumber(); - qCDebug(dcZigbeeController()) << "Request enqueue send data to group" << ZigbeeUtils::convertUint16ToHexString(groupAddress) - << "SQN:" << sequenceNumber - << static_cast(profileId) - << ZigbeeUtils::convertUint16ToHexString(clusterId) - << ZigbeeUtils::convertByteToHexString(sourceEndpoint); +// quint8 sequenceNumber = generateSequenceNumber(); +// qCDebug(dcZigbeeController()) << "Request enqueue send data to group" << ZigbeeUtils::convertUint16ToHexString(groupAddress) +// << "SQN:" << sequenceNumber +// << static_cast(profileId) +// << ZigbeeUtils::convertUint16ToHexString(clusterId) +// << ZigbeeUtils::convertByteToHexString(sourceEndpoint); Q_ASSERT_X(asdu.length() <= 127, "ASDU", "ASDU package length has to <= 127 bytes"); @@ -299,7 +281,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData QDataStream stream(&message, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream << static_cast(Deconz::CommandApsDataRequest); - stream << static_cast(sequenceNumber); + stream << static_cast(0); // SQN will be generated right before sending stream << static_cast(0); // Reserverd stream << static_cast(7 + payloadLength); // Frame length stream << payloadLength; @@ -317,20 +299,18 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData stream << static_cast(txOptions); stream << radius; - m_interface->sendPackage(message); - - return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this); + return createReply(Deconz::CommandApsDataRequest, "Request enqueue send data to group", message, this); } ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius) { - quint8 sequenceNumber = generateSequenceNumber(); - qCDebug(dcZigbeeController()) << "Request enqueue send data to short address" << ZigbeeUtils::convertUint16ToHexString(shortAddress) - << "SQN:" << sequenceNumber - << ZigbeeUtils::convertByteToHexString(destinationEndpoint) - << static_cast(profileId) - << ZigbeeUtils::convertUint16ToHexString(clusterId) - << ZigbeeUtils::convertByteToHexString(sourceEndpoint); +// quint8 sequenceNumber = generateSequenceNumber(); +// qCDebug(dcZigbeeController()) << "Request enqueue send data to short address" << ZigbeeUtils::convertUint16ToHexString(shortAddress) +// << "SQN:" << sequenceNumber +// << ZigbeeUtils::convertByteToHexString(destinationEndpoint) +// << static_cast(profileId) +// << ZigbeeUtils::convertUint16ToHexString(clusterId) +// << ZigbeeUtils::convertByteToHexString(sourceEndpoint); Q_ASSERT_X(asdu.length() <= 127, "ASDU", "ASDU package length has to <= 127 bytes"); @@ -341,7 +321,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData QDataStream stream(&message, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream << static_cast(Deconz::CommandApsDataRequest); - stream << static_cast(sequenceNumber); + stream << static_cast(0); // SQN will be generated right before sending stream << static_cast(0); // Reserverd stream << static_cast(7 + payloadLength); // Frame length stream << payloadLength; @@ -359,19 +339,17 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData stream << static_cast(txOptions); // TX Options: Use APS ACKs stream << radius; - m_interface->sendPackage(message); - - return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this); + return createReply(Deconz::CommandApsDataRequest, "Request enqueue send data to short address", message, this); } ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius) { - quint8 sequenceNumber = generateSequenceNumber(); - qCDebug(dcZigbeeController()) << "Request enqueue send data to IEEE address" << ieeeAddress.toString() - << "SQN:" << sequenceNumber - << ZigbeeUtils::convertByteToHexString(destinationEndpoint) - << profileId << clusterId - << ZigbeeUtils::convertByteToHexString(sourceEndpoint); +// quint8 sequenceNumber = generateSequenceNumber(); +// qCDebug(dcZigbeeController()) << "Request enqueue send data to IEEE address" << ieeeAddress.toString() +// << "SQN:" << sequenceNumber +// << ZigbeeUtils::convertByteToHexString(destinationEndpoint) +// << profileId << clusterId +// << ZigbeeUtils::convertByteToHexString(sourceEndpoint); Q_ASSERT_X(asdu.length() <= 127, "ZigbeeController", "ASDU package length has to be <= 127 bytes"); @@ -382,7 +360,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData QDataStream stream(&message, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream << static_cast(Deconz::CommandApsDataRequest); - stream << static_cast(sequenceNumber); + stream << static_cast(0); // SQN will be generated right before sending stream << static_cast(0); // Reserverd stream << static_cast(7 + payloadLength); // Frame length stream << payloadLength; @@ -400,9 +378,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::requestEnqueueSendData stream << static_cast(txOptions); // TX Options: Use APS ACKs stream << radius; - m_interface->sendPackage(message); - - return createReply(Deconz::CommandApsDataRequest, sequenceNumber, this); + return createReply(Deconz::CommandApsDataRequest, "Request enqueue send data to IEEE address", message, this); } ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters() @@ -414,7 +390,7 @@ ZigbeeInterfaceDeconzReply *ZigbeeBridgeControllerDeconz::readNetworkParameters( // If read request failes, this mehtod returns the status code of the failed request. // Create an independent reply for finishing the entire read sequence - ZigbeeInterfaceDeconzReply *readNetworkParametersReply = new ZigbeeInterfaceDeconzReply(Deconz::CommandReadParameter, generateSequenceNumber(), this); + ZigbeeInterfaceDeconzReply *readNetworkParametersReply = new ZigbeeInterfaceDeconzReply(Deconz::CommandReadParameter, this); connect(readNetworkParametersReply, &ZigbeeInterfaceDeconzReply::finished, readNetworkParametersReply, &ZigbeeInterfaceDeconzReply::deleteLater, Qt::QueuedConnection); // Read MAC address of the bridge @@ -756,14 +732,25 @@ DeconzDeviceState ZigbeeBridgeControllerDeconz::parseDeviceStateFlag(quint8 devi void ZigbeeBridgeControllerDeconz::readDataIndication() { - ZigbeeInterfaceDeconzReply *reply = requestReadReceivedDataIndication(); - connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (m_readIndicationReply) { + // There is alreay a read indication reply in the queue, let finish that first before creating a new one + return; + } + + m_readIndicationReply = requestReadReceivedDataIndication(); + connect(m_readIndicationReply, &ZigbeeInterfaceDeconzReply::finished, this, [this](){ + ZigbeeInterfaceDeconzReply *reply = m_readIndicationReply; + + // Allow to send the next read indication reply if required + m_readIndicationReply = nullptr; + if (reply->statusCode() != Deconz::StatusCodeSuccess) { - qCWarning(dcZigbeeController()) << "Could not read data indication." << "SQN:" << reply->sequenceNumber() << reply->statusCode(); + qCWarning(dcZigbeeController()) << "Could not read data indication." << "SQN:" << m_readIndicationReply->sequenceNumber() << m_readIndicationReply->statusCode(); // FIXME: set an appropriate error return; } + // APS data indication received, process the content qCDebug(dcZigbeeController()) << "Reading data indication finished successfully" << "SQN:" << reply->sequenceNumber(); processDataIndication(reply->responseData()); @@ -772,8 +759,18 @@ void ZigbeeBridgeControllerDeconz::readDataIndication() void ZigbeeBridgeControllerDeconz::readDataConfirm() { - ZigbeeInterfaceDeconzReply *reply = requestQuerySendDataConfirm(); - connect(reply, &ZigbeeInterfaceDeconzReply::finished, this, [this, reply](){ + if (m_readConfirmReply) { + // There is alreay a read confirm reply in the queue, let finish that first before creating a new one + return; + } + + m_readConfirmReply = requestQuerySendDataConfirm(); + connect(m_readConfirmReply, &ZigbeeInterfaceDeconzReply::finished, this, [this](){ + ZigbeeInterfaceDeconzReply *reply = m_readConfirmReply; + + // Allow to send the next read confirm reply if required + m_readConfirmReply = nullptr; + if (reply->statusCode() != Deconz::StatusCodeSuccess) { qCWarning(dcZigbeeController()) << "Could not read data confirm." << "SQN:" << reply->sequenceNumber() << reply->statusCode(); // FIXME: set an appropriate error @@ -801,9 +798,10 @@ void ZigbeeBridgeControllerDeconz::processDeviceState(DeconzDeviceState deviceSt if (!m_apsFreeSlotsAvailable) { qCWarning(dcZigbeeController()) << "The APS request table is full on the device. Cannot send requests until the queue gets processed on the controller."; return; + } else { + qCDebug(dcZigbeeController()) << "The APS request table is free again. Sending the next request"; + sendNextRequest(); } - // FIXME: if changed to true, send next aps data request - } if (m_networkState != Deconz::NetworkStateConnected) @@ -909,15 +907,18 @@ void ZigbeeBridgeControllerDeconz::onInterfaceAvailableChanged(bool available) qCDebug(dcZigbeeController()) << "Interface available changed" << available; if (!available) { // Clean up any pending replies - foreach (quint8 id, m_pendingReplies.keys()) { - ZigbeeInterfaceDeconzReply *reply = m_pendingReplies.take(id); + while (!m_replyQueue.isEmpty()) { + ZigbeeInterfaceDeconzReply *reply = m_replyQueue.dequeue(); reply->abort(); } + m_sequenceNumber = 0; + m_apsFreeSlotsAvailable = true; m_watchdogTimer->stop(); } setAvailable(available); + sendNextRequest(); } void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray &package) @@ -933,29 +934,18 @@ void ZigbeeBridgeControllerDeconz::onInterfacePackageReceived(const QByteArray & qCDebug(dcZigbeeController()) << "Interface message received" << command << "SQN:" << sequenceNumber << status << "Frame length:" << frameLength << ZigbeeUtils::convertByteArrayToHexString(data); - // Check if this is an interface response for a pending reply - if (m_pendingReplies.contains(sequenceNumber)) { - if (m_pendingReplies.value(sequenceNumber)->command() == command) { - // SQN and command maches - ZigbeeInterfaceDeconzReply *reply = m_pendingReplies.take(sequenceNumber); - if (!reply) { - qCWarning(dcZigbeeController()) << "Received message but the corresponding reply does not exist any more."; - return; - } - reply->m_responseData = data; - reply->m_statusCode = status; - reply->finished(); - return; - } else { - qCWarning(dcZigbeeController()) << "Received message with a pending request SQN but the command does not match. SQN mismatch."; - qCWarning(dcZigbeeController()) << "The SQN matches" << m_pendingReplies.value(sequenceNumber)->command() << "but command" << command << "received for SQN" << sequenceNumber; - } + // Check if this is the response to the current active reply + if (m_currentReply && m_currentReply->sequenceNumber() == sequenceNumber && m_currentReply->command() == command) { + m_currentReply->m_responseData = data; + m_currentReply->m_statusCode = status; + m_currentReply->finished(); + // Note: the current reply will be cleand up in the finished slot + return; } - // Note: we got a notification, lets set the current sequence number to the notification id, - // so the next request will be a continuouse increase - - //m_sequenceNumber = sequenceNumber + 10; + // We got a notification, lets set the current sequence number to the notification id, + // so the next request will be a continuouse increase + m_sequenceNumber = sequenceNumber; // No request for this data, lets check which notification and process the data switch (command) { diff --git a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h index 9b7877b..824d01c 100644 --- a/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h +++ b/libnymea-zigbee/backends/deconz/zigbeebridgecontrollerdeconz.h @@ -93,11 +93,7 @@ public: ZigbeeInterfaceDeconzReply *requestWriteParameter(Deconz::Parameter parameter, const QByteArray &data); ZigbeeInterfaceDeconzReply *requestChangeNetworkState(Deconz::NetworkState networkState); - // Receive data - ZigbeeInterfaceDeconzReply *requestReadReceivedDataIndication(Deconz::SourceAddressMode sourceAddressMode = Deconz::SourceAddressModeShortSourceAddress); - ZigbeeInterfaceDeconzReply *requestQuerySendDataConfirm(); - - // Send data + // Send APS request data ZigbeeInterfaceDeconzReply *requestSendRequest(const ZigbeeNetworkRequest &request); private: @@ -105,21 +101,22 @@ private: quint8 m_sequenceNumber = 0; quint32 m_watchdogTimeout = 300; int m_watchdogResetTimout = 280; - QHash m_pendingReplies; + DeconzNetworkConfiguration m_networkConfiguration; Deconz::NetworkState m_networkState = Deconz::NetworkStateOffline; QTimer *m_watchdogTimer = nullptr; - // Interface queue, send all requests sequentially and always wait for the interface response - // APS request queue - bool m_apsFreeSlotsAvailable = false; - QQueue m_requestQueue; - void sendNextRequest(); + bool m_apsFreeSlotsAvailable = true; + ZigbeeInterfaceDeconzReply *m_currentReply = nullptr; + ZigbeeInterfaceDeconzReply *m_readConfirmReply = nullptr; + ZigbeeInterfaceDeconzReply *m_readIndicationReply = nullptr; + + QQueue m_replyQueue; quint8 generateSequenceNumber(); - ZigbeeInterfaceDeconzReply *createReply(Deconz::Command command, quint8 sequenceNumber, QObject *parent); + ZigbeeInterfaceDeconzReply *createReply(Deconz::Command command, const QString &requestName, const QByteArray &requestData, QObject *parent); // Send data depending on the request destination address mode QByteArray buildRequestEnqueueSendDataGroupMessage(quint8 requestId, quint16 groupAddress, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0); @@ -127,6 +124,10 @@ private: ZigbeeInterfaceDeconzReply *requestEnqueueSendDataShortAddress(quint8 requestId, quint16 shortAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0); ZigbeeInterfaceDeconzReply *requestEnqueueSendDataIeeeAddress(quint8 requestId, ZigbeeAddress ieeeAddress, quint8 destinationEndpoint, quint16 profileId, quint16 clusterId, quint8 sourceEndpoint, const QByteArray &asdu, Zigbee::ZigbeeTxOptions txOptions, quint8 radius = 0); + // Receive data + ZigbeeInterfaceDeconzReply *requestReadReceivedDataIndication(Deconz::SourceAddressMode sourceAddressMode = Deconz::SourceAddressModeShortSourceAddress); + ZigbeeInterfaceDeconzReply *requestQuerySendDataConfirm(); + // Note: this method reads all parameters individual. The returned reply it self will not send or receive any data. // The data can be fetched from m_networkConfiguration on success. ZigbeeInterfaceDeconzReply *readNetworkParameters(); @@ -151,8 +152,9 @@ signals: private slots: void onInterfaceAvailableChanged(bool available); void onInterfacePackageReceived(const QByteArray &package); - void resetControllerWatchdog(); + void sendNextRequest(); + public slots: bool enable(const QString &serialPort, qint32 baudrate); diff --git a/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.cpp b/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.cpp index e9d0d48..1e72a74 100644 --- a/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.cpp +++ b/libnymea-zigbee/zcl/general/zigbeeclusterlevelcontrol.cpp @@ -133,5 +133,24 @@ void ZigbeeClusterLevelControl::processDataIndication(ZigbeeClusterLibrary::Fram // Increase the tsn for continuouse id increasing on both sides m_transactionSequenceNumber = frame.header.transactionSequenceNumber; - // FIXME: parse client commands to group + switch (m_direction) { + case Client: + // If the client cluster sends data to a server cluster (independent which), the command was executed on the device like button pressed + if (frame.header.frameControl.direction == ZigbeeClusterLibrary::DirectionClientToServer) { + // Read the payload which is + Command command = static_cast(frame.header.command); + qCDebug(dcZigbeeCluster()) << "Command sent from" << m_node << m_endpoint << this << command; + switch (command) { + default: + qCWarning(dcZigbeeCluster()) << "Unhandled command sent from" << m_node << m_endpoint << this << command; + break; + } + } + break; + case Server: + qCWarning(dcZigbeeCluster()) << "Unhandled ZCL indication in" << m_node << m_endpoint << this << frame; + break; + } + + } diff --git a/libnymea-zigbee/zcl/lighting/zigbeeclustercolorcontrol.cpp b/libnymea-zigbee/zcl/lighting/zigbeeclustercolorcontrol.cpp index 30b26e2..ff1a31c 100644 --- a/libnymea-zigbee/zcl/lighting/zigbeeclustercolorcontrol.cpp +++ b/libnymea-zigbee/zcl/lighting/zigbeeclustercolorcontrol.cpp @@ -145,7 +145,7 @@ ZigbeeClusterReply *ZigbeeClusterColorControl::commandEnhancedMoveToHue(quint16 QDataStream stream(&payload, QIODevice::WriteOnly); stream.setByteOrder(QDataStream::LittleEndian); stream << enhancedHue << static_cast(direction) << transitionTime; - return executeClusterCommand(ZigbeeClusterColorControl::CommandEnhancedMoveHue, payload); + return executeClusterCommand(ZigbeeClusterColorControl::CommandEnhancedMoveToHue, payload); } ZigbeeClusterReply *ZigbeeClusterColorControl::commandEnhancedMoveHue(ZigbeeClusterColorControl::MoveMode moveMode, quint16 rate) @@ -212,7 +212,7 @@ ZigbeeClusterReply *ZigbeeClusterColorControl::commandStepColorTemperature(Zigbe void ZigbeeClusterColorControl::setAttribute(const ZigbeeClusterAttribute &attribute) { - qCDebug(dcZigbeeCluster()) << "Update attribute" << m_node << m_endpoint << this << static_cast(attribute.id()) << attribute.dataType(); + qCDebug(dcZigbeeCluster()) << "Attribute changed" << m_node << m_endpoint << this << static_cast(attribute.id()) << attribute.dataType(); if (hasAttribute(attribute.id())) { m_attributes[attribute.id()] = attribute; emit attributeChanged(attribute); @@ -220,6 +220,8 @@ void ZigbeeClusterColorControl::setAttribute(const ZigbeeClusterAttribute &attri m_attributes.insert(attribute.id(), attribute); emit attributeChanged(attribute); } + + } void ZigbeeClusterColorControl::processDataIndication(ZigbeeClusterLibrary::Frame frame) diff --git a/libnymea-zigbee/zigbeedatatype.cpp b/libnymea-zigbee/zigbeedatatype.cpp index 0b7e664..1276cca 100644 --- a/libnymea-zigbee/zigbeedatatype.cpp +++ b/libnymea-zigbee/zigbeedatatype.cpp @@ -1121,7 +1121,17 @@ QDebug operator<<(QDebug debug, const ZigbeeDataType &dataType) { // FIXME: print data depending on the datatype debug.nospace() << "ZigbeeDataType(" << dataType.name(); - debug.nospace() << ", " << ZigbeeUtils::convertByteArrayToHexString(dataType.data()); + switch (dataType.dataType()) { + case Zigbee::OctetString: + case Zigbee::LongOctetString: + case Zigbee::LongCharString: + case Zigbee::CharString: + debug.nospace() << ", " << dataType.toString(); + break; + default: + debug.nospace() << ", " << ZigbeeUtils::convertByteArrayToHexString(dataType.data()); + } + debug.nospace() << ")"; return debug.space(); } diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp index a68b464..a4e54df 100644 --- a/libnymea-zigbee/zigbeenetwork.cpp +++ b/libnymea-zigbee/zigbeenetwork.cpp @@ -437,6 +437,12 @@ void ZigbeeNetwork::addUnitializedNode(ZigbeeNode *node) } connect(node, &ZigbeeNode::stateChanged, this, &ZigbeeNetwork::onNodeStateChanged); + connect(node, &ZigbeeNode::nodeInitializationFailed, this, [this, node](){ + qCWarning(dcZigbeeNetwork()) << "The initialization procedure for" << node << "failed. Please retry to add this node by restarting the init procedure."; + m_uninitializedNodes.removeAll(node); + node->deleteLater(); + }); + m_uninitializedNodes.append(node); } diff --git a/libnymea-zigbee/zigbeenetworkdatabase.cpp b/libnymea-zigbee/zigbeenetworkdatabase.cpp index ad7b8ca..340bfa5 100644 --- a/libnymea-zigbee/zigbeenetworkdatabase.cpp +++ b/libnymea-zigbee/zigbeenetworkdatabase.cpp @@ -62,7 +62,7 @@ QList ZigbeeNetworkDatabase::loadNodes() QString query("SELECT * FROM nodes;"); QSqlQuery nodesQuery = m_db.exec(query); while (nodesQuery.next()) { - quint64 ieeeAddress = nodesQuery.value("ieeeAddress").toULongLong(); + QString ieeeAddress = nodesQuery.value("ieeeAddress").toString(); quint16 shortAddress = nodesQuery.value("shortAddress").toUInt(); QByteArray nodeDescriptor = QByteArray::fromBase64(nodesQuery.value("nodeDescriptor").toByteArray()); quint16 powerDescriptor = nodesQuery.value("powerDescriptor").toUInt(); @@ -185,7 +185,7 @@ bool ZigbeeNetworkDatabase::initDatabase() // Create nodes table createTable("nodes", - "(ieeeAddress INTEGER PRIMARY KEY, " // uint64 + "(ieeeAddress TEXT PRIMARY KEY, " // ieeeAddress to string "shortAddress INTEGER NOT NULL, " // uint16 "nodeDescriptor BLOB NOT NULL, " // bytes as received from the node "powerDescriptor INTEGER NOT NULL)"); // uint16 @@ -250,7 +250,7 @@ bool ZigbeeNetworkDatabase::saveNodeEndpoint(ZigbeeNodeEndpoint *endpoint) qCDebug(dcZigbeeNetworkDatabase()) << "Save" << endpoint; QString queryString = QString("INSERT OR REPLACE INTO endpoints (ieeeAddress, endpointId, profileId, deviceId, deviceVersion) " "VALUES (\"%1\", \"%2\", \"%3\", \"%4\", \"%5\");") - .arg(endpoint->node()->extendedAddress().toUInt64()) + .arg(endpoint->node()->extendedAddress().toString()) .arg(endpoint->endpointId()) .arg(static_cast(endpoint->profile())) .arg(static_cast(endpoint->deviceId())) @@ -258,7 +258,7 @@ bool ZigbeeNetworkDatabase::saveNodeEndpoint(ZigbeeNodeEndpoint *endpoint) m_db.exec(queryString); if (m_db.lastError().type() != QSqlError::NoError) { - qCWarning(dcZigbeeNetworkDatabase()) << "Could not save node into database." << m_db.lastError().databaseText() << m_db.lastError().driverText(); + qCWarning(dcZigbeeNetworkDatabase()) << "Could not save node into database." << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); return false; } @@ -288,14 +288,14 @@ bool ZigbeeNetworkDatabase::saveInputCluster(ZigbeeCluster *cluster) { qCDebug(dcZigbeeNetworkDatabase()) << "Save" << cluster; QString endpointIdReferenceQuery = QString("(SELECT id FROM endpoints WHERE ieeeAddress = \"%1\" AND endpointId = \"%2\")") - .arg(cluster->node()->extendedAddress().toUInt64()) + .arg(cluster->node()->extendedAddress().toString()) .arg(cluster->endpoint()->endpointId()); QString queryString = QString("INSERT OR REPLACE INTO serverClusters (endpointId, clusterId) VALUES (%1, \"%2\");") .arg(endpointIdReferenceQuery) .arg(static_cast(cluster->clusterId())); m_db.exec(queryString); if (m_db.lastError().type() != QSqlError::NoError) { - qCWarning(dcZigbeeNetworkDatabase()) << "Could not save input cluster into database." << m_db.lastError().databaseText() << m_db.lastError().driverText(); + qCWarning(dcZigbeeNetworkDatabase()) << "Could not save input cluster into database." << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); return false; } @@ -306,7 +306,7 @@ bool ZigbeeNetworkDatabase::saveOutputCluster(ZigbeeCluster *cluster) { qCDebug(dcZigbeeNetworkDatabase()) << "Save" << cluster; QString endpointIdReferenceQuery = QString("(SELECT id FROM endpoints WHERE ieeeAddress = \"%1\" AND endpointId = \"%2\")") - .arg(cluster->node()->extendedAddress().toUInt64()) + .arg(cluster->node()->extendedAddress().toString()) .arg(cluster->endpoint()->endpointId()); QString queryString = QString("INSERT OR REPLACE INTO clientClusters (endpointId, clusterId) VALUES (%1, \"%2\");") .arg(endpointIdReferenceQuery) @@ -314,7 +314,7 @@ bool ZigbeeNetworkDatabase::saveOutputCluster(ZigbeeCluster *cluster) m_db.exec(queryString); if (m_db.lastError().type() != QSqlError::NoError) { - qCWarning(dcZigbeeNetworkDatabase()) << "Could not save output cluster into database." << m_db.lastError().databaseText() << m_db.lastError().driverText(); + qCWarning(dcZigbeeNetworkDatabase()) << "Could not save output cluster into database." << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); return false; } @@ -327,7 +327,7 @@ bool ZigbeeNetworkDatabase::saveAttribute(ZigbeeCluster *cluster, const ZigbeeCl QString serverClusterIdReferenceQuery = QString("(SELECT id FROM serverClusters " "WHERE endpointId = (SELECT id FROM endpoints WHERE ieeeAddress = \"%1\" AND endpointId = \"%2\")" "AND clusterId = \"%3\")") - .arg(cluster->node()->extendedAddress().toUInt64()) + .arg(cluster->node()->extendedAddress().toString()) .arg(cluster->endpoint()->endpointId()) .arg(cluster->clusterId()); @@ -340,7 +340,7 @@ bool ZigbeeNetworkDatabase::saveAttribute(ZigbeeCluster *cluster, const ZigbeeCl m_db.exec(queryString); if (m_db.lastError().type() != QSqlError::NoError) { - qCWarning(dcZigbeeNetworkDatabase()) << "Could not save cluster cluster attribute into database." << m_db.lastError().databaseText() << m_db.lastError().driverText(); + qCWarning(dcZigbeeNetworkDatabase()) << "Could not save cluster cluster attribute into database." << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); return false; } @@ -352,14 +352,15 @@ bool ZigbeeNetworkDatabase::saveNode(ZigbeeNode *node) qCDebug(dcZigbeeNetworkDatabase()) << "Save" << node; QString queryString = QString("INSERT OR REPLACE INTO nodes (ieeeAddress, shortAddress, nodeDescriptor, powerDescriptor) " "VALUES (\"%1\", \"%2\", \"%3\", \"%4\");") - .arg(node->extendedAddress().toUInt64()) + .arg(node->extendedAddress().toString()) .arg(node->shortAddress()) .arg(node->nodeDescriptor().descriptorRawData.toBase64().data()) // Note: convert to base64 for saving zeros as string .arg(node->powerDescriptor().powerDescriptoFlag); + qCDebug(dcZigbeeNetworkDatabase()) << queryString; m_db.exec(queryString); if (m_db.lastError().type() != QSqlError::NoError) { - qCWarning(dcZigbeeNetworkDatabase()) << "Could not save node into database." << m_db.lastError().databaseText() << m_db.lastError().driverText(); + qCWarning(dcZigbeeNetworkDatabase()) << "Could not save node into database." << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); return false; } @@ -377,10 +378,10 @@ bool ZigbeeNetworkDatabase::removeNode(ZigbeeNode *node) { qCDebug(dcZigbeeNetworkDatabase()) << "Remove" << node; // Note: cascade delete will clean up all other tables - QString queryString = QString("DELETE FROM nodes WHERE ieeeAddress = %1;").arg(node->extendedAddress().toUInt64()); + QString queryString = QString("DELETE FROM nodes WHERE ieeeAddress = %1;").arg(node->extendedAddress().toString()); m_db.exec(queryString); if (m_db.lastError().type() != QSqlError::NoError) { - qCWarning(dcZigbeeNetworkDatabase()) << "Could not remove node from database." << m_db.lastError().databaseText() << m_db.lastError().driverText(); + qCWarning(dcZigbeeNetworkDatabase()) << "Could not remove node from database." << queryString << m_db.lastError().databaseText() << m_db.lastError().driverText(); return false; } diff --git a/libnymea-zigbee/zigbeenode.cpp b/libnymea-zigbee/zigbeenode.cpp index f948820..d63f981 100644 --- a/libnymea-zigbee/zigbeenode.cpp +++ b/libnymea-zigbee/zigbeenode.cpp @@ -153,7 +153,7 @@ void ZigbeeNode::initNodeDescriptor() } else { qCWarning(dcZigbeeNode()) << "Failed to read node descriptor from" << this << "after 3 attempts. Giving up."; m_requestRetry = 0; - // FIXME: decide what to do, remove the node again from network + emit nodeInitializationFailed(); } return; } @@ -188,7 +188,7 @@ void ZigbeeNode::initPowerDescriptor() } else { qCWarning(dcZigbeeNode()) << "Failed to read power descriptor from" << this << "after 3 attempts. Giving up."; m_requestRetry = 0; - // FIXME: decide what to do, remove the node again from network or continue with active endpoint request + emit nodeInitializationFailed(); } return; } @@ -228,7 +228,7 @@ void ZigbeeNode::initEndpoints() } else { qCWarning(dcZigbeeNode()) << "Failed to read active endpoints from" << this << "after 3 attempts. Giving up."; m_requestRetry = 0; - // FIXME: decide what to do, remove the node again from network + emit nodeInitializationFailed(); } return; } @@ -284,7 +284,7 @@ void ZigbeeNode::initEndpoint(quint8 endpointId) } else { qCWarning(dcZigbeeNode()) << "Failed to read simple descriptor from" << this << ZigbeeUtils::convertByteToHexString(endpointId) << "after 3 attempts. Giving up."; m_requestRetry = 0; - // FIXME: decide what to do, remove the node again from network + emit nodeInitializationFailed(); } return; } diff --git a/libnymea-zigbee/zigbeenode.h b/libnymea-zigbee/zigbeenode.h index 4fd3221..526da82 100644 --- a/libnymea-zigbee/zigbeenode.h +++ b/libnymea-zigbee/zigbeenode.h @@ -115,6 +115,7 @@ private: void readSoftwareBuildId(ZigbeeClusterBasic *basicCluster); signals: + void nodeInitializationFailed(); void stateChanged(State state); void lqiChanged(quint8 lqi); void connectedChanged(bool connected);