diff options
author | Jannis Voelker <jannis.voelker@basyskom.com> | 2023-10-24 15:32:47 +0200 |
---|---|---|
committer | Jannis Voelker <jannis.voelker@basyskom.com> | 2023-12-07 14:42:21 +0100 |
commit | c23cccdd17e0529946f0e923a85378e070817c93 (patch) | |
tree | 924577b16ef9f79d9cf76862322216b1151fdc18 /tests | |
parent | bba934aebc0cc37f012cea446258ec9b2cc106c9 (diff) |
Implement triggering for monitored items
This change adds an API to create and remove a triggering link
between two monitored items on the same subscription.
[ChangeLog][Qt OPC UA] QOpcUaNode now supports SetTriggering
to set up a triggering link between two monitored items.
Change-Id: Ieea1ccf78d8f71d7bde4cd1487d5926ec6ae988c
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Frank Meerkoetter <frank.meerkoetter@basyskom.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/qopcuaclient/tst_client.cpp | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/tests/auto/qopcuaclient/tst_client.cpp b/tests/auto/qopcuaclient/tst_client.cpp index b7fe080..c025f68 100644 --- a/tests/auto/qopcuaclient/tst_client.cpp +++ b/tests/auto/qopcuaclient/tst_client.cpp @@ -554,6 +554,10 @@ private slots: defineDataMethod(dataChangeSubscriptionSharing_data) void dataChangeSubscriptionSharing(); defineDataMethod(methodCall_data) + void dataChangeSubscriptionTriggering(); + defineDataMethod(dataChangeSubscriptionTriggering_data); + void dataChangeSubscriptionModifyTriggering(); + defineDataMethod(dataChangeSubscriptionModifyTriggering_data); void methodCall(); defineDataMethod(methodCallInvalid_data) void methodCallInvalid(); @@ -2512,6 +2516,170 @@ void Tst_QOpcUaClient::dataChangeSubscriptionSharing() QCOMPARE(attrs.size(), 0); } +void Tst_QOpcUaClient::dataChangeSubscriptionTriggering() +{ + QFETCH(QOpcUaClient *, opcuaClient); + OpcuaConnector connector(opcuaClient, m_endpoint); + + // Setup triggered node and write node + QScopedPointer<QOpcUaNode> writeNode(opcuaClient->node("ns=2;s=Demo.Static.Scalar.Int32")); + QScopedPointer<QOpcUaNode> triggeredNode(opcuaClient->node("ns=2;s=Demo.Static.Scalar.Int32")); + + WRITE_VALUE_ATTRIBUTE(writeNode, 1, QOpcUa::Types::Int32); + + QOpcUaMonitoringParameters triggeredParams(50); + triggeredParams.setMonitoringMode(QOpcUaMonitoringParameters::MonitoringMode::Sampling); + triggeredParams.setQueueSize(10); + + triggeredNode->enableMonitoring(QOpcUa::NodeAttribute::Value, triggeredParams); + QSignalSpy monitoringEnabledSpy2(triggeredNode.data(), &QOpcUaNode::enableMonitoringFinished); + QSignalSpy valueChangedSpy(triggeredNode.data(), &QOpcUaNode::attributeUpdated); + monitoringEnabledSpy2.wait(signalSpyTimeout); + + QCOMPARE(monitoringEnabledSpy2.size(), 1); + QCOMPARE(monitoringEnabledSpy2.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value); + const auto triggeredStatus = triggeredNode->monitoringStatus(QOpcUa::NodeAttribute::Value); + QCOMPARE(triggeredStatus.statusCode(), QOpcUa::UaStatusCode::Good); + + // Setup trigger + QScopedPointer<QOpcUaNode> triggeringNode(opcuaClient->node(readWriteNode)); + QVERIFY(triggeringNode != nullptr); + QSignalSpy monitoringEnabledSpy(triggeringNode.data(), &QOpcUaNode::enableMonitoringFinished); + + QOpcUaMonitoringParameters triggerParameters(50); + triggerParameters.setSubscriptionId(triggeredStatus.subscriptionId()); + triggerParameters.setTriggeredItemIds({ triggeredStatus.monitoredItemId(), 10, 11 }); + triggeringNode->enableMonitoring(QOpcUa::NodeAttribute::Value, triggerParameters); + monitoringEnabledSpy.wait(signalSpyTimeout); + + QCOMPARE(monitoringEnabledSpy.size(), 1); + QCOMPARE(monitoringEnabledSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value); + QCOMPARE(triggeringNode->monitoringStatus(QOpcUa::NodeAttribute::Value).statusCode(), QOpcUa::UaStatusCode::Good); + + const auto triggerStatus = triggeringNode->monitoringStatus(QOpcUa::NodeAttribute::Value); + QVERIFY(triggerStatus.subscriptionId() != 0); + QCOMPARE(triggerStatus.statusCode(), QOpcUa::UaStatusCode::Good); + QCOMPARE(triggerStatus.subscriptionId(), triggeredStatus.subscriptionId()); + QCOMPARE(triggerStatus.triggeredItemIds(), QSet<quint32>{ triggeredStatus.monitoredItemId() }); + QCOMPARE(triggerStatus.failedTriggeredItemsStatus(), + (QHash<quint32, QOpcUa::UaStatusCode>{ + { 10, QOpcUa::UaStatusCode::BadMonitoredItemIdInvalid }, + { 11, QOpcUa::UaStatusCode::BadMonitoredItemIdInvalid } + })); + + // Create value change, trigger and check results + + WRITE_VALUE_ATTRIBUTE(writeNode, 2, QOpcUa::Types::Int32); + + valueChangedSpy.wait(1000); + QCOMPARE(valueChangedSpy.size(), 0); + + WRITE_VALUE_ATTRIBUTE(triggeringNode, 1234.0, QOpcUa::Types::Double); + + valueChangedSpy.wait(signalSpyTimeout); + QCOMPARE(valueChangedSpy.size(), 1); + QCOMPARE(valueChangedSpy.at(0).at(1).value<quint32>(), 2); +} + +void Tst_QOpcUaClient::dataChangeSubscriptionModifyTriggering() +{ + QFETCH(QOpcUaClient *, opcuaClient); + OpcuaConnector connector(opcuaClient, m_endpoint); + + // Setup triggered and write nodes + QScopedPointer<QOpcUaNode> writeNode(opcuaClient->node("ns=2;s=Demo.Static.Scalar.Int32")); + QScopedPointer<QOpcUaNode> triggeredNode(opcuaClient->node("ns=2;s=Demo.Static.Scalar.Int32")); + + WRITE_VALUE_ATTRIBUTE(writeNode, 1, QOpcUa::Types::Int32); + + QOpcUaMonitoringParameters triggeredParams(50); + triggeredParams.setMonitoringMode(QOpcUaMonitoringParameters::MonitoringMode::Sampling); + triggeredParams.setQueueSize(10); + + triggeredNode->enableMonitoring(QOpcUa::NodeAttribute::Value, triggeredParams); + QSignalSpy monitoringEnabledSpy2(triggeredNode.data(), &QOpcUaNode::enableMonitoringFinished); + QSignalSpy valueChangedSpy(triggeredNode.data(), &QOpcUaNode::attributeUpdated); + monitoringEnabledSpy2.wait(); + + QCOMPARE(monitoringEnabledSpy2.size(), 1); + QCOMPARE(monitoringEnabledSpy2.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value); + const auto triggeredStatus = triggeredNode->monitoringStatus(QOpcUa::NodeAttribute::Value); + QCOMPARE(triggeredStatus.statusCode(), QOpcUa::UaStatusCode::Good); + + // Setup triggering node + QScopedPointer<QOpcUaNode> triggeringNode(opcuaClient->node(readWriteNode)); + QVERIFY(triggeringNode != nullptr); + QSignalSpy monitoringEnabledSpy(triggeringNode.data(), &QOpcUaNode::enableMonitoringFinished); + + QOpcUaMonitoringParameters triggerSettings(50); + triggerSettings.setSubscriptionId(triggeredStatus.subscriptionId()); + triggeringNode->enableMonitoring(QOpcUa::NodeAttribute::Value, triggerSettings); + monitoringEnabledSpy.wait(signalSpyTimeout); + + QCOMPARE(monitoringEnabledSpy.size(), 1); + QCOMPARE(monitoringEnabledSpy.at(0).at(0).value<QOpcUa::NodeAttribute>(), QOpcUa::NodeAttribute::Value); + auto triggerStatus = triggeringNode->monitoringStatus(QOpcUa::NodeAttribute::Value); + QCOMPARE(triggerStatus.statusCode(), QOpcUa::UaStatusCode::Good); + QCOMPARE(triggerStatus.subscriptionId(), triggeredStatus.subscriptionId()); + QCOMPARE(triggerStatus.statusCode(), QOpcUa::UaStatusCode::Good); + + // Write, nothing should happen + WRITE_VALUE_ATTRIBUTE(writeNode, 2, QOpcUa::Types::Int32); + + valueChangedSpy.wait(1000); + QCOMPARE(valueChangedSpy.size(), 0); + + WRITE_VALUE_ATTRIBUTE(triggeringNode, 1235.0, QOpcUa::Types::Double); + + valueChangedSpy.wait(1000); + QCOMPARE(valueChangedSpy.size(), 0); + + // Modify triggering node to actually trigger + QSignalSpy modifySpy(triggeringNode.get(), &QOpcUaNode::monitoringStatusChanged); + triggeringNode->modifyMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters::Parameter::TriggeredItemIds, + QVariant::fromValue(QSet<quint32>{triggeredStatus.monitoredItemId(), 10, 11})); + modifySpy.wait(signalSpyTimeout); + QCOMPARE(modifySpy.size(), 1); + QCOMPARE(modifySpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good); + QCOMPARE(triggeringNode->monitoringStatus(QOpcUa::NodeAttribute::Value).triggeredItemIds(), + QSet<quint32>{triggeredStatus.monitoredItemId()}); + QCOMPARE(triggeringNode->monitoringStatus(QOpcUa::NodeAttribute::Value).failedTriggeredItemsStatus(), + (QHash<quint32, QOpcUa::UaStatusCode>{ + { 10, QOpcUa::UaStatusCode::BadMonitoredItemIdInvalid }, + { 11, QOpcUa::UaStatusCode::BadMonitoredItemIdInvalid } + })); + + WRITE_VALUE_ATTRIBUTE(writeNode, 3, QOpcUa::Types::Int32); + + valueChangedSpy.wait(1000); + QCOMPARE(valueChangedSpy.size(), 0); + + WRITE_VALUE_ATTRIBUTE(triggeringNode, 1236.0, QOpcUa::Types::Double); + + valueChangedSpy.wait(signalSpyTimeout); + QCOMPARE(valueChangedSpy.size(), 1); + QCOMPARE(valueChangedSpy.at(0).at(1).value<quint32>(), 3); + + modifySpy.clear(); + triggeringNode->modifyMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters::Parameter::TriggeredItemIds, + QVariant::fromValue(QSet<quint32>())); + modifySpy.wait(); + QCOMPARE(modifySpy.size(), 1); + QCOMPARE(modifySpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good); + QCOMPARE(triggeredNode->monitoringStatus(QOpcUa::NodeAttribute::Value).triggeredItemIds(), QSet<quint32>()); + + valueChangedSpy.clear(); + WRITE_VALUE_ATTRIBUTE(writeNode, 4, QOpcUa::Types::Int32); + + valueChangedSpy.wait(1000); + QCOMPARE(valueChangedSpy.size(), 0); + + WRITE_VALUE_ATTRIBUTE(triggeringNode, 1237.0, QOpcUa::Types::Double); + + valueChangedSpy.wait(1000); + QCOMPARE(valueChangedSpy.size(), 0); +} + void Tst_QOpcUaClient::methodCall() { QFETCH(QOpcUaClient *, opcuaClient); |