/** * @file OpcUaMonitoredNode.cpp * @brief OpcUaMonitoredNode implementation. */ #include "OpcUaMonitoredNode.h" #include "OpcUaClient.h" #include #include OpcUaMonitoredNode::OpcUaMonitoredNode (QObject *parent) : QObject (parent) {} /* ====================================== * Properties * ====================================== */ QString OpcUaMonitoredNode::nodeId () const { return m_nodeId; } void OpcUaMonitoredNode::setNodeId (const QString &id) { if (m_nodeId == id) return; m_nodeId = id; emit nodeIdChanged (); if (!m_componentComplete) return; teardownNode (); if (OpcUaClient::instance () && OpcUaClient::instance ()->connected ()) setupNode (); } bool OpcUaMonitoredNode::monitored () const { return m_monitored; } void OpcUaMonitoredNode::setMonitored (bool monitored) { if (m_monitored == monitored) return; m_monitored = monitored; emit monitoredChanged (); } QVariant OpcUaMonitoredNode::value () const { return m_value; } OpcUaNodeInfo OpcUaMonitoredNode::info () const { return m_info; } /* ====================================== * QQmlParserStatus * ====================================== */ void OpcUaMonitoredNode::classBegin () { } 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 (); } }