diff --git a/libnymea-core/zigbee/zigbeemanager.cpp b/libnymea-core/zigbee/zigbeemanager.cpp index ae5337c0..c53fdd20 100644 --- a/libnymea-core/zigbee/zigbeemanager.cpp +++ b/libnymea-core/zigbee/zigbeemanager.cpp @@ -272,8 +272,13 @@ void ZigbeeManager::loadZigbeeNetworks() network->setChannel(channel); network->setChannelMask(channelMask); network->setSecurityConfiguration(securityConfiguration); - addNetwork(network); settings.endGroup(); // networkUuid + + // Load the nodes before adding the network internally, so the loaded nodes will not generate added signals + network->loadNetwork(); + + // Add the network internally + addNetwork(network); } settings.endGroup(); // ZigbeeNetworks @@ -359,10 +364,36 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) return; } - ZigbeeNodeInitializer *nodeInitializer = m_zigbeeNodeInitializers.value(network->networkUuid()); - nodeInitializer->initializeNode(node); + qCDebug(dcZigbee()) << "-->" << node; + foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { + qCDebug(dcZigbee()) << " " << endpoint; + if (!endpoint->manufacturerName().isEmpty()) { + qCDebug(dcZigbee()) << " Manufacturer" << endpoint->manufacturerName(); + qCDebug(dcZigbee()) << " Model" << endpoint->modelIdentifier(); + qCDebug(dcZigbee()) << " Version" << endpoint->softwareBuildId(); + } + qCDebug(dcZigbee()) << " Input clusters (" << endpoint->inputClusters().count() << ")"; + foreach (ZigbeeCluster *cluster, endpoint->inputClusters()) { + qCDebug(dcZigbee()) << " -" << cluster; + foreach(const ZigbeeClusterAttribute &attribute, cluster->attributes()) { + qCDebug(dcZigbee()) << " - " << attribute; + } + } - //emit nodeAdded(network->networkUuid(), node); + qCDebug(dcZigbee()) << " Output clusters (" << endpoint->outputClusters().count() << ")"; + foreach (ZigbeeCluster *cluster, endpoint->outputClusters()) { + qCDebug(dcZigbee()) << " -" << cluster; + foreach(const ZigbeeClusterAttribute &attribute, cluster->attributes()) { + qCDebug(dcZigbee()) << " - " << attribute; + } + } + } + + +// ZigbeeNodeInitializer *nodeInitializer = m_zigbeeNodeInitializers.value(network->networkUuid()); +// nodeInitializer->initializeNode(node); + // TODO: emit node added once initialized so the plugins can use it + emit nodeAdded(network->networkUuid(), node); }); connect(network, &ZigbeeNetwork::nodeRemoved, this, [this, network](ZigbeeNode *node){ @@ -389,6 +420,34 @@ void ZigbeeManager::addNetwork(ZigbeeNetwork *network) emit nodeAdded(network->networkUuid(), node); }); + qCDebug(dcZigbee()) << "Network added" << network; + foreach (ZigbeeNode *node, network->nodes()) { + qCDebug(dcZigbee()) << "-->" << node; + foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { + qCDebug(dcZigbee()) << " " << endpoint; + if (!endpoint->manufacturerName().isEmpty()) { + qCDebug(dcZigbee()) << " Manufacturer" << endpoint->manufacturerName(); + qCDebug(dcZigbee()) << " Model" << endpoint->modelIdentifier(); + qCDebug(dcZigbee()) << " Version" << endpoint->softwareBuildId(); + } + qCDebug(dcZigbee()) << " Input clusters (" << endpoint->inputClusters().count() << ")"; + foreach (ZigbeeCluster *cluster, endpoint->inputClusters()) { + qCDebug(dcZigbee()) << " -" << cluster; + foreach(const ZigbeeClusterAttribute &attribute, cluster->attributes()) { + qCDebug(dcZigbee()) << " - " << attribute; + } + } + + qCDebug(dcZigbee()) << " Output clusters (" << endpoint->outputClusters().count() << ")"; + foreach (ZigbeeCluster *cluster, endpoint->outputClusters()) { + qCDebug(dcZigbee()) << " -" << cluster; + foreach(const ZigbeeClusterAttribute &attribute, cluster->attributes()) { + qCDebug(dcZigbee()) << " - " << attribute; + } + } + } + } + m_zigbeeNodeInitializers.insert(network->networkUuid(), nodeInitializer); } diff --git a/libnymea-core/zigbee/zigbeenodeinitializer.cpp b/libnymea-core/zigbee/zigbeenodeinitializer.cpp index 96b48cfe..68c21891 100644 --- a/libnymea-core/zigbee/zigbeenodeinitializer.cpp +++ b/libnymea-core/zigbee/zigbeenodeinitializer.cpp @@ -48,35 +48,66 @@ void ZigbeeNodeInitializer::initializeNode(ZigbeeNode *node) // Initialize and configure server clusters foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { - - // Read values + // Configure attribute reporting if (endpoint->hasInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)) { - } - - foreach (ZigbeeCluster *cluster, endpoint->inputClusters()) { - switch (cluster->clusterId()) { - case ZigbeeClusterLibrary::ClusterIdPowerConfiguration: { - // Read values + // Read current battery remaining + ZigbeeClusterReply *readAttributeReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->readAttributes({ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining}); + connect(readAttributeReply, &ZigbeeClusterReply::finished, this, [this, node, readAttributeReply](){ + if (readAttributeReply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbee()) << "Failed to read power cluster attributes" << readAttributeReply->error(); + emit nodeInitialized(node); + return; + } + }); + // Configure attribute rporting for battery remaining + ZigbeeClusterLibrary::AttributeReportingConfiguration reportingConfig; + reportingConfig.attributeId = ZigbeeClusterPowerConfiguration::AttributeBatteryPercentageRemaining; + reportingConfig.dataType = Zigbee::Uint8; + reportingConfig.minReportingInterval = 300; + reportingConfig.maxReportingInterval = 2700; + reportingConfig.reportableChange = ZigbeeDataType(static_cast(1)).data(); - // Configure attribute reporting - - break; - } - default: - // Not handeld, leave it to the plugin - break; - } - + ZigbeeClusterReply *reportingReply = endpoint->getInputCluster(ZigbeeClusterLibrary::ClusterIdPowerConfiguration)->configureReporting({reportingConfig}); + connect(reportingReply, &ZigbeeClusterReply::finished, this, [reportingReply](){ + if (reportingReply->error() != ZigbeeClusterReply::ErrorNoError) { + qCWarning(dcZigbee()) << "Failed to read power cluster attributes" << reportingReply->error(); + return; + } + qCDebug(dcZigbee()) << "Reporting config finished" << ZigbeeClusterLibrary::parseAttributeReportingStatusRecords(reportingReply->responseFrame().payload); + }); } } // Initialize and configure client clusters + foreach (ZigbeeNodeEndpoint *endpoint, node->endpoints()) { + if (endpoint->hasOutputCluster(ZigbeeClusterLibrary::ClusterIdOnOff)) { + // Bind command + ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdOnOff, m_network->coordinatorNode()->extendedAddress(), 0x01); + connect(zdoReply, &ZigbeeDeviceObjectReply::finished, this, [zdoReply](){ + if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbee()) << "Failed to bind OnOff cluster attributes" << zdoReply->error(); + return; + } + }); + } - + if (endpoint->hasOutputCluster(ZigbeeClusterLibrary::ClusterIdLevelControl)) { + // Bind command + ZigbeeDeviceObjectReply *zdoReply = node->deviceObject()->requestBindIeeeAddress(endpoint->endpointId(), ZigbeeClusterLibrary::ClusterIdLevelControl, m_network->coordinatorNode()->extendedAddress(), 0x01); + connect(zdoReply, &ZigbeeDeviceObjectReply::finished, this, [this, node, zdoReply](){ + if (zdoReply->error() != ZigbeeDeviceObjectReply::ErrorNoError) { + qCWarning(dcZigbee()) << "Failed to bind Level cluster attributes" << zdoReply->error(); + emit nodeInitialized(node); + return; + } + emit nodeInitialized(node); + }); + } + } }