diff --git a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp index a634eb7..59e5b98 100644 --- a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp +++ b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.cpp @@ -378,57 +378,6 @@ void ZigbeeNetworkDeconz::setCreateNetworkState(ZigbeeNetworkDeconz::CreateNetwo } } -void ZigbeeNetworkDeconz::handleZigbeeDeviceProfileIndication(const Zigbee::ApsdeDataIndication &indication) -{ - //qCDebug(dcZigbeeNetwork()) << "Handle ZDP indication" << indication; - - // Check if this is a device announcement - if (indication.clusterId == ZigbeeDeviceProfile::DeviceAnnounce) { - QDataStream stream(indication.asdu); - stream.setByteOrder(QDataStream::LittleEndian); - quint8 sequenceNumber = 0; quint16 shortAddress = 0; quint64 ieeeAddress = 0; quint8 macFlag = 0; - stream >> sequenceNumber >> shortAddress >> ieeeAddress >> macFlag; - onDeviceAnnounced(shortAddress, ZigbeeAddress(ieeeAddress), macFlag); - return; - } - - if (indication.destinationShortAddress == Zigbee::BroadcastAddressAllNodes || - indication.destinationShortAddress == Zigbee::BroadcastAddressAllRouters || - indication.destinationShortAddress == Zigbee::BroadcastAddressAllNonSleepingNodes) { - qCDebug(dcZigbeeNetwork()) << "Received unhandled broadcast ZDO indication" << indication; - - // FIXME: check what we can do with such messages like permit join - return; - } - - ZigbeeNode *node = getZigbeeNode(indication.sourceShortAddress); - if (!node) { - qCWarning(dcZigbeeNetwork()) << "Received a ZDO indication for an unrecognized node. There is no such node in the system. Ignoring indication" << indication; - // FIXME: check if we want to create it since the device definitly exists within the network - return; - } - - // Let the node handle this indication - handleNodeIndication(node, indication); -} - -void ZigbeeNetworkDeconz::handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication) -{ - ZigbeeClusterLibrary::Frame frame = ZigbeeClusterLibrary::parseFrameData(indication.asdu); - //qCDebug(dcZigbeeNetwork()) << "Handle ZCL indication" << indication << frame; - - // Get the node - ZigbeeNode *node = getZigbeeNode(indication.sourceShortAddress); - if (!node) { - qCWarning(dcZigbeeNetwork()) << "Received a ZCL indication for an unrecognized node. There is no such node in the system. Ignoring indication" << indication; - // FIXME: maybe create and init the node, since it is in the network, but not recognized - // FIXME: maybe remove this node since we might have removed it but it did not respond, or we not explicitly allowed it to join. - return; - } - // Let the node handle this indication - handleNodeIndication(node, indication); -} - void ZigbeeNetworkDeconz::startNetworkInternally() { qCDebug(dcZigbeeNetwork()) << "Start zigbee network internally"; @@ -659,34 +608,6 @@ void ZigbeeNetworkDeconz::onApsDataIndicationReceived(const Zigbee::ApsdeDataInd handleZigbeeClusterLibraryIndication(indication); } -void ZigbeeNetworkDeconz::onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities) -{ - qCDebug(dcZigbeeNetwork()) << "Device announced" << ZigbeeUtils::convertUint16ToHexString(shortAddress) << ieeeAddress.toString() << ZigbeeUtils::convertByteToHexString(macCapabilities); - - // Lets check if this device is in the uninitialized node list, if so, remove it and recreate the device - if (hasUninitializedNode(ieeeAddress)) { - qCWarning(dcZigbeeNetwork()) << "Device announced but there is already an initialization running for it. Remove the device and restart the initialization."; - ZigbeeNode *uninitializedNode = getZigbeeNode(ieeeAddress); - removeUninitializedNode(uninitializedNode); - } - - if (hasNode(ieeeAddress)) { - ZigbeeNode *node = getZigbeeNode(ieeeAddress); - if (shortAddress == node->shortAddress()) { - qCDebug(dcZigbeeNetwork()) << "Already known device announced and is reachable again" << node; - setNodeReachable(node, true); - return; - } else { - qCDebug(dcZigbeeNetwork()) << "Already known device announced with different network address. Removing node and reinitialize..."; - removeNode(node); - } - } - - ZigbeeNode *node = createNode(shortAddress, ieeeAddress, macCapabilities, this); - addUnitializedNode(node); - node->startInitialization(); -} - void ZigbeeNetworkDeconz::startNetwork() { loadNetwork(); diff --git a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h index 47a41f5..c380fdb 100644 --- a/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h +++ b/libnymea-zigbee/backends/deconz/zigbeenetworkdeconz.h @@ -73,12 +73,6 @@ private: ZigbeeNetworkReply *requestSetPermitJoin(quint16 shortAddress = Zigbee::BroadcastAddressAllRouters, quint8 duration = 0xfe); - // ZDO - void handleZigbeeDeviceProfileIndication(const Zigbee::ApsdeDataIndication &indication); - - // ZCL - void handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication); - protected: void startNetworkInternally(); @@ -89,7 +83,6 @@ private slots: void onApsDataConfirmReceived(const Zigbee::ApsdeDataConfirm &confirm); void onApsDataIndicationReceived(const Zigbee::ApsdeDataIndication &indication); - void onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities); public slots: void startNetwork() override; diff --git a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp index e550733..f38b393 100644 --- a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp +++ b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.cpp @@ -306,55 +306,6 @@ bool ZigbeeNetworkNxp::processVersionReply(ZigbeeInterfaceNxpReply *reply) return true; } -void ZigbeeNetworkNxp::handleZigbeeDeviceProfileIndication(const Zigbee::ApsdeDataIndication &indication) -{ - // Check if this is a device announcement - if (indication.clusterId == ZigbeeDeviceProfile::DeviceAnnounce) { - QDataStream stream(indication.asdu); - stream.setByteOrder(QDataStream::LittleEndian); - quint8 sequenceNumber = 0; quint16 shortAddress = 0; quint64 ieeeAddress = 0; quint8 macFlag = 0; - stream >> sequenceNumber >> shortAddress >> ieeeAddress >> macFlag; - onDeviceAnnounced(shortAddress, ZigbeeAddress(ieeeAddress), macFlag); - return; - } - - if (indication.destinationShortAddress == Zigbee::BroadcastAddressAllNodes || - indication.destinationShortAddress == Zigbee::BroadcastAddressAllRouters || - indication.destinationShortAddress == Zigbee::BroadcastAddressAllNonSleepingNodes) { - qCDebug(dcZigbeeNetwork()) << "Received unhandled broadcast ZDO indication" << indication; - - // FIXME: check what we can do with such messages like permit join - return; - } - - ZigbeeNode *node = getZigbeeNode(indication.sourceShortAddress); - if (!node) { - qCWarning(dcZigbeeNetwork()) << "Received a ZDO indication for an unrecognized node. There is no such node in the system. Ignoring indication" << indication; - // FIXME: check if we want to create it since the device definitly exists within the network - return; - } - - // Let the node handle this indication - handleNodeIndication(node, indication); -} - -void ZigbeeNetworkNxp::handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication) -{ - ZigbeeClusterLibrary::Frame frame = ZigbeeClusterLibrary::parseFrameData(indication.asdu); - //qCDebug(dcZigbeeNetwork()) << "Handle ZCL indication" << indication << frame; - - // Get the node - ZigbeeNode *node = getZigbeeNode(indication.sourceShortAddress); - if (!node) { - qCWarning(dcZigbeeNetwork()) << "Received a ZCL indication for an unrecognized node. There is no such node in the system. Ignoring indication" << indication; - // FIXME: maybe create and init the node, since it is in the network, but not recognized - // FIXME: maybe remove this node since we might have removed it but it did not respond, or we not explicitly allowed it to join. - return; - } - // Let the node handle this indication - handleNodeIndication(node, indication); -} - void ZigbeeNetworkNxp::onControllerAvailableChanged(bool available) { qCDebug(dcZigbeeNetwork()) << "Controller is" << (available ? "now available" : "not available any more"); @@ -603,36 +554,6 @@ void ZigbeeNetworkNxp::onApsDataIndicationReceived(const Zigbee::ApsdeDataIndica handleZigbeeClusterLibraryIndication(indication); } -void ZigbeeNetworkNxp::onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities) -{ - qCDebug(dcZigbeeNetwork()) << "Device announced" << ZigbeeUtils::convertUint16ToHexString(shortAddress) << ieeeAddress.toString() << ZigbeeUtils::convertByteToHexString(macCapabilities); - - // Lets check if this device is in the uninitialized node list, if so, remove it and recreate the device - if (hasUninitializedNode(ieeeAddress)) { - qCWarning(dcZigbeeNetwork()) << "Device announced but there is already an initialization running for it. Remove the device and restart the initialization."; - ZigbeeNode *uninitializedNode = getZigbeeNode(ieeeAddress); - removeUninitializedNode(uninitializedNode); - } - - if (hasNode(ieeeAddress)) { - ZigbeeNode *node = getZigbeeNode(ieeeAddress); - if (shortAddress == node->shortAddress()) { - qCDebug(dcZigbeeNetwork()) << "Already known device announced and is reachable again" << node; - setNodeReachable(node, true); - return; - } else { - qCWarning(dcZigbeeNetwork()) << "Already known device announced with different network address. FIXME: update the network address or reinitialize node..."; - - - //removeNode(node); - } - } - - ZigbeeNode *node = createNode(shortAddress, ieeeAddress, macCapabilities, this); - addUnitializedNode(node); - node->startInitialization(); -} - void ZigbeeNetworkNxp::onNodeLeftIndication(const ZigbeeAddress &ieeeAddress, bool rejoining) { qCDebug(dcZigbeeNetwork()) << "Received node left indication" << ieeeAddress.toString() << "rejoining:" << rejoining; diff --git a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.h b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.h index 093ca64..433a070 100644 --- a/libnymea-zigbee/backends/nxp/zigbeenetworknxp.h +++ b/libnymea-zigbee/backends/nxp/zigbeenetworknxp.h @@ -62,12 +62,6 @@ private: int m_reconnectCounter = 0; bool processVersionReply(ZigbeeInterfaceNxpReply *reply); - // ZDO - void handleZigbeeDeviceProfileIndication(const Zigbee::ApsdeDataIndication &indication); - - // ZCL - void handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication); - ZigbeeNetworkReply *requestSetPermitJoin(quint16 shortAddress = Zigbee::BroadcastAddressAllRouters, quint8 duration = 0xfe); private slots: @@ -78,7 +72,6 @@ private slots: void onApsDataConfirmReceived(const Zigbee::ApsdeDataConfirm &confirm); void onApsDataIndicationReceived(const Zigbee::ApsdeDataIndication &indication); - void onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities); void onNodeLeftIndication(const ZigbeeAddress &ieeeAddress, bool rejoining); signals: diff --git a/libnymea-zigbee/zdo/zigbeedeviceobject.cpp b/libnymea-zigbee/zdo/zigbeedeviceobject.cpp index 9120c25..1efd4ff 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceobject.cpp +++ b/libnymea-zigbee/zdo/zigbeedeviceobject.cpp @@ -42,6 +42,104 @@ ZigbeeDeviceObject::ZigbeeDeviceObject(ZigbeeNetwork *network, ZigbeeNode *node, } +ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestNetworkAddress() +{ + qCDebug(dcZigbeeDeviceObject()) << "Request network address from" << m_node; + + // Build APS request and make ieee address request + ZigbeeNetworkRequest request; + request.setRequestId(m_network->generateSequenceNumber()); + request.setDestinationAddressMode(Zigbee::DestinationAddressModeIeeeAddress); + request.setDestinationIeeeAddress(m_node->extendedAddress()); + request.setDestinationEndpoint(0); // ZDO + request.setProfileId(Zigbee::ZigbeeProfileDevice); // ZDP + request.setClusterId(ZigbeeDeviceProfile::NetworkAddressRequest); + request.setSourceEndpoint(0); // ZDO + + // Generate a new transaction sequence number for this device object + quint8 transactionSequenceNumber = m_transactionSequenceNumber++; + + // Build ZDO frame + QByteArray asdu; + QDataStream stream(&asdu, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << transactionSequenceNumber; + stream << m_node->extendedAddress().toUInt64(); + stream << static_cast(0); // Note: 0 = single device response, 1 = extended request + stream << static_cast(0); // Start index + + // Set the ZDO frame as APS request payload + request.setAsdu(asdu); + + // Create the device object reply and wait for the response indication + ZigbeeDeviceObjectReply *zdoReply = createZigbeeDeviceObjectReply(request, transactionSequenceNumber); + + // Send the request, on finished read the confirm information + ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); + connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + if (!verifyNetworkError(zdoReply, networkReply)) { + finishZdoReply(zdoReply); + return; + } + + // The request was successfully sent to the device + // Now check if the expected indication response received already + if (zdoReply->isComplete()) { + finishZdoReply(zdoReply); + return; + } + + // We received the confirmation but not yet the indication + }); + + return zdoReply; +} + +ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestIeeeAddress() +{ + qCDebug(dcZigbeeDeviceObject()) << "Request IEEE address from" << m_node; + + // Build APS request + ZigbeeNetworkRequest request = buildZdoRequest(ZigbeeDeviceProfile::IeeeAddressRequest); + + // Generate a new transaction sequence number for this device object + quint8 transactionSequenceNumber = m_transactionSequenceNumber++; + + // Build ZDO frame + QByteArray asdu; + QDataStream stream(&asdu, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + stream << transactionSequenceNumber << m_node->shortAddress(); + stream << static_cast(0); // Note: 0 = single device response, 1 = extended request + stream << static_cast(0); // Start index + + // Set the ZDO frame as APS request payload + request.setAsdu(asdu); + + // Create the device object reply and wait for the response indication + ZigbeeDeviceObjectReply *zdoReply = createZigbeeDeviceObjectReply(request, transactionSequenceNumber); + + // Send the request, on finished read the confirm information + ZigbeeNetworkReply *networkReply = m_network->sendRequest(request); + connect(networkReply, &ZigbeeNetworkReply::finished, this, [this, networkReply, zdoReply](){ + if (!verifyNetworkError(zdoReply, networkReply)) { + finishZdoReply(zdoReply); + return; + } + + // The request was successfully sent to the device + // Now check if the expected indication response received already + if (zdoReply->isComplete()) { + finishZdoReply(zdoReply); + return; + } + + // We received the confirmation but not yet the indication + }); + + return zdoReply; +} + ZigbeeDeviceObjectReply *ZigbeeDeviceObject::requestNodeDescriptor() { qCDebug(dcZigbeeDeviceObject()) << "Request node descriptor from" << m_node; diff --git a/libnymea-zigbee/zdo/zigbeedeviceobject.h b/libnymea-zigbee/zdo/zigbeedeviceobject.h index 1b900e7..70202b9 100644 --- a/libnymea-zigbee/zdo/zigbeedeviceobject.h +++ b/libnymea-zigbee/zdo/zigbeedeviceobject.h @@ -43,6 +43,8 @@ public: explicit ZigbeeDeviceObject(ZigbeeNetwork *network, ZigbeeNode *node, QObject *parent = nullptr); // Device and service discovery + ZigbeeDeviceObjectReply *requestNetworkAddress(); + ZigbeeDeviceObjectReply *requestIeeeAddress(); ZigbeeDeviceObjectReply *requestNodeDescriptor(); ZigbeeDeviceObjectReply *requestPowerDescriptor(); ZigbeeDeviceObjectReply *requestActiveEndpoints(); diff --git a/libnymea-zigbee/zigbeenetwork.cpp b/libnymea-zigbee/zigbeenetwork.cpp index a9f1084..4f47877 100644 --- a/libnymea-zigbee/zigbeenetwork.cpp +++ b/libnymea-zigbee/zigbeenetwork.cpp @@ -34,6 +34,7 @@ #include #include +#include ZigbeeNetwork::ZigbeeNetwork(const QUuid &networkUuid, QObject *parent) : QObject(parent), @@ -609,6 +610,84 @@ void ZigbeeNetwork::handleNodeIndication(ZigbeeNode *node, const Zigbee::ApsdeDa node->handleDataIndication(indication); } +void ZigbeeNetwork::handleZigbeeDeviceProfileIndication(const Zigbee::ApsdeDataIndication &indication) +{ + // Check if this is a device announcement + if (indication.clusterId == ZigbeeDeviceProfile::DeviceAnnounce) { + QDataStream stream(indication.asdu); + stream.setByteOrder(QDataStream::LittleEndian); + quint8 sequenceNumber = 0; quint16 shortAddress = 0; quint64 ieeeAddress = 0; quint8 macFlag = 0; + stream >> sequenceNumber >> shortAddress >> ieeeAddress >> macFlag; + onDeviceAnnounced(shortAddress, ZigbeeAddress(ieeeAddress), macFlag); + return; + } + + if (indication.destinationShortAddress == Zigbee::BroadcastAddressAllNodes || + indication.destinationShortAddress == Zigbee::BroadcastAddressAllRouters || + indication.destinationShortAddress == Zigbee::BroadcastAddressAllNonSleepingNodes) { + qCDebug(dcZigbeeNetwork()) << "Received unhandled broadcast ZDO indication" << indication; + + // FIXME: check what we can do with such messages like permit join + return; + } + + ZigbeeNode *node = getZigbeeNode(indication.sourceShortAddress); + if (!node) { + qCWarning(dcZigbeeNetwork()) << "Received a ZDO indication for an unrecognized node. There is no such node in the system. Ignoring indication" << indication; + // FIXME: check if we want to create it since the device definitly exists within the network + return; + } + + // Let the node handle this indication + handleNodeIndication(node, indication); +} + +void ZigbeeNetwork::handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication) +{ + ZigbeeClusterLibrary::Frame frame = ZigbeeClusterLibrary::parseFrameData(indication.asdu); + //qCDebug(dcZigbeeNetwork()) << "Handle ZCL indication" << indication << frame; + + // Get the node + ZigbeeNode *node = getZigbeeNode(indication.sourceShortAddress); + if (!node) { + qCWarning(dcZigbeeNetwork()) << "Received a ZCL indication for an unrecognized node. There is no such node in the system. Ignoring indication" << indication; + // FIXME: maybe create and init the node, since it is in the network, but not recognized + // FIXME: maybe remove this node since we might have removed it but it did not respond, or we not explicitly allowed it to join. + return; + } + // Let the node handle this indication + handleNodeIndication(node, indication); +} + +void ZigbeeNetwork::onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities) +{ + qCDebug(dcZigbeeNetwork()) << "Device announced" << ZigbeeUtils::convertUint16ToHexString(shortAddress) << ieeeAddress.toString() << ZigbeeUtils::convertByteToHexString(macCapabilities); + + // Lets check if this device is in the uninitialized node list, if so, remove it and recreate the device + if (hasUninitializedNode(ieeeAddress)) { + qCWarning(dcZigbeeNetwork()) << "Device announced but there is already an initialization running for it. Remove the device and restart the initialization."; + ZigbeeNode *uninitializedNode = getZigbeeNode(ieeeAddress); + removeUninitializedNode(uninitializedNode); + } + + if (hasNode(ieeeAddress)) { + ZigbeeNode *node = getZigbeeNode(ieeeAddress); + if (shortAddress == node->shortAddress()) { + qCDebug(dcZigbeeNetwork()) << "Already known device announced and is reachable again" << node; + setNodeReachable(node, true); + return; + } else { + qCWarning(dcZigbeeNetwork()) << "Already known device announced with different network address. FIXME: update the network address or reinitialize node..."; + //removeNode(node); + + } + } + + ZigbeeNode *node = createNode(shortAddress, ieeeAddress, macCapabilities, this); + addUnitializedNode(node); + node->startInitialization(); +} + ZigbeeNetworkReply *ZigbeeNetwork::createNetworkReply(const ZigbeeNetworkRequest &request) { ZigbeeNetworkReply *reply = new ZigbeeNetworkReply(request, this); diff --git a/libnymea-zigbee/zigbeenetwork.h b/libnymea-zigbee/zigbeenetwork.h index 4619c70..4a96c38 100644 --- a/libnymea-zigbee/zigbeenetwork.h +++ b/libnymea-zigbee/zigbeenetwork.h @@ -202,6 +202,14 @@ protected: void handleNodeIndication(ZigbeeNode *node, const Zigbee::ApsdeDataIndication indication); + // ZDO + void handleZigbeeDeviceProfileIndication(const Zigbee::ApsdeDataIndication &indication); + + // ZCL + void handleZigbeeClusterLibraryIndication(const Zigbee::ApsdeDataIndication &indication); + + void onDeviceAnnounced(quint16 shortAddress, ZigbeeAddress ieeeAddress, quint8 macCapabilities); + // Network reply methods ZigbeeNetworkReply *createNetworkReply(const ZigbeeNetworkRequest &request = ZigbeeNetworkRequest()); void setReplyResponseError(ZigbeeNetworkReply *reply, Zigbee::ZigbeeApsStatus zigbeeApsStatus = Zigbee::ZigbeeApsStatusSuccess); diff --git a/libnymea-zigbee/zigbeenetworkreply.cpp b/libnymea-zigbee/zigbeenetworkreply.cpp index 3db5817..4003eaa 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(8000); + m_timer->setInterval(10000); connect(m_timer, &QTimer::timeout, this, [this](){ m_error = ErrorTimeout; emit finished();