diff options
Diffstat (limited to 'demo/NodePage.qml')
| -rw-r--r-- | demo/NodePage.qml | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/demo/NodePage.qml b/demo/NodePage.qml new file mode 100644 index 0000000..e4862d8 --- /dev/null +++ b/demo/NodePage.qml @@ -0,0 +1,164 @@ +// NodePage.qml — Monitors a single OPC UA node. +// Two instances demonstrate visibility lifecycle: switching pages +// stops monitoring on the hidden page automatically. + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Bobink + +Page { + id: nodePage + + required property StackView stackRef + required property int pageNumber + required property var logFunction + + property string monitoredNodeId: "" + property string nodeDescription: "" + property bool nodeWritable: true + property bool metadataLoaded: false + + BobinkNode { + id: node + nodeId: nodePage.monitoredNodeId + onAttributeRead: (name, val) => { + if (name === "DisplayName") + nodePage.nodeDescription = val.toString(); + else if (name === "AccessLevel") + nodePage.nodeWritable = (val & 0x02) !== 0; + nodePage.metadataLoaded = true; + } + onWriteError: (message) => nodePage.logFunction("WRITE: " + message) + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: 20 + spacing: 12 + + RowLayout { + Label { + text: "Node Page " + nodePage.pageNumber + font.bold: true + font.pointSize: 14 + } + Item { Layout.fillWidth: true } + Button { + text: "Disconnect" + onClicked: BobinkClient.disconnectFromServer() + } + } + + RowLayout { + TextField { + id: nodeIdField + Layout.fillWidth: true + placeholderText: "ns=2;s=Temperature" + enabled: !nodePage.monitoredNodeId + } + Button { + text: nodePage.monitoredNodeId ? "Stop" : "Monitor" + onClicked: { + if (nodePage.monitoredNodeId) { + nodePage.monitoredNodeId = ""; + nodePage.nodeDescription = ""; + nodePage.nodeWritable = true; + nodePage.metadataLoaded = false; + } else { + nodePage.monitoredNodeId = nodeIdField.text; + node.readAttribute("DisplayName"); + node.readAttribute("AccessLevel"); + } + } + } + } + + GroupBox { + Layout.fillWidth: true + visible: nodePage.monitoredNodeId.length > 0 + title: nodePage.nodeDescription || nodePage.monitoredNodeId + + GridLayout { + columns: 2 + width: parent.width + + Label { text: "Value:" } + Label { + text: node.value !== undefined ? node.value.toString() : "—" + font.family: "monospace" + font.bold: true + } + + Label { text: "Status:" } + Label { + text: node.status === BobinkNode.Good ? "Good" + : node.status === BobinkNode.Uncertain ? "Uncertain" + : "Bad" + color: node.status === BobinkNode.Good ? "green" + : node.status === BobinkNode.Uncertain ? "orange" + : "red" + } + + Label { text: "Source TS:" } + Label { + text: node.sourceTimestamp.toLocaleString( + Qt.locale(), "HH:mm:ss.zzz") + font.family: "monospace" + } + + Label { text: "Server TS:" } + Label { + text: node.serverTimestamp.toLocaleString( + Qt.locale(), "HH:mm:ss.zzz") + font.family: "monospace" + } + } + } + + RowLayout { + visible: nodePage.monitoredNodeId.length > 0 + + TextField { + id: writeField + Layout.fillWidth: true + enabled: nodePage.nodeWritable + placeholderText: nodePage.metadataLoaded && !nodePage.nodeWritable + ? "Read-only node" : "Value to write" + } + Button { + text: "Write" + enabled: nodePage.nodeWritable + onClicked: { + node.value = writeField.text; + writeField.clear(); + } + } + } + + Label { + visible: nodePage.monitoredNodeId.length > 0 + && nodePage.metadataLoaded && !nodePage.nodeWritable + text: "Read-only node" + font.italic: true + color: "gray" + } + + Item { Layout.fillHeight: true } + + Button { + Layout.fillWidth: true + text: nodePage.pageNumber === 1 ? "Go to Page 2" : "Back to Page 1" + onClicked: { + if (nodePage.pageNumber === 1) + nodePage.stackRef.push("NodePage.qml", { + stackRef: nodePage.stackRef, + pageNumber: 2, + logFunction: nodePage.logFunction + }); + else + nodePage.stackRef.pop(); + } + } + } +} |
