From 3d1e4c225541bd50f6bfe41884dab84f6b8bad8c Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Fri, 9 Sep 2022 00:46:47 +0200 Subject: [PATCH] Improvements in the ZigBee topology map --- libnymea-app/libnymea-app-core.h | 1 + libnymea-app/zigbee/zigbeemanager.cpp | 2 +- nymea-app/images.qrc | 16 +- nymea-app/ui/components/SelectionTabs.qml | 3 +- nymea-app/ui/images/arrow-down.svg | 165 +++++ nymea-app/ui/images/transfer-error.svg | 170 +++++ nymea-app/ui/images/transfer-none.svg | 165 +++++ nymea-app/ui/images/transfer-paused.svg | 181 ++++++ .../ui/images/transfer-progress-download.svg | 165 +++++ .../ui/images/transfer-progress-upload.svg | 165 +++++ ...igbee-router.svg => transfer-progress.svg} | 103 +-- nymea-app/ui/images/zigbee/zigbee-child.svg | 196 ++++++ .../ui/images/zigbee/zigbee-coordinator.svg | 222 +++++++ .../ui/images/zigbee/zigbee-enddevice.svg | 212 +++++++ nymea-app/ui/images/zigbee/zigbee-parent.svg | 196 ++++++ .../zigbee-previous-child.svg} | 105 ++- nymea-app/ui/images/zigbee/zigbee-router.svg | 204 ++++++ nymea-app/ui/images/zigbee/zigbee-sibling.svg | 206 ++++++ .../ui/system/zigbee/ZigbeeNetworkPage.qml | 10 +- .../ui/system/zigbee/ZigbeeTopologyPage.qml | 598 ++++++++++++++++-- .../ui/system/zwave/ZWaveNetworkPage.qml | 6 +- 21 files changed, 2898 insertions(+), 193 deletions(-) create mode 100644 nymea-app/ui/images/arrow-down.svg create mode 100644 nymea-app/ui/images/transfer-error.svg create mode 100644 nymea-app/ui/images/transfer-none.svg create mode 100644 nymea-app/ui/images/transfer-paused.svg create mode 100644 nymea-app/ui/images/transfer-progress-download.svg create mode 100644 nymea-app/ui/images/transfer-progress-upload.svg rename nymea-app/ui/images/{zigbee-router.svg => transfer-progress.svg} (52%) create mode 100644 nymea-app/ui/images/zigbee/zigbee-child.svg create mode 100644 nymea-app/ui/images/zigbee/zigbee-coordinator.svg create mode 100644 nymea-app/ui/images/zigbee/zigbee-enddevice.svg create mode 100644 nymea-app/ui/images/zigbee/zigbee-parent.svg rename nymea-app/ui/images/{zigbee-enddevice.svg => zigbee/zigbee-previous-child.svg} (50%) create mode 100644 nymea-app/ui/images/zigbee/zigbee-router.svg create mode 100644 nymea-app/ui/images/zigbee/zigbee-sibling.svg diff --git a/libnymea-app/libnymea-app-core.h b/libnymea-app/libnymea-app-core.h index 7a9bd264..240d45e0 100644 --- a/libnymea-app/libnymea-app-core.h +++ b/libnymea-app/libnymea-app-core.h @@ -330,6 +330,7 @@ void registerQmlTypes() { qmlRegisterUncreatableType(uri, 1, 0, "ZigbeeNetworks", "Get it from the ZigbeeManager"); qmlRegisterUncreatableType(uri, 1, 0, "ZigbeeNode", "Get it from the ZigbeeNodes"); qmlRegisterUncreatableType(uri, 1, 0, "ZigbeeNodeNeighbor", "Get it from the ZigbeeNode"); + qmlRegisterUncreatableType(uri, 1, 0, "ZigbeeNodeRoute", "Get it from the ZigbeeNode"); qmlRegisterUncreatableType(uri, 1, 0, "ZigbeeNodes", "Get it from the ZigbeeNetwork"); qmlRegisterType(uri, 1, 0, "ZigbeeNodesProxy"); diff --git a/libnymea-app/zigbee/zigbeemanager.cpp b/libnymea-app/zigbee/zigbeemanager.cpp index f6d8b146..94ccff65 100644 --- a/libnymea-app/zigbee/zigbeemanager.cpp +++ b/libnymea-app/zigbee/zigbeemanager.cpp @@ -409,7 +409,7 @@ void ZigbeeManager::updateNodeProperties(ZigbeeNode *node, const QVariantMap &no node->setRxOnWhenIdle(nodeMap.value("receiverOnWhileIdle").toBool()); node->setReachable(nodeMap.value("reachable").toBool()); node->setLqi(nodeMap.value("lqi").toUInt()); - node->setLastSeen(QDateTime::fromMSecsSinceEpoch(nodeMap.value("lastSeen").toUInt() * 1000)); + node->setLastSeen(QDateTime::fromMSecsSinceEpoch(nodeMap.value("lastSeen").toULongLong() * 1000)); QList neighbors; foreach (const QVariant &neighbor, nodeMap.value("neighborTableRecords").toList()) { QVariantMap neighborMap = neighbor.toMap(); diff --git a/nymea-app/images.qrc b/nymea-app/images.qrc index 36397a87..6a5b4b5b 100644 --- a/nymea-app/images.qrc +++ b/nymea-app/images.qrc @@ -263,8 +263,6 @@ ui/images/setupwizard/wired-connection.svg ui/images/setupwizard/wireless-connection.svg ui/images/system-suspend.svg - ui/images/zigbee-enddevice.svg - ui/images/zigbee-router.svg ui/images/sensors/o2.svg ui/images/sensors/ph.svg ui/images/sensors/orp.svg @@ -277,5 +275,19 @@ ui/images/z-wave.svg ui/images/zwave/z-wave-plus-wide.svg ui/images/zwave/z-wave-wide.svg + ui/images/transfer-error.svg + ui/images/transfer-none.svg + ui/images/transfer-paused.svg + ui/images/transfer-progress.svg + ui/images/transfer-progress-download.svg + ui/images/transfer-progress-upload.svg + ui/images/zigbee/zigbee-child.svg + ui/images/zigbee/zigbee-coordinator.svg + ui/images/zigbee/zigbee-enddevice.svg + ui/images/zigbee/zigbee-parent.svg + ui/images/zigbee/zigbee-router.svg + ui/images/zigbee/zigbee-sibling.svg + ui/images/zigbee/zigbee-previous-child.svg + ui/images/arrow-down.svg diff --git a/nymea-app/ui/components/SelectionTabs.qml b/nymea-app/ui/components/SelectionTabs.qml index 1cab2129..b015cdeb 100644 --- a/nymea-app/ui/components/SelectionTabs.qml +++ b/nymea-app/ui/components/SelectionTabs.qml @@ -6,6 +6,7 @@ import Nymea 1.0 Rectangle { id: root color: Style.tileBackgroundColor + property color selectionColor: Style.tileOverlayColor radius: Style.smallCornerRadius implicitHeight: layout.implicitHeight @@ -22,7 +23,7 @@ Rectangle { Behavior on x { NumberAnimation { duration: 150; easing.type: Easing.InOutQuad } } height: layout.height - 2 width: Math.floor(root.width / repeater.count) - 2 - color: Style.tileOverlayColor + color: root.selectionColor radius: Style.smallCornerRadius } diff --git a/nymea-app/ui/images/arrow-down.svg b/nymea-app/ui/images/arrow-down.svg new file mode 100644 index 00000000..c0a01369 --- /dev/null +++ b/nymea-app/ui/images/arrow-down.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/transfer-error.svg b/nymea-app/ui/images/transfer-error.svg new file mode 100644 index 00000000..ff364f56 --- /dev/null +++ b/nymea-app/ui/images/transfer-error.svg @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/transfer-none.svg b/nymea-app/ui/images/transfer-none.svg new file mode 100644 index 00000000..485fbd0b --- /dev/null +++ b/nymea-app/ui/images/transfer-none.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/transfer-paused.svg b/nymea-app/ui/images/transfer-paused.svg new file mode 100644 index 00000000..c77e770c --- /dev/null +++ b/nymea-app/ui/images/transfer-paused.svg @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/transfer-progress-download.svg b/nymea-app/ui/images/transfer-progress-download.svg new file mode 100644 index 00000000..ac55b39a --- /dev/null +++ b/nymea-app/ui/images/transfer-progress-download.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/transfer-progress-upload.svg b/nymea-app/ui/images/transfer-progress-upload.svg new file mode 100644 index 00000000..b2055759 --- /dev/null +++ b/nymea-app/ui/images/transfer-progress-upload.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/zigbee-router.svg b/nymea-app/ui/images/transfer-progress.svg similarity index 52% rename from nymea-app/ui/images/zigbee-router.svg rename to nymea-app/ui/images/transfer-progress.svg index 796c3bc9..74eaddb3 100644 --- a/nymea-app/ui/images/zigbee-router.svg +++ b/nymea-app/ui/images/transfer-progress.svg @@ -13,9 +13,9 @@ height="96" id="svg4874" version="1.1" - inkscape:version="0.92.3 (2405546, 2018-03-11)" + inkscape:version="0.91+devel r" viewBox="0 0 96 96.000001" - sodipodi:docname="zigbee-router.svg"> + sodipodi:docname="transfer-progress.svg"> + inkscape:snap-global="true"> + id="guide4063" /> + id="guide4065" /> + id="guide4067" /> + id="guide4069" /> + id="guide4071" /> - + id="guide4073" /> + id="guide4077" /> + id="guide4074" /> + id="guide4076" /> + + + id="guide4172" /> - + id="guide4760" /> @@ -133,7 +116,7 @@ image/svg+xml - + @@ -166,33 +149,15 @@ y="345.36221" transform="scale(-1,1)" /> - - - diff --git a/nymea-app/ui/images/zigbee/zigbee-child.svg b/nymea-app/ui/images/zigbee/zigbee-child.svg new file mode 100644 index 00000000..2adb63e5 --- /dev/null +++ b/nymea-app/ui/images/zigbee/zigbee-child.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/zigbee/zigbee-coordinator.svg b/nymea-app/ui/images/zigbee/zigbee-coordinator.svg new file mode 100644 index 00000000..647e04aa --- /dev/null +++ b/nymea-app/ui/images/zigbee/zigbee-coordinator.svg @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/zigbee/zigbee-enddevice.svg b/nymea-app/ui/images/zigbee/zigbee-enddevice.svg new file mode 100644 index 00000000..0ad878ef --- /dev/null +++ b/nymea-app/ui/images/zigbee/zigbee-enddevice.svg @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/zigbee/zigbee-parent.svg b/nymea-app/ui/images/zigbee/zigbee-parent.svg new file mode 100644 index 00000000..4681b16e --- /dev/null +++ b/nymea-app/ui/images/zigbee/zigbee-parent.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/zigbee-enddevice.svg b/nymea-app/ui/images/zigbee/zigbee-previous-child.svg similarity index 50% rename from nymea-app/ui/images/zigbee-enddevice.svg rename to nymea-app/ui/images/zigbee/zigbee-previous-child.svg index 8a9e545c..0ec621da 100644 --- a/nymea-app/ui/images/zigbee-enddevice.svg +++ b/nymea-app/ui/images/zigbee/zigbee-previous-child.svg @@ -2,20 +2,20 @@ + sodipodi:docname="zigbee-previous-child.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + inkscape:window-width="1462" + inkscape:window-height="933" + inkscape:window-x="74" + inkscape:window-y="27" + inkscape:window-maximized="1" + inkscape:pagecheckerboard="0" + inkscape:snap-nodes="false" + inkscape:snap-global="true"> image/svg+xml - @@ -162,45 +164,40 @@ id="rect4782" width="96.037987" height="96" - x="-438.00244" - y="345.36221" - transform="scale(-1,1)" /> + x="341.96445" + y="-441.36221" + transform="scale(1,-1)" /> - - - + cx="550.30798" + cy="-35.5961" + rx="5.1825347" + ry="5.1831102" + transform="matrix(0.70724662,0.70696691,0.70724663,-0.70696691,0,0)" /> + + + diff --git a/nymea-app/ui/images/zigbee/zigbee-router.svg b/nymea-app/ui/images/zigbee/zigbee-router.svg new file mode 100644 index 00000000..3d68fc59 --- /dev/null +++ b/nymea-app/ui/images/zigbee/zigbee-router.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/zigbee/zigbee-sibling.svg b/nymea-app/ui/images/zigbee/zigbee-sibling.svg new file mode 100644 index 00000000..6c6d4d48 --- /dev/null +++ b/nymea-app/ui/images/zigbee/zigbee-sibling.svg @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/system/zigbee/ZigbeeNetworkPage.qml b/nymea-app/ui/system/zigbee/ZigbeeNetworkPage.qml index 81395ba4..645e0711 100644 --- a/nymea-app/ui/system/zigbee/ZigbeeNetworkPage.qml +++ b/nymea-app/ui/system/zigbee/ZigbeeNetworkPage.qml @@ -327,10 +327,10 @@ SettingsPageBase { size: Style.smallIconSize anchors.verticalCenter: parent.verticalCenter name: node.type === ZigbeeNode.ZigbeeNodeTypeCoordinator - ? "/ui/images/zigbee-coordinator.svg" + ? "/ui/images/zigbee/zigbee-coordinator.svg" : node.type === ZigbeeNode.ZigbeeNodeTypeRouter - ? "/ui/images/zigbee-router.svg" - : "/ui/images/zigbee-enddevice.svg" + ? "/ui/images/zigbee/zigbee-router.svg" + : "/ui/images/zigbee/zigbee-enddevice.svg" color: communicationIndicatorLedTimer.running ? Style.accentColor : Style.iconColor } @@ -514,7 +514,7 @@ SettingsPageBase { ColorIcon { Layout.preferredHeight: Style.iconSize Layout.preferredWidth: Style.iconSize - name: "/ui/images/zigbee-router.svg" + name: "/ui/images/zigbee/zigbee-router.svg" } Label { @@ -527,7 +527,7 @@ SettingsPageBase { ColorIcon { Layout.preferredHeight: Style.iconSize Layout.preferredWidth: Style.iconSize - name: "/ui/images/zigbee-enddevice.svg" + name: "/ui/images/zigbee/zigbee-enddevice.svg" } Label { diff --git a/nymea-app/ui/system/zigbee/ZigbeeTopologyPage.qml b/nymea-app/ui/system/zigbee/ZigbeeTopologyPage.qml index e88e14a9..ba10bb2b 100644 --- a/nymea-app/ui/system/zigbee/ZigbeeTopologyPage.qml +++ b/nymea-app/ui/system/zigbee/ZigbeeTopologyPage.qml @@ -1,4 +1,4 @@ -import QtQuick 2.0 +import QtQuick 2.4 import QtQuick.Controls 2.1 import QtQuick.Layouts 1.1 import "qrc:/ui/components" @@ -11,6 +11,14 @@ Page { text: qsTr("ZigBee network topology") backButtonVisible: true onBackPressed: pageStack.pop() + HeaderButton { + imageSource: "/ui/images/help.svg" + text: qsTr("Help") + onClicked: { + var popup = zigbeeHelpDialog.createObject(app) + popup.open() + } + } } property ZigbeeManager zigbeeManager: null @@ -133,6 +141,17 @@ Page { function createNodeItem(node, x, y, angle) { + d.adjustSize(x, y) + + for (var i = 0; i < d.nodeItems.length; i++) { + if (d.nodeItems[i].node == node) { + d.nodeItems[i].x = x; + d.nodeItems[i].y = y; + d.nodeItems[i].angle = angle; + return d.nodeItems[i] + } + } + var icon = "/ui/images/zigbee.svg" var thing = null if (node.networkAddress == 0) { @@ -140,7 +159,7 @@ Page { } else { for (var i = 0; i < engine.thingManager.things.count; i++) { var t = engine.thingManager.things.get(i) -// print("checking thing", t.name) + // print("checking thing", t.name) var param = t.paramByName("ieeeAddress") if (param && param.value == node.ieeeAddress) { thing = t; @@ -167,8 +186,7 @@ Page { thing: thing } -// print("creared node", thing ? thing.name : "", " at", x, y) - d.adjustSize(x, y) + // print("creared node", thing ? thing.name : "", " at", x, y) return nodeItem } @@ -193,9 +211,7 @@ Page { property int selectedNodeAddress: -1 readonly property var selectedNodeItem: { - print("selected", selectedNodeAddress) for (var i = 0; i < nodeItems.length; i++) { - print("checking", nodeItems[i].node.networkAddress) if (nodeItems[i].node.networkAddress === selectedNodeAddress) { return nodeItems[i] } @@ -232,11 +248,10 @@ Page { Flickable { id: flickable anchors.fill: parent + clip: true contentWidth: canvas.width contentHeight: canvas.height -// interactive: true -// flickableDirection: Flickable.HorizontalAndVerticalFlick Canvas { id: canvas @@ -245,7 +260,7 @@ Page { clip: true onPaint: { -// print("**** height:", canvas.height, "width", canvas.width) + // print("**** height:", canvas.height, "width", canvas.width) var ctx = getContext("2d"); ctx.reset(); @@ -354,7 +369,7 @@ Page { ctx.strokeStyle = nodeItem.node.networkAddress === d.selectedNodeAddress ? Style.accentColor : Style.tileBackgroundColor ctx.arc(root.scale * nodeItem.x, root.scale * nodeItem.y, root.scale * root.nodeSize / 2, 0, 2 * Math.PI); ctx.fill(); -// ctx.stroke(); + // ctx.stroke(); ctx.fillStyle = Style.foregroundColor ctx.font = "" + Style.extraSmallFont.pixelSize + "px Ubuntu"; var text = "" @@ -433,11 +448,12 @@ Page { BigTile { + id: infoTile visible: d.selectedNodeAddress >= 0 anchors { top: parent.top right: parent.right - margins: Style.margins + margins: Style.smallMargins } width: 260 @@ -461,15 +477,16 @@ Page { ? selectedThingsProxy.get(0).name : network.nodes.getNodeByNetworkAddress(d.selectedNode).model } + ColorIcon { size: Style.smallIconSize name: { - if (!d.selectedNodeItem) { + if (!d.selectedNode) { return ""; } - var signalStrength = d.selectedNodeItem.node.lqi * 100 / 255 - if (signalStrength === 0) + var signalStrength = 100.0 * d.selectedNode.lqi / 255 + if (!d.selectedNode.reachable) return "/ui/images/connections/nm-signal-00.svg" if (signalStrength <= 25) return "/ui/images/connections/nm-signal-25.svg" @@ -481,66 +498,531 @@ Page { return "/ui/images/connections/nm-signal-100.svg" } } - ColorIcon { - size: Style.smallIconSize - name: "/ui/images/things.svg" - } - ColorIcon { - size: Style.smallIconSize - name: "/ui/images/add.svg" - } } - contentItem: ListView { - id: tableListView -// spacing: app.margins - implicitHeight: Math.min(root.height / 4, count * Style.smallIconSize) - clip: true - model: d.selectedNode ? d.selectedNode.neighbors.length : 0 - - delegate: RowLayout { - id: neighborTableDelegate - width: tableListView.width - property ZigbeeNodeNeighbor neighbor: d.selectedNode.neighbors[index] - property ZigbeeNode neighborNode: root.network.nodes.getNodeByNetworkAddress(neighbor.networkAddress) - property Thing neighborNodeThing: { - for (var i = 0; i < engine.thingManager.things.count; i++) { - var thing = engine.thingManager.things.get(i) - var param = thing.paramByName("ieeeAddress") - if (param && param.value == neighborNode.ieeeAddress) { - return thing - } + contentItem: ColumnLayout { + width: infoTile.width + SelectionTabs { + id: infoSelectionTabs + Layout.fillWidth: true + color: Style.tileOverlayColor + selectionColor: Qt.tint(Style.tileOverlayColor, Qt.rgba(Style.foregroundColor.r, Style.foregroundColor.g, Style.foregroundColor.b, 0.1)) + model: ListModel { + ListElement { + text: qsTr("Device") + } + ListElement { + text: qsTr("Links") + } + ListElement { + text: qsTr("Routes") } - return null } + } + + GridLayout { + Layout.fillWidth: true + visible: infoSelectionTabs.currentIndex == 0 + columns: 2 + columnSpacing: Style.smallMargins Label { + text: qsTr("Address:") + font: Style.smallFont + Layout.fillWidth: true + } + Label { + text: d.selectedNode ? "0x" + d.selectedNode.networkAddress.toString(16) : "" + font: Style.smallFont + horizontalAlignment: Text.AlignRight + Layout.fillWidth: true + } + Label { + text: qsTr("Model:") + font: Style.smallFont + Layout.fillWidth: true + } + Label { + text: d.selectedNode ? d.selectedNode.model : "" + font: Style.smallFont + horizontalAlignment: Text.AlignRight Layout.fillWidth: true elide: Text.ElideRight - font: Style.smallFont - text: neighborTableDelegate.neighbor.networkAddress === 0 - ? Configuration.systemName - : neighborTableDelegate.neighborNodeThing - ? neighborTableDelegate.neighborNodeThing.name - : neighborTableDelegate.neighborNode - ? neighborTableDelegate.neighborNode.model - : "0x" + neighborTableDelegate.neighbor.networkAddress.toString(16) } Label { - text: (neighborTableDelegate.neighbor.lqi * 100 / 255).toFixed(0) + "%" + text: qsTr("Manufacturer:") font: Style.smallFont - horizontalAlignment: Text.AlignRight + Layout.fillWidth: true } Label { - Layout.preferredWidth: Style.smallIconSize + Style.smallMargins + text: d.selectedNode ? d.selectedNode.manufacturer : "" font: Style.smallFont - text: neighborTableDelegate.neighbor.depth horizontalAlignment: Text.AlignRight + Layout.fillWidth: true + elide: Text.ElideRight } - ColorIcon { - size: Style.smallIconSize - name: "add" - opacity: neighborTableDelegate.neighbor.permitJoining ? 1 : 0 + Label { + text: qsTr("Last seen:") + font: Style.smallFont + Layout.fillWidth: true + } + Label { + text: d.selectedNode ? d.selectedNode.lastSeen.toLocaleString(Qt.locale(), Locale.ShortFormat) : "" + font: Style.smallFont + horizontalAlignment: Text.AlignRight + Layout.fillWidth: true + } + } + + ColumnLayout { + visible: infoSelectionTabs.currentIndex == 1 + RowLayout { + Label { + text: qsTr("Neighbor") + font: Style.smallFont + Layout.fillWidth: true + } + ColorIcon { + size: Style.smallIconSize + name: "connections/nm-signal-50" + } + ColorIcon { + size: Style.smallIconSize + name: "zigbee/zigbee-router" + } + Item { + Layout.preferredWidth: Style.smallIconSize + Style.smallMargins + Layout.fillHeight: true + ColorIcon { + anchors.centerIn: parent + size: Style.smallIconSize + name: "arrow-down" + } + } + + ColorIcon { + size: Style.smallIconSize + name: "add" + } + } + ThinDivider { + color: Style.foregroundColor + } + + ListView { + id: neighborTableListView + Layout.fillWidth: true + // spacing: app.margins + implicitHeight: Math.min(root.height / 4, count * Style.smallIconSize) + clip: true + model: d.selectedNode ? d.selectedNode.neighbors.length : 0 + + delegate: RowLayout { + id: neighborTableDelegate + width: neighborTableListView.width + property ZigbeeNodeNeighbor neighbor: d.selectedNode.neighbors[index] + property ZigbeeNode neighborNode: root.network.nodes.getNodeByNetworkAddress(neighbor.networkAddress) + property Thing neighborNodeThing: { + for (var i = 0; i < engine.thingManager.things.count; i++) { + var thing = engine.thingManager.things.get(i) + var param = thing.paramByName("ieeeAddress") + if (param && param.value == neighborNode.ieeeAddress) { + return thing + } + } + return null + } + + Label { + Layout.fillWidth: true + elide: Text.ElideRight + font: Style.smallFont + text: neighborTableDelegate.neighbor.networkAddress === 0 + ? Configuration.systemName + : neighborTableDelegate.neighborNodeThing + ? neighborTableDelegate.neighborNodeThing.name + : neighborTableDelegate.neighborNode + ? neighborTableDelegate.neighborNode.model + : "0x" + neighborTableDelegate.neighbor.networkAddress.toString(16) + color: neighborTableDelegate.neighborNode ? Style.foregroundColor : Style.red + } + Label { + text: (neighborTableDelegate.neighbor.lqi * 100 / 255).toFixed(0) + "%" + font: Style.smallFont + horizontalAlignment: Text.AlignRight + } + ColorIcon { + size: Style.smallIconSize + name: { + switch (neighborTableDelegate.neighbor.relationship) { + case ZigbeeNode.ZigbeeNodeRelationshipChild: + return "zigbee/zigbee-child" + case ZigbeeNode.ZigbeeNodeRelationshipParent: + return "zigbee/zigbee-parent" + case ZigbeeNode.ZigbeeNodeRelationshipSibling: + return "zigbee/zigbee-sibling" + case ZigbeeNode.ZigbeeNodeRelationshipPreviousChild: + return "zigbee/zigbee-previous-child" + } + return "" + } + } + + Label { + Layout.preferredWidth: Style.smallIconSize + Style.smallMargins + font: Style.smallFont + text: neighborTableDelegate.neighbor.depth + horizontalAlignment: Text.AlignRight + } + Item { + Layout.preferredWidth: Style.smallIconSize + Layout.preferredHeight: Style.smallIconSize + + Led { + anchors.fill: parent + anchors.margins: Style.smallIconSize / 4 + state: neighborTableDelegate.neighbor.permitJoining ? "on" : "off" + } + } + + } + } + + } + ColumnLayout { + visible: infoSelectionTabs.currentIndex == 2 + RowLayout { + Label { + id: toLabel + text: qsTr("To") + font: Style.smallFont + Layout.fillWidth: true + } + Label { + id: viaLabel + text: qsTr("Via") + font: Style.smallFont + Layout.fillWidth: true + } + ColorIcon { + size: Style.smallIconSize + name: "transfer-progress" + } + } + ThinDivider { + color: Style.foregroundColor + } + ListView { + id: routesListView + Layout.fillWidth: true + implicitHeight: Math.min(root.height / 4, count * Style.smallIconSize) + clip: true + model: d.selectedNode ? d.selectedNode.routes.length : 0 + + delegate: RowLayout { + id: routesTableDelegate + width: routesListView.width + property ZigbeeNodeRoute route: d.selectedNode.routes[index] + property ZigbeeNode destinationNode: root.network.nodes.getNodeByNetworkAddress(route.destinationAddress) + property Thing destinationNodeThing: { + for (var i = 0; i < engine.thingManager.things.count; i++) { + var thing = engine.thingManager.things.get(i) + var param = thing.paramByName("ieeeAddress") + if (param && param.value == destinationNode.ieeeAddress) { + return thing + } + } + return null + } + property ZigbeeNode nextHopNode: root.network.nodes.getNodeByNetworkAddress(route.nextHopAddress) + property Thing nextHopNodeThing: { + for (var i = 0; i < engine.thingManager.things.count; i++) { + var thing = engine.thingManager.things.get(i) + var param = thing.paramByName("ieeeAddress") + if (param && param.value == nextHopNode.ieeeAddress) { + return thing + } + } + return null + } + + Label { + Layout.preferredWidth: toLabel.width + elide: Text.ElideRight + font: Style.smallFont + text: routesTableDelegate.route.destinationAddress === 0 + ? Configuration.systemName + : routesTableDelegate.destinationNodeThing + ? routesTableDelegate.destinationNodeThing.name + : routesTableDelegate.destinationNode + ? routesTableDelegate.destinationNode.model + : "0x" + routesTableDelegate.route.destinationAddress.toString(16) + } + Label { + Layout.preferredWidth: viaLabel.width + elide: Text.ElideRight + font: Style.smallFont + text: routesTableDelegate.route.nextHopAddress === 0 + ? Configuration.systemName + : routesTableDelegate.nextHopNodeThing + ? routesTableDelegate.nextHopNodeThing.name + : routesTableDelegate.nextHopNode + ? routesTableDelegate.nextHopNode.model + : "0x" + routesTableDelegate.route.nextHopAddress.toString(16) + } + ColorIcon { + name: { + switch (routesTableDelegate.route.status) { + case ZigbeeNode.ZigbeeNodeRouteStatusActive: + return "tick" + case ZigbeeNode.ZigbeeNodeRouteStatusDiscoveryFailed: + return "dialog-error-symbolic" + case ZigbeeNode.ZigbeeNodeRouteStatusDiscoveryUnderway: + return "find" + case ZigbeeNode.ZigbeeNodeRouteStatusInactive: + return "dialog-warning-symbolic" + case ZigbeeNode.ZigbeeNodeRouteStatusValidationUnderway: + return "system-update" + } + } + size: Style.smallIconSize + color: routesTableDelegate.route.memoryConstrained ? Style.orange : Style.foregroundColor + } + } + } + } + } + } + + Component { + id: zigbeeHelpDialog + + MeaDialog { + id: dialog + title: qsTr("ZigBee topology help") + + Flickable { + implicitHeight: helpColumn.implicitHeight + Layout.fillWidth: true + Layout.fillHeight: true + contentHeight: helpColumn.implicitHeight + clip: true + + ColumnLayout { + id: helpColumn + width: parent.width + + ListSectionHeader { + text: qsTr("Map") + } + RowLayout { + ColumnLayout { + Layout.preferredWidth: Style.iconSize + Rectangle { + Layout.fillWidth: true + height: 2 + color: Style.green + } + Rectangle { + Layout.fillWidth: true + height: 2 + color: Style.orange + } + Rectangle { + Layout.fillWidth: true + height: 2 + color: Style.red + } + } + Label { + Layout.fillWidth: true + text: qsTr("Links between nodes") + } + } + RowLayout { + ColumnLayout { + Layout.preferredWidth: Style.iconSize + Rectangle { + Layout.fillWidth: true + height: 2 + color: Style.blue + } + } + Label { + Layout.fillWidth: true + text: qsTr("Route to coordinator") + } + } + + ListSectionHeader { + text: qsTr("Links") + } + + + RowLayout { + spacing: Style.margins + ColorIcon { + size: Style.iconSize + name: "zigbee/zigbee-coordinator" + } + + Label { + text: qsTr("Node relationship") + } + } + + RowLayout { + spacing: Style.margins + ColorIcon { + Layout.preferredHeight: Style.iconSize + Layout.preferredWidth: Style.iconSize + name: "zigbee/zigbee-sibling" + } + + Label { + text: qsTr("Sibling") + } + } + RowLayout { + spacing: Style.margins + ColorIcon { + Layout.preferredHeight: Style.iconSize + Layout.preferredWidth: Style.iconSize + name: "zigbee/zigbee-parent" + } + + Label { + text: qsTr("Parent") + } + } + RowLayout { + spacing: Style.margins + ColorIcon { + Layout.preferredHeight: Style.iconSize + Layout.preferredWidth: Style.iconSize + name: "zigbee/zigbee-child" + } + + Label { + text: qsTr("Child") + } + } + + RowLayout { + spacing: Style.margins + ColorIcon { + Layout.preferredHeight: Style.iconSize + Layout.preferredWidth: Style.iconSize + name: "zigbee/zigbee-previous-child" + } + + Label { + text: qsTr("Previous child") + } + } + + RowLayout { + spacing: Style.margins + ColorIcon { + Layout.preferredHeight: Style.iconSize + Layout.preferredWidth: Style.iconSize + name: "/ui/images/arrow-down.svg" + } + + Label { + text: qsTr("Depth in network") + } + } + RowLayout { + spacing: Style.margins + ColorIcon { + Layout.preferredHeight: Style.iconSize + Layout.preferredWidth: Style.iconSize + name: "add" + } + + Label { + text: qsTr("Permit join") + } + } + + ListSectionHeader { + text: qsTr("Routes") + } + + RowLayout { + spacing: Style.margins + ColorIcon { + Layout.preferredHeight: Style.iconSize + Layout.preferredWidth: Style.iconSize + name: "transfer-progress" + } + + Label { + text: qsTr("Route status") + } + } + + RowLayout { + spacing: Style.margins + ColorIcon { + Layout.preferredHeight: Style.iconSize + Layout.preferredWidth: Style.iconSize + name: "tick" + } + + Label { + text: qsTr("Route active") + } + } + RowLayout { + spacing: Style.margins + ColorIcon { + Layout.preferredHeight: Style.iconSize + Layout.preferredWidth: Style.iconSize + name: "dialog-warning-symbolic" + } + + Label { + text: qsTr("Route inactive") + } + } + RowLayout { + spacing: Style.margins + ColorIcon { + Layout.preferredHeight: Style.iconSize + Layout.preferredWidth: Style.iconSize + name: "dialog-error-symbolic" + } + + Label { + text: qsTr("Route failed") + } + } + RowLayout { + spacing: Style.margins + ColorIcon { + Layout.preferredHeight: Style.iconSize + Layout.preferredWidth: Style.iconSize + name: "find" + } + + Label { + text: qsTr("Discovery in progress") + } + } + RowLayout { + spacing: Style.margins + ColorIcon { + Layout.preferredHeight: Style.iconSize + Layout.preferredWidth: Style.iconSize + name: "system-update" + } + + Label { + text: qsTr("Validation in progress") + } + } } } } diff --git a/nymea-app/ui/system/zwave/ZWaveNetworkPage.qml b/nymea-app/ui/system/zwave/ZWaveNetworkPage.qml index b82cb945..c4dc6dad 100644 --- a/nymea-app/ui/system/zwave/ZWaveNetworkPage.qml +++ b/nymea-app/ui/system/zwave/ZWaveNetworkPage.qml @@ -329,9 +329,9 @@ SettingsPageBase { case ZWaveNode.ZWaveNodeTypeStaticController: return "/ui/images/z-wave.svg" case ZWaveNode.ZWaveNodeTypeRoutingSlave: - return "/ui/images/zigbee-router.svg" + return "/ui/images/zigbee/zigbee-router.svg" case ZWaveNode.ZWaveNodeTypeSlave: - return "/ui/images/zigbee-enddevice.svg" + return "/ui/images/zigbee/zigbee-enddevice.svg" } } color: communicationIndicatorLedTimer.running ? Style.accentColor : Style.iconColor @@ -576,7 +576,7 @@ SettingsPageBase { ColorIcon { Layout.preferredHeight: Style.iconSize Layout.preferredWidth: Style.iconSize - name: "/ui/images/zigbee-router.svg" + name: "/ui/images/zigbee/zigbee-router.svg" } Label {