summaryrefslogtreecommitdiffstats
path: root/src/imports/opcua/opcuanode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/imports/opcua/opcuanode.cpp')
-rw-r--r--src/imports/opcua/opcuanode.cpp277
1 files changed, 264 insertions, 13 deletions
diff --git a/src/imports/opcua/opcuanode.cpp b/src/imports/opcua/opcuanode.cpp
index 28fe73c..d81f287 100644
--- a/src/imports/opcua/opcuanode.cpp
+++ b/src/imports/opcua/opcuanode.cpp
@@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE
\since QtOpcUa 5.12
\code
- import QtOpcUa 5.12 as QtOpcUa
+ import QtOpcUa 5.13 as QtOpcUa
QtOpcUa.Node {
nodeId : QtOpcUa.NodeId {
@@ -134,12 +134,59 @@ QT_BEGIN_NAMESPACE
a default constructed \l LocalizedText is returned.
*/
+/*!
+ \qmlproperty Status Node::status
+ \readonly
+
+ Current status of the node. The node is only usable when the status is \c Valid.
+ In any other case it indicates an error.
+
+ \sa errorMessage, Status
+*/
+
+/*!
+ \qmlproperty string Node::errorMessage
+ \readonly
+
+ A string representation of the current status code.
+
+ \sa status, Status
+*/
+
+/*!
+ \qmlproperty enumeration Node::Status
+
+ Status of a node.
+
+ \value Node.Status.Valid Node is ready for use
+ \value Node.Status.InvalidNodeId Node id is invalid
+ \value Node.Status.NoConnection Not connected to a server
+ \value Node.Status.InvalidNodeType Node type on the server does not match the QML type
+ \value Node.Status.InvalidClient Invalid connection client
+ \value Node.Status.FailedToResolveNode Failed to resolve node
+ \value Node.Status.InvalidObjectNode The object node is invalid or its type does not match the expected type
+ \value Node.Status.FailedToReadAttributes Failed to read attributes
+ \value Node.Status.FailedToSetupMonitoring Failed to setup monitoring
+
+ \sa status, errorMessage
+*/
+
+/*!
+ \qmlproperty EventFilter Node::eventFilter
+ \since 5.13
+
+ An event filter allows monitoring events on the server for certain conditions.
+
+ \sa EventFilter
+*/
+
Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_QML)
OpcUaNode::OpcUaNode(QObject *parent):
QObject(parent),
m_nodeId(new OpcUaNodeIdType(this)),
- m_attributesToRead(QOpcUaNode::mandatoryBaseAttributes())
+ m_attributesToRead(QOpcUaNode::mandatoryBaseAttributes()),
+ m_status(Status::InvalidNodeId)
{
m_attributesToRead |= QOpcUa::NodeAttribute::Description;
connect(&m_resolvedNode, &UniversalNode::nodeChanged, this, &OpcUaNode::nodeChanged);
@@ -179,12 +226,12 @@ void OpcUaNode::setBrowseName(const QString &value)
if (!m_resolvedNode.isNamespaceIndexValid())
return;
- m_node->writeAttribute(QOpcUa::NodeAttribute::BrowseName, QOpcUa::QQualifiedName(m_resolvedNode.namespaceIndex(), value));
+ m_node->writeAttribute(QOpcUa::NodeAttribute::BrowseName, QOpcUaQualifiedName(m_resolvedNode.namespaceIndex(), value));
}
QString OpcUaNode::browseName()
{
- return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::BrowseName).value<QOpcUa::QQualifiedName>().name();
+ return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>().name();
}
QOpcUa::NodeClass OpcUaNode::nodeClass()
@@ -192,28 +239,62 @@ QOpcUa::NodeClass OpcUaNode::nodeClass()
return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::NodeClass).value<QOpcUa::NodeClass>();
}
-void OpcUaNode::setDisplayName(const QOpcUa::QLocalizedText &value)
+void OpcUaNode::setDisplayName(const QOpcUaLocalizedText &value)
{
if (!m_connection || !m_node)
return;
m_node->writeAttribute(QOpcUa::NodeAttribute::DisplayName, value);
}
-QOpcUa::QLocalizedText OpcUaNode::displayName()
+QOpcUaLocalizedText OpcUaNode::displayName()
{
- return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::DisplayName).value<QOpcUa::QLocalizedText>();
+ return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>();
}
-void OpcUaNode::setDescription(const QOpcUa::QLocalizedText &value)
+void OpcUaNode::setDescription(const QOpcUaLocalizedText &value)
{
if (!m_connection || !m_node)
return;
m_node->writeAttribute(QOpcUa::NodeAttribute::Description, value);
}
-QOpcUa::QLocalizedText OpcUaNode::description()
+QOpcUaLocalizedText OpcUaNode::description()
+{
+ return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::Description).value<QOpcUaLocalizedText>();
+}
+
+OpcUaNode::Status OpcUaNode::status() const
+{
+ return m_status;
+}
+
+const QString &OpcUaNode::errorMessage() const
+{
+ return m_errorMessage;
+}
+
+/*!
+ \qmlmethod Date Node::getSourceTimestamp(QOpcUa::NodeAttribute attribute)
+
+ Returns the source timestamp of the given \a attribute.
+*/
+QDateTime OpcUaNode::getSourceTimestamp(QOpcUa::NodeAttribute attribute) const
+{
+ if (!m_connection || !m_node)
+ return QDateTime();
+ return m_node->sourceTimestamp(attribute);
+}
+
+/*!
+ \qmlmethod Date Node::getServerTimestamp(Constants::NodeAttribute attribute)
+
+ Returns the server timestamp of the given \a attribute.
+*/
+QDateTime OpcUaNode::getServerTimestamp(QOpcUa::NodeAttribute attribute) const
{
- return m_attributeCache.attributeValue(QOpcUa::NodeAttribute::Description).value<QOpcUa::QLocalizedText>();
+ if (!m_connection || !m_node)
+ return QDateTime();
+ return m_node->serverTimestamp(attribute);
}
void OpcUaNode::setNodeId(OpcUaNodeIdType *nodeId)
@@ -278,9 +359,52 @@ void OpcUaNode::setupNode(const QString &absoluteNodePath)
setReadyToUse(true);
});
+ connect(m_node, &QOpcUaNode::enableMonitoringFinished, this, [this](QOpcUa::NodeAttribute attr, QOpcUa::UaStatusCode statusCode){
+ if (attr != QOpcUa::NodeAttribute::EventNotifier)
+ return;
+ if (statusCode == QOpcUa::Good) {
+ m_eventFilterActive = true;
+ qCDebug(QT_OPCUA_PLUGINS_QML) << "Event filter was enabled for node" << resolvedNode().fullNodeId();
+ updateEventFilter();
+ } else {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Failed to enable event filter for node" << resolvedNode().fullNodeId();
+ setStatus(Status::FailedToSetupMonitoring);
+ }
+ });
+
+ connect(m_node, &QOpcUaNode::disableMonitoringFinished, this, [this](QOpcUa::NodeAttribute attr, QOpcUa::UaStatusCode statusCode){
+ if (attr != QOpcUa::NodeAttribute::EventNotifier)
+ return;
+ if (statusCode == QOpcUa::Good) {
+ m_eventFilterActive = false;
+ qCDebug(QT_OPCUA_PLUGINS_QML) << "Event filter was disabled for node "<< resolvedNode().fullNodeId();
+ } else {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Failed to disable event filter for node "<< resolvedNode().fullNodeId();
+ setStatus(Status::FailedToDisableMonitoring);
+ }
+ });
+
+ connect(m_node, &QOpcUaNode::monitoringStatusChanged, this, [this](QOpcUa::NodeAttribute attr, QOpcUaMonitoringParameters::Parameters items,
+ QOpcUa::UaStatusCode statusCode) {
+ Q_UNUSED(items);
+ if (attr != QOpcUa::NodeAttribute::EventNotifier)
+ return;
+ if (statusCode != QOpcUa::Good) {
+ setStatus(Status::FailedToModifyMonitoring);
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Failed to modify event filter for" << m_node->nodeId();
+ }
+ });
+
+ connect (m_node, &QOpcUaNode::eventOccurred, this, &OpcUaNode::eventOccurred);
+
+
// Read mandatory attributes
- if (!m_node->readAttributes(m_attributesToRead))
+ if (!m_node->readAttributes(m_attributesToRead)) {
qCWarning(QT_OPCUA_PLUGINS_QML) << "Reading attributes" << m_node->nodeId() << "failed";
+ setStatus(Status::FailedToReadAttributes);
+ }
+
+ updateEventFilter();
}
void OpcUaNode::updateNode()
@@ -288,6 +412,109 @@ void OpcUaNode::updateNode()
retrieveAbsoluteNodePath(m_nodeId, [this](const QString &absoluteNodePath) {setupNode(absoluteNodePath);});
}
+OpcUaEventFilter *OpcUaNode::eventFilter() const
+{
+ return m_eventFilter;
+}
+
+void OpcUaNode::setEventFilter(OpcUaEventFilter *eventFilter)
+{
+ bool changed = false;
+
+ if (m_eventFilter) {
+ disconnect(m_eventFilter, &OpcUaEventFilter::dataChanged, this, &OpcUaNode::updateEventFilter);
+ changed = !(*m_eventFilter == *eventFilter);
+ } else {
+ changed = true;
+ }
+
+ m_eventFilter = eventFilter;
+ connect(m_eventFilter, &OpcUaEventFilter::dataChanged, this, &OpcUaNode::updateEventFilter);
+
+ if (changed)
+ emit eventFilterChanged();
+}
+
+
+void OpcUaNode::updateEventFilter()
+{
+ if (!m_connection || !m_node || !m_eventFilter)
+ return;
+
+ if (m_eventFilterActive) {
+ m_node->modifyEventFilter(m_eventFilter->filter(m_connection->m_client));
+ } else {
+ QOpcUaMonitoringParameters parameters;
+ parameters.setFilter(m_eventFilter->filter(m_connection->m_client));
+ m_node->enableMonitoring(QOpcUa::NodeAttribute::EventNotifier, parameters);
+ m_eventFilterActive = true;
+ }
+}
+
+void OpcUaNode::setStatus(OpcUaNode::Status status, const QString &message)
+{
+ QString errorMessage(message);
+ bool emitStatusChanged = false;
+ bool emitErrorMessageChanged = false;
+
+ if (m_status != status) {
+ m_status = status;
+ emitStatusChanged = true;
+ }
+
+ // if error message is not given, use default error message
+ if (errorMessage.isEmpty()) {
+ switch (m_status) {
+ case Status::Valid:
+ errorMessage = tr("Node is valid");
+ break;
+ case Status::InvalidNodeId:
+ errorMessage = tr("Node Id is invalid");
+ break;
+ case Status::NoConnection:
+ errorMessage = tr("Not connected to server");
+ break;
+ case Status::InvalidNodeType:
+ errorMessage = tr("QML element does not match node type on the server");
+ break;
+ case Status::InvalidClient:
+ errorMessage = tr("Connecting client is invalid");
+ break;
+ case Status::FailedToResolveNode:
+ errorMessage = tr("Failed to resolve node");
+ break;
+ case Status::InvalidObjectNode:
+ errorMessage = tr("Invalid object node");
+ break;
+ case Status::FailedToReadAttributes:
+ errorMessage = tr("Failed to read attributes");
+ break;
+ case Status::FailedToSetupMonitoring:
+ errorMessage = tr("Failed to setup monitoring");
+ break;
+ case Status::FailedToWriteAttribute:
+ errorMessage = tr("Failed to write attribute");
+ break;
+ case Status::FailedToModifyMonitoring:
+ errorMessage = tr("Failed to modify monitoring");
+ break;
+ case Status::FailedToDisableMonitoring:
+ errorMessage = tr("Failed to disable monitoring");
+ break;
+ }
+ }
+
+ if (errorMessage != m_errorMessage) {
+ m_errorMessage = errorMessage;
+ emitErrorMessageChanged = true;
+ }
+
+ if (emitStatusChanged)
+ emit statusChanged();
+ if (emitErrorMessageChanged)
+ emit errorMessageChanged();
+}
+
const UniversalNode &OpcUaNode::resolvedNode() const
{
return m_resolvedNode;
@@ -311,8 +538,19 @@ QOpcUa::NodeAttributes OpcUaNode::attributesToRead() const
void OpcUaNode::retrieveAbsoluteNodePath(OpcUaNodeIdType *node, std::function<void (const QString &)> functor)
{
auto conn = connection();
- if (!conn || !m_nodeId || !conn->m_client) {
- qCWarning(QT_OPCUA_PLUGINS_QML) << "connection, nodeID or client is invalid";
+ if (!conn) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "No connection to server";
+ setStatus(Status::NoConnection);
+ return;
+ }
+ if (!m_nodeId) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Invalid node ID";
+ setStatus(Status::InvalidNodeId);
+ return;
+ }
+ if (!conn->m_client) {
+ qCWarning(QT_OPCUA_PLUGINS_QML) << "Client instance is invalid";
+ setStatus(Status::InvalidClient);
return;
}
@@ -336,6 +574,7 @@ void OpcUaNode::retrieveAbsoluteNodePath(OpcUaNodeIdType *node, std::function<vo
if (!errorMessage.isEmpty()) {
qCWarning(QT_OPCUA_PLUGINS_QML) << "Failed to resolve node:" << errorMessage;
+ setStatus(Status::FailedToResolveNode, errorMessage);
functor(QString());
return;
}
@@ -353,10 +592,22 @@ void OpcUaNode::retrieveAbsoluteNodePath(OpcUaNodeIdType *node, std::function<vo
void OpcUaNode::setReadyToUse(bool value)
{
+ if (value && !checkValidity())
+ value = false;
+
bool old = m_readyToUse;
m_readyToUse = value;
+
+ if (value)
+ setStatus(Status::Valid);
+
if (!old && value)
emit readyToUseChanged();
}
+bool OpcUaNode::checkValidity()
+{
+ return true;
+}
+
QT_END_NAMESPACE