From 690db0fa630ac57d0ec99010862c7b7e4a7ac589 Mon Sep 17 00:00:00 2001 From: Thomas Vanbesien Date: Fri, 20 Feb 2026 12:16:50 +0100 Subject: Implement OpcUaMonitoredNode attribute reading with OpcUaNodeInfo gadget --- src/OpcUaMonitoredNode.cpp | 157 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) (limited to 'src/OpcUaMonitoredNode.cpp') diff --git a/src/OpcUaMonitoredNode.cpp b/src/OpcUaMonitoredNode.cpp index f7a5c9f..0ffe300 100644 --- a/src/OpcUaMonitoredNode.cpp +++ b/src/OpcUaMonitoredNode.cpp @@ -3,9 +3,17 @@ * @brief OpcUaMonitoredNode implementation. */ #include "OpcUaMonitoredNode.h" +#include "OpcUaClient.h" + +#include +#include OpcUaMonitoredNode::OpcUaMonitoredNode (QObject *parent) : QObject (parent) {} +/* ====================================== + * Properties + * ====================================== */ + QString OpcUaMonitoredNode::nodeId () const { @@ -19,6 +27,13 @@ OpcUaMonitoredNode::setNodeId (const QString &id) return; m_nodeId = id; emit nodeIdChanged (); + + if (!m_componentComplete) + return; + + teardownNode (); + if (OpcUaClient::instance () && OpcUaClient::instance ()->connected ()) + setupNode (); } bool @@ -36,6 +51,22 @@ OpcUaMonitoredNode::setMonitored (bool monitored) emit monitoredChanged (); } +QVariant +OpcUaMonitoredNode::value () const +{ + return m_value; +} + +OpcUaNodeInfo +OpcUaMonitoredNode::info () const +{ + return m_info; +} + +/* ====================================== + * QQmlParserStatus + * ====================================== */ + void OpcUaMonitoredNode::classBegin () { @@ -45,4 +76,130 @@ void OpcUaMonitoredNode::componentComplete () { m_componentComplete = true; + + auto *client = OpcUaClient::instance (); + if (!client) + return; + + connect (client, &OpcUaClient::connectedChanged, this, + &OpcUaMonitoredNode::handleClientConnectedChanged); + + if (client->connected () && !m_nodeId.isEmpty ()) + setupNode (); +} + +/* ====================================== + * Node lifecycle + * ====================================== */ + +void +OpcUaMonitoredNode::setupNode () +{ + if (m_node || m_nodeId.isEmpty ()) + return; + + auto *client = OpcUaClient::instance (); + if (!client || !client->connected ()) + return; + + m_node = client->opcuaClient ()->node (m_nodeId); + if (!m_node) + return; + + m_node->setParent (this); + + connect (m_node, &QOpcUaNode::attributeUpdated, this, + &OpcUaMonitoredNode::handleAttributeUpdated); + connect (m_node, &QOpcUaNode::valueAttributeUpdated, this, + &OpcUaMonitoredNode::handleValueUpdated); + + m_node->readAttributes ( + QOpcUa::NodeAttribute::Value | QOpcUa::NodeAttribute::DisplayName + | QOpcUa::NodeAttribute::Description | QOpcUa::NodeAttribute::NodeClass + | QOpcUa::NodeAttribute::DataType | QOpcUa::NodeAttribute::AccessLevel); +} + +void +OpcUaMonitoredNode::teardownNode () +{ + if (!m_node) + return; + + delete m_node; + m_node = nullptr; + + m_value.clear (); + emit valueChanged (); + + m_info = OpcUaNodeInfo{}; + emit infoChanged (); +} + +/* ====================================== + * Signal handlers + * ====================================== */ + +void +OpcUaMonitoredNode::handleAttributeUpdated (QOpcUa::NodeAttribute attr, + const QVariant &value) +{ + switch (attr) + { + case QOpcUa::NodeAttribute::DisplayName: + m_info.displayName = value.value ().text (); + break; + case QOpcUa::NodeAttribute::Description: + m_info.description = value.value ().text (); + break; + case QOpcUa::NodeAttribute::NodeClass: + { + auto me = QMetaEnum::fromType (); + auto nc = static_cast (value.toInt ()); + const char *key = me.valueToKey (static_cast (nc)); + m_info.nodeClass + = key ? QLatin1StringView (key) : QStringLiteral ("Unknown"); + } + break; + case QOpcUa::NodeAttribute::DataType: + m_info.dataType = value.toString (); + break; + case QOpcUa::NodeAttribute::AccessLevel: + m_info.accessLevel = value.toUInt (); + break; + default: + return; + } + emit infoChanged (); +} + +void +OpcUaMonitoredNode::handleValueUpdated (const QVariant &value) +{ + m_value = value; + emit valueChanged (); + + m_info.status = QOpcUa::statusToString (m_node->valueAttributeError ()); + m_info.sourceTimestamp + = m_node->sourceTimestamp (QOpcUa::NodeAttribute::Value); + m_info.serverTimestamp + = m_node->serverTimestamp (QOpcUa::NodeAttribute::Value); + emit infoChanged (); +} + +void +OpcUaMonitoredNode::handleClientConnectedChanged () +{ + auto *client = OpcUaClient::instance (); + if (!client) + return; + + if (client->connected ()) + { + if (!m_nodeId.isEmpty ()) + setupNode (); + } + else + { + teardownNode (); + } } -- cgit v1.2.3