From 6c142a234673e442561b2c050b727aa4400177d8 Mon Sep 17 00:00:00 2001 From: Thomas Vanbesien Date: Fri, 20 Feb 2026 14:50:39 +0100 Subject: Wire monitored property to OPC UA monitored items MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The monitored bool now calls enableMonitoring/disableMonitoring on the Value attribute. Adds publishingInterval property (default 100ms). Value is no longer read at init — delivered by the monitored item. Empty 4th demo page to verify monitoring stops when navigating away. --- demo/NodePage.qml | 20 ++++++++++-- src/OpcUaMonitoredNode.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++++-- src/OpcUaMonitoredNode.h | 13 ++++++++ 3 files changed, 104 insertions(+), 5 deletions(-) diff --git a/demo/NodePage.qml b/demo/NodePage.qml index 442a6fd..a8e07d5 100644 --- a/demo/NodePage.qml +++ b/demo/NodePage.qml @@ -57,6 +57,12 @@ Page { "ns=1;s=double_rw_array", "ns=1;s=string_rw_array" ] + }, + { + title: "Empty (Monitoring Test)", + description: "No nodes on this page. All previous pages are inactive," + + " so the server log should show zero active monitored items.", + nodes: [] } ] @@ -78,7 +84,7 @@ Page { font.pointSize: 14 } Label { - text: "(" + nodePage.pageNumber + "/3)" + text: "(" + nodePage.pageNumber + "/" + nodePage.pages.length + ")" color: "gray" } Item { Layout.fillWidth: true } @@ -88,6 +94,16 @@ Page { } } + Label { + id: pageDescription + visible: currentPage.description !== undefined + text: currentPage.description || "" + wrapMode: Text.WordWrap + color: "gray" + font.italic: true + Layout.fillWidth: true + } + // Column headers RowLayout { Layout.fillWidth: true @@ -216,7 +232,7 @@ Page { Item { Layout.fillWidth: true } Button { text: "Next →" - visible: nodePage.pageNumber < 3 + visible: nodePage.pageNumber < nodePage.pages.length onClicked: nodePage.stackRef.push("NodePage.qml", { stackRef: nodePage.stackRef, pageNumber: nodePage.pageNumber + 1, diff --git a/src/OpcUaMonitoredNode.cpp b/src/OpcUaMonitoredNode.cpp index 518ddd5..1a2da86 100644 --- a/src/OpcUaMonitoredNode.cpp +++ b/src/OpcUaMonitoredNode.cpp @@ -7,6 +7,7 @@ #include #include +#include #include OpcUaMonitoredNode::OpcUaMonitoredNode (QObject *parent) : QObject (parent) {} @@ -51,6 +52,29 @@ OpcUaMonitoredNode::setMonitored (bool monitored) return; m_monitored = monitored; emit monitoredChanged (); + + if (!m_componentComplete || !m_node) + return; + + if (m_monitored) + startMonitoring (); + else + stopMonitoring (); +} + +double +OpcUaMonitoredNode::publishingInterval () const +{ + return m_publishingInterval; +} + +void +OpcUaMonitoredNode::setPublishingInterval (double interval) +{ + if (qFuzzyCompare (m_publishingInterval, interval)) + return; + m_publishingInterval = interval; + emit publishingIntervalChanged (); } QVariant @@ -122,11 +146,18 @@ OpcUaMonitoredNode::setupNode () &OpcUaMonitoredNode::handleValueUpdated); connect (m_node, &QOpcUaNode::attributeWritten, this, &OpcUaMonitoredNode::handleAttributeWritten); + connect (m_node, &QOpcUaNode::enableMonitoringFinished, this, + &OpcUaMonitoredNode::handleEnableMonitoringFinished); + connect (m_node, &QOpcUaNode::disableMonitoringFinished, this, + &OpcUaMonitoredNode::handleDisableMonitoringFinished); m_node->readAttributes ( - QOpcUa::NodeAttribute::Value | QOpcUa::NodeAttribute::DisplayName - | QOpcUa::NodeAttribute::Description | QOpcUa::NodeAttribute::NodeClass - | QOpcUa::NodeAttribute::DataType | QOpcUa::NodeAttribute::AccessLevel); + QOpcUa::NodeAttribute::DisplayName | QOpcUa::NodeAttribute::Description + | QOpcUa::NodeAttribute::NodeClass | QOpcUa::NodeAttribute::DataType + | QOpcUa::NodeAttribute::AccessLevel); + + if (m_monitored) + startMonitoring (); } void @@ -153,6 +184,23 @@ OpcUaMonitoredNode::teardownNode () } } +void +OpcUaMonitoredNode::startMonitoring () +{ + if (!m_node || !m_monitored) + return; + QOpcUaMonitoringParameters params (m_publishingInterval); + m_node->enableMonitoring (QOpcUa::NodeAttribute::Value, params); +} + +void +OpcUaMonitoredNode::stopMonitoring () +{ + if (!m_node) + return; + m_node->disableMonitoring (QOpcUa::NodeAttribute::Value); +} + /* ====================================== * Signal handlers * ====================================== */ @@ -262,6 +310,28 @@ OpcUaMonitoredNode::handleAttributeWritten (QOpcUa::NodeAttribute attr, : QOpcUa::statusToString (statusCode)); } +void +OpcUaMonitoredNode::handleEnableMonitoringFinished ( + QOpcUa::NodeAttribute attr, QOpcUa::UaStatusCode statusCode) +{ + if (attr != QOpcUa::NodeAttribute::Value) + return; + if (statusCode != QOpcUa::Good) + qWarning () << "OpcUaMonitoredNode: enableMonitoring failed for" + << m_nodeId << ":" << QOpcUa::statusToString (statusCode); +} + +void +OpcUaMonitoredNode::handleDisableMonitoringFinished ( + QOpcUa::NodeAttribute attr, QOpcUa::UaStatusCode statusCode) +{ + if (attr != QOpcUa::NodeAttribute::Value) + return; + if (statusCode != QOpcUa::Good) + qWarning () << "OpcUaMonitoredNode: disableMonitoring failed for" + << m_nodeId << ":" << QOpcUa::statusToString (statusCode); +} + /* ====================================== * Write support * ====================================== */ diff --git a/src/OpcUaMonitoredNode.h b/src/OpcUaMonitoredNode.h index 5895bea..3e86cb4 100644 --- a/src/OpcUaMonitoredNode.h +++ b/src/OpcUaMonitoredNode.h @@ -56,6 +56,8 @@ class OpcUaMonitoredNode : public QObject, public QQmlParserStatus Q_PROPERTY (QString nodeId READ nodeId WRITE setNodeId NOTIFY nodeIdChanged) Q_PROPERTY ( bool monitored READ monitored WRITE setMonitored NOTIFY monitoredChanged) + Q_PROPERTY (double publishingInterval READ publishingInterval WRITE + setPublishingInterval NOTIFY publishingIntervalChanged) Q_PROPERTY (QVariant value READ value NOTIFY valueChanged) Q_PROPERTY (bool writable READ writable NOTIFY writableChanged) Q_PROPERTY (OpcUaNodeInfo info READ info NOTIFY infoChanged) @@ -69,6 +71,9 @@ public: bool monitored () const; void setMonitored (bool monitored); + double publishingInterval () const; + void setPublishingInterval (double interval); + QVariant value () const; bool writable () const; OpcUaNodeInfo info () const; @@ -89,6 +94,7 @@ public: signals: void nodeIdChanged (); void monitoredChanged (); + void publishingIntervalChanged (); void valueChanged (); void writableChanged (); void infoChanged (); @@ -101,14 +107,21 @@ private slots: void handleClientConnectedChanged (); void handleAttributeWritten (QOpcUa::NodeAttribute attr, QOpcUa::UaStatusCode statusCode); + void handleEnableMonitoringFinished (QOpcUa::NodeAttribute attr, + QOpcUa::UaStatusCode statusCode); + void handleDisableMonitoringFinished (QOpcUa::NodeAttribute attr, + QOpcUa::UaStatusCode statusCode); private: void setupNode (); void teardownNode (); + void startMonitoring (); + void stopMonitoring (); QVariant coerceValue (const QVariant &input) const; QString m_nodeId; bool m_monitored = true; + double m_publishingInterval = 100.0; bool m_componentComplete = false; QOpcUaNode *m_node = nullptr; -- cgit v1.2.3