From e95724b37509dca01d7a8bd63895b5dbdfe2fb39 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Fri, 16 Sep 2022 00:41:39 +0200 Subject: [PATCH] Fix destination node selection for Zigbee bindings --- .../ui/mainviews/energy/PowerBalanceStats.qml | 4 +- .../zigbee/ZigbeeNetworkSettingsPage.qml | 3 +- .../zigbee/ZigbeeNetworkTopologyPage.qml | 2 +- nymea-app/ui/system/zigbee/ZigbeeNodePage.qml | 210 ++++++++++++------ 4 files changed, 151 insertions(+), 68 deletions(-) diff --git a/nymea-app/ui/mainviews/energy/PowerBalanceStats.qml b/nymea-app/ui/mainviews/energy/PowerBalanceStats.qml index 8c493e4b..7b132449 100644 --- a/nymea-app/ui/mainviews/energy/PowerBalanceStats.qml +++ b/nymea-app/ui/mainviews/energy/PowerBalanceStats.qml @@ -49,12 +49,12 @@ StatsBase { } var upcomingTimestamp = root.calculateTimestamp(d.config.startTime(), d.config.sampleRate, d.config.count) - print("refreshing config start", d.config.startTime(), "upcoming:", upcomingTimestamp, "fetchPending", d.fetchPending) +// print("refreshing config start", d.config.startTime(), "upcoming:", upcomingTimestamp, "fetchPending", d.fetchPending) for (var i = 0; i < d.config.count; i++) { var timestamp = root.calculateTimestamp(d.config.startTime(), d.config.sampleRate, d.startOffset + i + 1) var previousTimestamp = root.calculateTimestamp(timestamp, d.config.sampleRate, -1) var entry = powerBalanceLogs.find(timestamp) - print("timestamp:", timestamp, "found", (entry ? entry.timestamp : "")) +// print("timestamp:", timestamp, "found", (entry ? entry.timestamp : "")) var previousEntry = powerBalanceLogs.find(previousTimestamp); if (entry && (previousEntry || !d.loading)) { // print("found entry:", entry.timestamp, previousEntry) diff --git a/nymea-app/ui/system/zigbee/ZigbeeNetworkSettingsPage.qml b/nymea-app/ui/system/zigbee/ZigbeeNetworkSettingsPage.qml index cf350f11..3f453f63 100644 --- a/nymea-app/ui/system/zigbee/ZigbeeNetworkSettingsPage.qml +++ b/nymea-app/ui/system/zigbee/ZigbeeNetworkSettingsPage.qml @@ -91,7 +91,8 @@ SettingsPageBase { NymeaItemDelegate { Layout.fillWidth: true - text: qsTr("Network topology") + text: qsTr("Network map") + visible: engine.jsonRpcClient.ensureServerVersion("6.2") onClicked: { pageStack.push(Qt.resolvedUrl("ZigbeeNetworkTopologyPage.qml"), {zigbeeManager: root.zigbeeManager, network: root.network}) } diff --git a/nymea-app/ui/system/zigbee/ZigbeeNetworkTopologyPage.qml b/nymea-app/ui/system/zigbee/ZigbeeNetworkTopologyPage.qml index af0a39f3..8762c13f 100644 --- a/nymea-app/ui/system/zigbee/ZigbeeNetworkTopologyPage.qml +++ b/nymea-app/ui/system/zigbee/ZigbeeNetworkTopologyPage.qml @@ -8,7 +8,7 @@ Page { id: root header: NymeaHeader { - text: qsTr("ZigBee network topology") + text: qsTr("ZigBee network map") backButtonVisible: true onBackPressed: pageStack.pop() HeaderButton { diff --git a/nymea-app/ui/system/zigbee/ZigbeeNodePage.qml b/nymea-app/ui/system/zigbee/ZigbeeNodePage.qml index 4252ca1f..f174ebb4 100644 --- a/nymea-app/ui/system/zigbee/ZigbeeNodePage.qml +++ b/nymea-app/ui/system/zigbee/ZigbeeNodePage.qml @@ -41,6 +41,7 @@ SettingsPageBase { property ZigbeeManager zigbeeManager: null property ZigbeeNetwork network: null property ZigbeeNode node: null + readonly property ZigbeeNode coordinatorNode: root.network.nodes.getNodeByNetworkAddress(0) header: NymeaHeader { text: qsTr("ZigBee node info") @@ -220,69 +221,92 @@ SettingsPageBase { } - SettingsPageSectionHeader { - text: qsTr("Bindings") - } + ColumnLayout { + visible: engine.jsonRpcClient.ensureServerVersion("6.2") - property ZigbeeNode coordinatorNode: root.network.nodes.getNodeByNetworkAddress(0) - Repeater { - model: root.node.bindings - delegate: NymeaSwipeDelegate { - id: bindingDelegate - Layout.fillWidth: true - property ZigbeeNodeBinding binding: root.node.bindings[index] - ThingsProxy { - id: destinationThings - engine: _engine - paramsFilter: {"ieeeAddress": bindingDelegate.binding.destinationAddress} - } + SettingsPageSectionHeader { + text: qsTr("Bindings") + } - canDelete: true - progressive: false - text: { - if (destinationThings.count > 0) { - return destinationThings.get(0).name + Repeater { + model: root.node.bindings + delegate: NymeaSwipeDelegate { + id: bindingDelegate + Layout.fillWidth: true + property ZigbeeNodeBinding binding: root.node.bindings[index] + property ZigbeeNode destinationNode: root.network.nodes.getNode(binding.destinationAddress) + property ZigbeeNodeEndpoint endpoint: root.node.getEndpoint(binding.sourceEndpointId); + property ZigbeeCluster inputCluster: endpoint ? endpoint.getInputCluster(binding.clusterId) : null + property ZigbeeCluster outputCluster: endpoint ? endpoint.getOutputCluster(binding.clusterId) : null + property ZigbeeCluster usedCluster: inputCluster ? inputCluster : outputCluster + property Thing destinationThing: destinationThings.count > 0 ? destinationThings.get(0) : null + ThingsProxy { + id: destinationThings + engine: _engine + paramsFilter: {"ieeeAddress": bindingDelegate.binding.destinationAddress} } - if (binding.destinationAddress != "") { - if (binding.destinationAddress == coordinatorNode.ieeeAddress) { - return Configuration.systemName + + iconName: destinationNode && destinationNode == root.coordinatorNode + ? "qrc:/styles/%1/logo.svg".arg(styleController.currentStyle) + : destinationThing + ? app.interfacesToIcon(destinationThing.thingClass.interfaces) + : "/ui/images/zigbee.svg" + canDelete: true + progressive: false + text: { + if (binding.destinationAddress == "") { + return qsTr("Group: 0x%1").arg(NymeaUtils.pad(binding.groupAddress.toString(16), 4)) } - return binding.destinationAddress + var ret = "" + if (destinationNode) { + if (destinationNode == root.coordinatorNode) { + ret += Configuration.systemName + } else { + ret += destinationNode.model + } + } else { + ret += binding.destinationAddress + } + + if (destinationThings.count == 1) { + ret += " (" + destinationThings.get(0).name + ")" + } else if (destinationThings.count > 1) { + ret += " (" + destinationThing.count + " things)" + } + + return ret + } + subText: { + var ret = usedCluster.clusterName(); + if (binding.destinationAddress != "") { + ret += " (" + binding.sourceEndpointId + " -> " + binding.destinationEndpointId + ")" + } + return ret; + } + onDeleteClicked: { + if (!node.rxOnWhenIdle) { + d.wakeupDialog = wakeupDialogComponent.createObject(root) + d.wakeupDialog.open() + } + d.pendingCommandId = zigbeeManager.removeBinding(network.networkUuid, binding) } - return qsTr("Group: 0x%1").arg(NymeaUtils.pad(binding.groupAddress.toString(16), 4)) } - property ZigbeeNodeEndpoint endpoint: root.node.getEndpoint(binding.sourceEndpointId); - property ZigbeeCluster inputCluster: endpoint ? endpoint.getInputCluster(binding.clusterId) : null - property ZigbeeCluster outputCluster: endpoint ? endpoint.getOutputCluster(binding.clusterId) : null - property ZigbeeCluster usedCluster: inputCluster ? inputCluster : outputCluster - subText: { - var ret = usedCluster.clusterName(); - if (binding.destinationAddress != "") { - ret += " (" + binding.sourceEndpointId + " -> " + binding.destinationEndpointId + ")" - } - return ret; - } - onDeleteClicked: { - if (!node.rxOnWhenIdle) { - d.wakeupDialog = wakeupDialogComponent.createObject(root) - d.wakeupDialog.open() - } - d.pendingCommandId = zigbeeManager.removeBinding(network.networkUuid, binding) + } + + Button { + Layout.fillWidth: true + Layout.leftMargin: Style.margins + Layout.rightMargin: Style.margins + text: qsTr("Add binding") + onClicked: { + var dialog = addBindingComponent.createObject(root) + dialog.open() + } } } - Button { - Layout.fillWidth: true - Layout.leftMargin: Style.margins - Layout.rightMargin: Style.margins - text: qsTr("Add binding") - onClicked: { - var dialog = addBindingComponent.createObject(root) - dialog.open() - } - } @@ -382,27 +406,85 @@ SettingsPageBase { ComboBox { id: destinationNodeComboBox Layout.fillWidth: true + Layout.preferredHeight: Style.delegateHeight model: network.nodes - displayText: currentDestinationNodeThings.count > 0 - ? currentDestinationNodeThings.get(0).name - : currentNode == root.coordinatorNode - ? Configuration.systemName - : currentNode.model property ZigbeeNode currentNode: network.nodes.get(currentIndex) + property Thing currentNodeThing: currentNode && currentDestinationNodeThings.count > 0 ? currentDestinationNodeThings.get(0) : null ThingsProxy { id: currentDestinationNodeThings engine: _engine - paramsFilter: {"ieeeAddress": destinationNodeDelegate.node.ieeeAddress} + paramsFilter: destinationNodeComboBox.currentNode ? {"ieeeAddress": destinationNodeComboBox.currentNode.ieeeAddress} : {} } - delegate: ItemDelegate { + + contentItem: RowLayout { + id: destinationNodeContentItem + width: parent.width - destinationNodeComboBox.indicator.width - Style.smallMargins + height: Style.delegateHeight + spacing: Style.smallMargins + + ColorIcon { + Layout.leftMargin: Style.smallMargins + size: Style.iconSize + name: destinationNodeComboBox.currentNode == root.coordinatorNode + ? "qrc:/styles/%1/logo.svg".arg(styleController.currentStyle) + : destinationNodeComboBox.currentNodeThing + ? app.interfacesToIcon(destinationNodeComboBox.currentNodeThing.thingClass.interfaces) + : "/ui/images/zigbee.svg" + color: Style.accentColor + } + + ColumnLayout { + Label { + Layout.fillWidth: true + text: destinationNodeComboBox.currentNode == root.coordinatorNode + ? Configuration.systemName + : destinationNodeComboBox.currentNode.model + " - " + destinationNodeComboBox.currentNode.manufacturer + elide: Text.ElideRight + } + Label { + Layout.fillWidth: true + text: destinationNodeComboBox.currentNode == root.coordinatorNode + ? qsTr("Coordinator") + : currentDestinationNodeThings.count == 1 + ? destinationNodeComboBox.currentNodeThing.name + : currentDestinationNodeThings.count > 1 + ? qsTr("%1 things").arg(currentDestinationNodeThings.count) + : qsTr("Unrecognized device") + font: Style.smallFont + elide: Text.ElideRight + } + } + } +// displayText: currentDestinationNodeThings.count > 0 +// ? currentDestinationNodeThings.get(0).name +// : currentNode == root.coordinatorNode +// ? Configuration.systemName +// : currentNode.model +// ThingsProxy { +// id: currentDestinationNodeThings +// engine: _engine +// paramsFilter: {"ieeeAddress": destinationNodeComboBox.currentNode.ieeeAddress} +// } + delegate: NymeaItemDelegate { id: destinationNodeDelegate property ZigbeeNode node: network.nodes.get(index) + property Thing nodeThing: destinationNodeThings.count > 0 ? destinationNodeThings.get(0) : null + iconName: node == coordinatorNode + ? "qrc:/styles/%1/logo.svg".arg(styleController.currentStyle) + : nodeThing ? app.interfacesToIcon(nodeThing.thingClass.interfaces) : "/ui/images/zigbee.svg" width: parent.width - text: destinationNodeThings.count > 0 - ? destinationNodeThings.get(0).name - : node == root.coordinatorNode - ? Configuration.systemName - : node.model + text: node == root.coordinatorNode + ? Configuration.systemName + : node.model + " - " + node.manufacturer + subText: node == root.coordinatorNode + ? qsTr("Coordinator") + : destinationNodeThings.count == 1 + ? nodeThing.name + : nodeThings.count > 1 + ? qsTr("%1 things").arg(nodeThings.count) + : qsTr("Unrecognized device") + progressive: false + ThingsProxy { id: destinationNodeThings engine: _engine