Fix destination node selection for Zigbee bindings

pull/884/head
Michael Zanetti 2022-09-16 00:41:39 +02:00
parent d6fe4d9249
commit e95724b375
4 changed files with 151 additions and 68 deletions

View File

@ -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)

View File

@ -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})
}

View File

@ -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 {

View File

@ -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