diff options
author | Rainer Keller <Rainer.Keller@qt.io> | 2019-04-29 13:14:14 +0200 |
---|---|---|
committer | Rainer Keller <Rainer.Keller@qt.io> | 2019-05-17 10:15:56 +0000 |
commit | 387309bd295256dd1668fc7fa7de979331763a77 (patch) | |
tree | 58f1afe3b8ab5f1498b3858d9a9832c470c23042 | |
parent | 7ce99deb73f854b367139212b6042b4ce4e06b8e (diff) |
qml: Add data change filter support
Change-Id: Ib0e8d10f298a63fb7b3892cd61ac5e4c12b4d56f
Reviewed-by: Jannis Völker <jannis.voelker@basyskom.com>
-rw-r--r-- | src/imports/opcua/opcua.pro | 2 | ||||
-rw-r--r-- | src/imports/opcua/opcua_plugin.cpp | 2 | ||||
-rw-r--r-- | src/imports/opcua/opcuadatachangefilter.cpp | 114 | ||||
-rw-r--r-- | src/imports/opcua/opcuadatachangefilter.h | 93 | ||||
-rw-r--r-- | src/imports/opcua/opcuavaluenode.cpp | 46 | ||||
-rw-r--r-- | src/imports/opcua/opcuavaluenode.h | 9 | ||||
-rw-r--r-- | tests/auto/declarative/DataChangeFilterTest.qml | 186 | ||||
-rw-r--r-- | tests/auto/declarative/tst_dataChangeFilter.qml | 41 | ||||
-rw-r--r-- | tests/auto/declarative/tst_generic.qml | 2 |
9 files changed, 493 insertions, 2 deletions
diff --git a/src/imports/opcua/opcua.pro b/src/imports/opcua/opcua.pro index e53cf6c..dd3cc01 100644 --- a/src/imports/opcua/opcua.pro +++ b/src/imports/opcua/opcua.pro @@ -22,6 +22,7 @@ SOURCES += \ opcuastatus.cpp \ opcuawriteitem.cpp \ opcuawriteresult.cpp \ + opcuadatachangefilter.cpp \ HEADERS += \ opcua_plugin.h \ @@ -45,6 +46,7 @@ HEADERS += \ opcuastatus.h \ opcuawriteitem.h \ opcuawriteresult.h \ + opcuadatachangefilter.h \ load(qml_plugin) diff --git a/src/imports/opcua/opcua_plugin.cpp b/src/imports/opcua/opcua_plugin.cpp index 3fc8ac6..4c2c51b 100644 --- a/src/imports/opcua/opcua_plugin.cpp +++ b/src/imports/opcua/opcua_plugin.cpp @@ -41,6 +41,7 @@ #include "opcuanodeid.h" #include "opcuanodeidtype.h" #include "opcuaconnection.h" +#include "opcuadatachangefilter.h" #include "opcuarelativenodepath.h" #include "opcuarelativenodeid.h" #include "qopcuatype.h" @@ -145,6 +146,7 @@ void OpcUaPlugin::registerTypes(const char *uri) qmlRegisterType<OpcUaEndpointDiscovery>(uri, major, minor, "EndpointDiscovery"); qmlRegisterType<OpcUaServerDiscovery>(uri, major, minor, "ServerDiscovery"); qmlRegisterUncreatableType<QOpcUaUserTokenPolicy>(uri, major, minor, "UserTokenPolicy", "This type can not be created."); + qmlRegisterType<OpcUaDataChangeFilter>(uri, major, minor, "DataChangeFilter"); // insert new versions here diff --git a/src/imports/opcua/opcuadatachangefilter.cpp b/src/imports/opcua/opcuadatachangefilter.cpp new file mode 100644 index 0000000..fb06839 --- /dev/null +++ b/src/imports/opcua/opcuadatachangefilter.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt OPC UA module. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "opcuadatachangefilter.h" + +QT_BEGIN_NAMESPACE + +OpcUaDataChangeFilter::OpcUaDataChangeFilter(QObject *parent) + : QObject(parent) +{ + +} + +OpcUaDataChangeFilter::OpcUaDataChangeFilter(const OpcUaDataChangeFilter &other) + : QObject(nullptr) + , m_filter(other.filter()) +{ +} + +OpcUaDataChangeFilter::~OpcUaDataChangeFilter() = default; + +OpcUaDataChangeFilter &OpcUaDataChangeFilter::operator=(const OpcUaDataChangeFilter &other) +{ + m_filter = other.filter(); + return *this; +} + +bool OpcUaDataChangeFilter::operator==(const OpcUaDataChangeFilter &other) const +{ + return m_filter == other.filter(); +} + +OpcUaDataChangeFilter::DataChangeTrigger OpcUaDataChangeFilter::trigger() const +{ + return static_cast<OpcUaDataChangeFilter::DataChangeTrigger>(m_filter.trigger()); +} + +OpcUaDataChangeFilter::DeadbandType OpcUaDataChangeFilter::deadbandType() const +{ + return static_cast<OpcUaDataChangeFilter::DeadbandType>(m_filter.deadbandType()); +} + +double OpcUaDataChangeFilter::deadbandValue() const +{ + return m_filter.deadbandValue(); +} + +const QOpcUaMonitoringParameters::DataChangeFilter &OpcUaDataChangeFilter::filter() const +{ + return m_filter; +} + +void OpcUaDataChangeFilter::setTrigger(DataChangeTrigger trigger) +{ + const auto newValue = static_cast<QOpcUaMonitoringParameters::DataChangeFilter::DataChangeTrigger>(trigger); + + if (m_filter.trigger() == newValue) + return; + m_filter.setTrigger(newValue); + emit filterChanged(); +} + +void OpcUaDataChangeFilter::setDeadbandType(DeadbandType deadbandType) +{ + const auto newValue = static_cast<QOpcUaMonitoringParameters::DataChangeFilter::DeadbandType>(deadbandType); + + if (m_filter.deadbandType() == newValue) + return; + m_filter.setDeadbandType(newValue); + emit filterChanged(); +} + +void OpcUaDataChangeFilter::setDeadbandValue(double deadbandValue) +{ + if (deadbandValue == m_filter.deadbandValue()) + return; + m_filter.setDeadbandValue(deadbandValue); + emit filterChanged(); +} + +QT_END_NAMESPACE diff --git a/src/imports/opcua/opcuadatachangefilter.h b/src/imports/opcua/opcuadatachangefilter.h new file mode 100644 index 0000000..753c0f6 --- /dev/null +++ b/src/imports/opcua/opcuadatachangefilter.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt OPC UA module. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OPCUADATACHANGEFILTER +#define OPCUADATACHANGEFILTER + +#include <QOpcUaMonitoringParameters> + +QT_BEGIN_NAMESPACE + +class OpcUaDataChangeFilter : public QObject { + Q_OBJECT + Q_PROPERTY(DataChangeTrigger trigger READ trigger WRITE setTrigger) + Q_PROPERTY(DeadbandType deadbandType READ deadbandType WRITE setDeadbandType) + Q_PROPERTY(double deadbandValue READ deadbandValue WRITE setDeadbandValue) + +public: + // Same as in QOpcUaMonitoringParameters::DataChangeFilter::DataChangeTrigger + enum class DataChangeTrigger { + Status = 0, + StatusOrValue = 1, + StatusOrValueOrTimestamp = 2 + }; + Q_ENUM(DataChangeTrigger) + + // Same as in QOpcUaMonitoringParameters::DataChangeFilter::DeadbandType + enum class DeadbandType { + None = 0, + Absolute = 1, + Percent = 2 + }; + Q_ENUM(DeadbandType) + + explicit OpcUaDataChangeFilter(QObject *parent = nullptr); + OpcUaDataChangeFilter(const OpcUaDataChangeFilter &); + OpcUaDataChangeFilter &operator=(const OpcUaDataChangeFilter &); + bool operator==(const OpcUaDataChangeFilter &) const; + ~OpcUaDataChangeFilter(); + + DataChangeTrigger trigger() const; + DeadbandType deadbandType() const; + double deadbandValue() const; + + const QOpcUaMonitoringParameters::DataChangeFilter &filter() const; + +signals: + void filterChanged(); + +public slots: + void setTrigger(DataChangeTrigger trigger); + void setDeadbandType(DeadbandType deadbandType); + void setDeadbandValue(double deadbandValue); + +private: + QOpcUaMonitoringParameters::DataChangeFilter m_filter; +}; + +QT_END_NAMESPACE + +#endif // OPCUADATACHANGEFILTER diff --git a/src/imports/opcua/opcuavaluenode.cpp b/src/imports/opcua/opcuavaluenode.cpp index 8a51247..cd42595 100644 --- a/src/imports/opcua/opcuavaluenode.cpp +++ b/src/imports/opcua/opcuavaluenode.cpp @@ -102,6 +102,7 @@ OpcUaValueNode::OpcUaValueNode(QObject *parent): OpcUaNode(parent) { connect(m_attributeCache.attribute(QOpcUa::NodeAttribute::Value), &OpcUaAttributeValue::changed, this, &OpcUaValueNode::valueChanged); + connect(this, &OpcUaValueNode::filterChanged, this, &OpcUaValueNode::updateFilters); } OpcUaValueNode::~OpcUaValueNode() @@ -161,6 +162,10 @@ void OpcUaValueNode::setupNode(const QString &absolutePath) m_monitoredState = true; emit monitoredChanged(m_monitoredState); qCDebug(QT_OPCUA_PLUGINS_QML) << "Monitoring was enabled for node" << resolvedNode().fullNodeId(); + if (m_connection->backend() != QLatin1String("open62541")) { + // This line triggers a bug in open62541. When it is fixed the call should be unconditional. + updateFilters(); + } } else { qCWarning(QT_OPCUA_PLUGINS_QML) << "Failed to enable monitoring for node" << resolvedNode().fullNodeId(); setStatus(Status::FailedToSetupMonitoring); @@ -180,7 +185,7 @@ void OpcUaValueNode::setupNode(const QString &absolutePath) }); connect(m_node, &QOpcUaNode::monitoringStatusChanged, this, [this](QOpcUa::NodeAttribute attr, QOpcUaMonitoringParameters::Parameters items, QOpcUa::UaStatusCode statusCode) { - if (attr != QOpcUa::NodeAttribute::Value) + if (attr != QOpcUa::NodeAttribute::Value && attr != QOpcUa::NodeAttribute::EventNotifier) return; if (statusCode != QOpcUa::Good) { setStatus(Status::FailedToModifyMonitoring); @@ -198,6 +203,14 @@ void OpcUaValueNode::setupNode(const QString &absolutePath) updateSubscription(); } +void OpcUaValueNode::updateFilters() const +{ + if (!m_connection || !m_node || !m_filter || !m_monitoredState) + return; + + m_node->modifyDataChangeFilter(QOpcUa::NodeAttribute::Value, m_filter->filter()); +} + bool OpcUaValueNode::checkValidity() { if (!m_connection || !m_node) @@ -242,9 +255,15 @@ void OpcUaValueNode::updateSubscription() if (!m_connection || !m_node) return; + QOpcUaMonitoringParameters parameters; + parameters.setPublishingInterval(m_publishingInterval); + + if (m_filter) + parameters.setFilter(m_filter->filter()); + if (m_monitoredState != m_monitored) { if (m_monitored) { - m_node->enableMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters(m_publishingInterval)); + m_node->enableMonitoring(QOpcUa::NodeAttribute::Value, parameters); } else { m_node->disableMonitoring(QOpcUa::NodeAttribute::Value); } @@ -267,6 +286,29 @@ double OpcUaValueNode::publishingInterval() const return monitoringStatus.publishingInterval(); } +OpcUaDataChangeFilter *OpcUaValueNode::filter() const +{ + return m_filter; +} + +void OpcUaValueNode::setFilter(OpcUaDataChangeFilter *filter) +{ + bool changed = false; + + if (m_filter) { + disconnect(m_filter, &OpcUaDataChangeFilter::filterChanged, this, &OpcUaValueNode::updateFilters); + changed = !(*m_filter == *filter); + } else { + changed = true; + } + + m_filter = filter; + connect(m_filter, &OpcUaDataChangeFilter::filterChanged, this, &OpcUaValueNode::updateFilters); + + if (changed) + emit filterChanged(); +} + void OpcUaValueNode::setPublishingInterval(double publishingInterval) { if (!m_connection || !m_node) diff --git a/src/imports/opcua/opcuavaluenode.h b/src/imports/opcua/opcuavaluenode.h index cafaf41..ff0a929 100644 --- a/src/imports/opcua/opcuavaluenode.h +++ b/src/imports/opcua/opcuavaluenode.h @@ -38,6 +38,7 @@ #include "opcuanode.h" #include <QDateTime> +#include "opcuadatachangefilter.h" QT_BEGIN_NAMESPACE @@ -51,6 +52,7 @@ class OpcUaValueNode : public OpcUaNode Q_PROPERTY(QDateTime sourceTimestamp READ sourceTimestamp) Q_PROPERTY(bool monitored READ monitored WRITE setMonitored NOTIFY monitoredChanged) Q_PROPERTY(double publishingInterval READ publishingInterval WRITE setPublishingInterval NOTIFY publishingIntervalChanged) + Q_PROPERTY(OpcUaDataChangeFilter *filter READ filter WRITE setFilter NOTIFY filterChanged) public: OpcUaValueNode(QObject *parent = nullptr); @@ -62,6 +64,8 @@ public: bool monitored() const; double publishingInterval() const; QOpcUa::Types valueType() const; + OpcUaDataChangeFilter *filter() const; + void setFilter(OpcUaDataChangeFilter *filter); public slots: void setValue(const QVariant &); @@ -69,14 +73,18 @@ public slots: void setPublishingInterval(double publishingInterval); void setValueType(QOpcUa::Types valueType); + signals: void valueChanged(const QVariant &value); void monitoredChanged(bool monitored); void publishingIntervalChanged(double publishingInterval); + void dataChangeOccurred(const QVariant &value); + void filterChanged(); private slots: void setupNode(const QString &absolutePath) override; void updateSubscription(); + void updateFilters() const; private: bool checkValidity() override; @@ -84,6 +92,7 @@ private: bool m_monitoredState = false; double m_publishingInterval = 100; QOpcUa::Types m_valueType = QOpcUa::Types::Undefined; + OpcUaDataChangeFilter *m_filter = nullptr; }; QT_END_NAMESPACE diff --git a/tests/auto/declarative/DataChangeFilterTest.qml b/tests/auto/declarative/DataChangeFilterTest.qml new file mode 100644 index 0000000..2ca77f7 --- /dev/null +++ b/tests/auto/declarative/DataChangeFilterTest.qml @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt OPC UA module. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 +import QtTest 1.0 +import QtOpcUa 5.13 as QtOpcUa + +Item { + property string backendName + property int completedTestCases: 0 + property int availableTestCases: 0 + property bool completed: completedTestCases == availableTestCases && availableTestCases > 0 + property bool shouldRun: false + + onShouldRunChanged: { + if (shouldRun) + console.log("Running", parent.testName, "with", backendName); + } + + QtOpcUa.Connection { + id: connection + backend: backendName + defaultConnection: true + } + + QtOpcUa.ServerDiscovery { + id: serverDiscovery + onServersChanged: { + if (!count) + return; + endpointDiscovery.serverUrl = at(0).discoveryUrls[0]; + } + + Binding on discoveryUrl { + when: shouldRun && Component.completed + value: "opc.tcp://127.0.0.1:43344" + } + } + + QtOpcUa.EndpointDiscovery { + id: endpointDiscovery + onEndpointsChanged: { + if (!count) + return; + connection.connectToEndpoint(at(0)); + } + } + + Component.onCompleted: { + for (var i in children) { + if (children[i].objectName == "TestCase") + availableTestCases += 1; + } + } + + Timer { + id: timer + interval: 2000 + } + + CompletionLoggingTestCase { + name: "Data Change Filter" + when: node1.readyToUse && shouldRun + + function test_nodeTest() { + tryCompare(node1, "monitored", true); + compare(node2.monitored, false); + compare(node1.publishingInterval, 100.0); + + compare(node1.filter.deadbandType, 1); + compare(node1.filter.trigger, 1); + compare(node1.filter.deadbandValue, 1); + if (node1ValueSpy.count == 0) + node1ValueSpy.wait(); + + verify(node1.value != 1.5); + + node1ValueSpy.clear(); + node2ValueSpy.clear(); + node2.value = 1.5; + node2ValueSpy.wait(); // wait for value written + timer.running = true; + timerSpy.wait(); + compare(node1ValueSpy.count, 0); + compare(node1.value, 1.0); // still 1.0 because of filtering + + node1ValueSpy.clear(); + node2ValueSpy.clear(); + verify(node1.value != 30); + node2.value = 30.0; + verify(node1.value != 30); + node2ValueSpy.wait(); // wait for value written + node1ValueSpy.wait(); + compare(node1.value, 30); + compare(node1ValueSpy.count, 1); + + // Reset values + node1ValueSpy.clear(); + node2ValueSpy.clear(); + node2.value = 1.0; + node2ValueSpy.wait(); // wait for value written + node1ValueSpy.wait(); + compare(node1ValueSpy.count, 1); + compare(node1.value, 1.0); + } + + SignalSpy { + id: node1ValueSpy + target: node1 + signalName: "valueChanged" + } + + SignalSpy { + id: node2ValueSpy + target: node2 + signalName: "valueChanged" + } + + QtOpcUa.ValueNode { + connection: connection + nodeId: QtOpcUa.NodeId { + ns: "http://qt-project.org" + identifier: "s=Demo.Static.Scalar.Double" + } + id: node1 + + filter: QtOpcUa.DataChangeFilter { + deadbandValue: 1.0 + deadbandType: QtOpcUa.DataChangeFilter.DeadbandType.Absolute + trigger: QtOpcUa.DataChangeFilter.DataChangeTrigger.StatusOrValue + } + + } + + QtOpcUa.ValueNode { + connection: connection + nodeId: QtOpcUa.NodeId { + ns: "http://qt-project.org" + identifier: "s=Demo.Static.Scalar.Double" + } + id: node2 + monitored: false + } + + SignalSpy { + id: timerSpy + target: timer + signalName: "triggered" + } + } +} + + diff --git a/tests/auto/declarative/tst_dataChangeFilter.qml b/tests/auto/declarative/tst_dataChangeFilter.qml new file mode 100644 index 0000000..9e35ff0 --- /dev/null +++ b/tests/auto/declarative/tst_dataChangeFilter.qml @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt OPC UA module. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 + +BackendTestMultiplier { + testName: "DataChangeFilterTest" +} diff --git a/tests/auto/declarative/tst_generic.qml b/tests/auto/declarative/tst_generic.qml index 7bf98fd..ad9ae82 100644 --- a/tests/auto/declarative/tst_generic.qml +++ b/tests/auto/declarative/tst_generic.qml @@ -50,6 +50,8 @@ Item { compare(QtOpcUa.Status.BadUnexpectedError, 0x8001); compare(QtOpcUa.Constants.Double, 3); compare(QtOpcUa.Constants.Certificate, 2); + compare(QtOpcUa.DataChangeFilter.DeadbandType.Absolute, 1); + compare(QtOpcUa.DataChangeFilter.DataChangeTrigger.StatusOrValueOrTimestamp, 2); // Test return value of undefined node compare(node1.nodeClass, QtOpcUa.Constants.NodeClass.Undefined); |