From 3526e1261de6c33268e951d3378a40333835c213 Mon Sep 17 00:00:00 2001 From: "nikolai.shipilov" Date: Fri, 20 Feb 2026 13:09:57 +0100 Subject: [PATCH 1/6] Import changes from openDAQ/openDAQ#981 --- modules/opcua_client_module/src/opcua_client_module_impl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 0ceb21a..631b726 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -115,6 +116,7 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, .addAddressInfo(addressInfo) .freeze(); + device.asPtr(true).setAsRoot(); return device; } From 2dc7bfc70bd2dc1de8ff92df876327564daecbf1 Mon Sep 17 00:00:00 2001 From: "nikolai.shipilov" Date: Fri, 20 Feb 2026 13:13:33 +0100 Subject: [PATCH 2/6] Change opendaq target branch --- opendaq_ref | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendaq_ref b/opendaq_ref index 88d050b..494ec86 100644 --- a/opendaq_ref +++ b/opendaq_ref @@ -1 +1 @@ -main \ No newline at end of file +other/rework_active_attr \ No newline at end of file From 28b4f49ae5d15d19cb47cd2715277c70fb2108c8 Mon Sep 17 00:00:00 2001 From: Denis Erokhin Date: Thu, 26 Feb 2026 09:22:06 +0100 Subject: [PATCH 3/6] move the active test for opcua from opendaq to opcua module itself --- .../opcua_client_module/tests/CMakeLists.txt | 2 + .../tests/test_opcua_device_module.cpp | 94 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 modules/opcua_client_module/tests/test_opcua_device_module.cpp diff --git a/modules/opcua_client_module/tests/CMakeLists.txt b/modules/opcua_client_module/tests/CMakeLists.txt index 7deb68f..6b684dd 100644 --- a/modules/opcua_client_module/tests/CMakeLists.txt +++ b/modules/opcua_client_module/tests/CMakeLists.txt @@ -2,6 +2,7 @@ set(MODULE_NAME opcua_client_module) set(TEST_APP test_${MODULE_NAME}) set(TEST_SOURCES test_opcua_client_module.cpp + test_opcua_device_module.cpp test_app.cpp ) @@ -10,6 +11,7 @@ add_executable(${TEST_APP} ${TEST_SOURCES} target_link_libraries(${TEST_APP} PRIVATE ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_test_utils gtest ${OPENDAQ_SDK_TARGET_NAMESPACE}::${MODULE_NAME} + ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_mocks ) add_test(NAME ${TEST_APP} diff --git a/modules/opcua_client_module/tests/test_opcua_device_module.cpp b/modules/opcua_client_module/tests/test_opcua_device_module.cpp new file mode 100644 index 0000000..47701fd --- /dev/null +++ b/modules/opcua_client_module/tests/test_opcua_device_module.cpp @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include + +using OpcuaDeviceModulesTest = testing::Test; + +using namespace daq; + +static InstancePtr CreateServerInstance() +{ + auto instance = InstanceBuilder().setDefaultRootDeviceLocalId("local").build(); + ContextPtr context = instance.getContext(); + ModuleManagerPtr manager = instance.getModuleManager(); + + manager.addModule(ModulePtr(MockDeviceModule_Create(context))); + manager.addModule(ModulePtr(MockFunctionBlockModule_Create(context))); + + instance.addDevice("daqmock://phys_device"); + instance.addFunctionBlock("mock_fb_uid"); + instance.addServer("OpenDAQOPCUA", nullptr); + return instance; +} + +static InstancePtr CreateClientInstance() +{ + auto instance = InstanceBuilder().build(); + + auto config = instance.createDefaultAddDeviceConfig(); + PropertyObjectPtr general = config.getPropertyValue("General"); + general.setPropertyValue("StreamingConnectionHeuristic", 2); + + instance.addDevice("daq.opcua://127.0.0.1", config); + return instance; +} + +TEST_F(OpcuaDeviceModulesTest, ComponentActiveChangedRecursive) +{ + // SKIP_TEST_MAC_CI; + auto server = CreateServerInstance(); + auto client = CreateClientInstance(); + + // Get the client's mirror of server device (this is a root device) + auto clientDevice = client.getDevices()[0]; + + // Get all components in clientDevice subtree + auto clientDeviceComponents = clientDevice.getItems(search::Recursive(search::Any())); + + // Set client (Instance) active to false + client.setActive(false); + + // client itself should be inactive + ASSERT_FALSE(client.getActive()) << "client should be inactive"; + + // clientDevice should still be active (it's a root device, doesn't receive parentActive) + ASSERT_TRUE(clientDevice.getActive()) << "clientDevice should remain active as it's a root device"; + + // All clientDevice subtree components should still be active + for (const auto& comp : clientDeviceComponents) + ASSERT_TRUE(comp.getActive()) << "Component should be active: " << comp.getGlobalId(); +} + +TEST_F(OpcuaDeviceModulesTest, ComponentActiveChangedRecursiveGateway) +{ + // SKIP_TEST_MAC_CI; + + // Create leaf server + auto leaf = InstanceBuilder().setDefaultRootDeviceLocalId("leaf").build(); + leaf.addServer("OpenDAQOPCUA", nullptr); + + // Create gateway that connects to leaf + auto gateway = Instance(); + auto gatewayServerConfig = gateway.getAvailableServerTypes().get("OpenDAQOPCUA").createDefaultConfig(); + gatewayServerConfig.setPropertyValue("Port", 4841); + gateway.addDevice("daq.opcua://127.0.0.1"); + gateway.addServer("OpenDAQOPCUA", gatewayServerConfig); + + // Create client that connects to gateway + auto client = Instance(); + auto clientGatewayDevice = client.addDevice("daq.opcua://127.0.0.1:4841"); + + // Get the leaf device through gateway + auto clientLeafDevice = clientGatewayDevice.getDevices()[0]; + + // Set clientGatewayDevice active to false (from client side) + clientGatewayDevice.setActive(false); + + // clientGatewayDevice itself should be inactive + ASSERT_FALSE(clientGatewayDevice.getActive()) << "clientGatewayDevice should be inactive"; + + // clientLeafDevice should still be active (it's a root device) + ASSERT_TRUE(clientLeafDevice.getActive()) << "clientLeafDevice should remain active as it's a root device"; +} From 20e8f22d325d543849804a66a182a5abd422f695 Mon Sep 17 00:00:00 2001 From: Denis Erokhin Date: Fri, 27 Feb 2026 08:57:55 +0100 Subject: [PATCH 4/6] trying to fix ci --- .../opcua_client_module/tests/CMakeLists.txt | 1 + .../tests/test_opcua_device_module.cpp | 17 +++++++++++++---- .../opcua_server_module/tests/CMakeLists.txt | 1 + .../opcuatms_server/tests/CMakeLists.txt | 1 + .../tests/opcuatms_integration/CMakeLists.txt | 1 + 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/modules/opcua_client_module/tests/CMakeLists.txt b/modules/opcua_client_module/tests/CMakeLists.txt index 6b684dd..4a637bc 100644 --- a/modules/opcua_client_module/tests/CMakeLists.txt +++ b/modules/opcua_client_module/tests/CMakeLists.txt @@ -12,6 +12,7 @@ add_executable(${TEST_APP} ${TEST_SOURCES} target_link_libraries(${TEST_APP} PRIVATE ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_test_utils gtest ${OPENDAQ_SDK_TARGET_NAMESPACE}::${MODULE_NAME} ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_mocks + fmt::fmt ) add_test(NAME ${TEST_APP} diff --git a/modules/opcua_client_module/tests/test_opcua_device_module.cpp b/modules/opcua_client_module/tests/test_opcua_device_module.cpp index 47701fd..e378321 100644 --- a/modules/opcua_client_module/tests/test_opcua_device_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_device_module.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -8,6 +9,13 @@ using OpcuaDeviceModulesTest = testing::Test; using namespace daq; +static ModulePtr CreateClientOpcUaModule(const ContextPtr& context) +{ + ModulePtr module; + createOpcUaClientModule(&module, context); + return module; +} + static InstancePtr CreateServerInstance() { auto instance = InstanceBuilder().setDefaultRootDeviceLocalId("local").build(); @@ -25,7 +33,11 @@ static InstancePtr CreateServerInstance() static InstancePtr CreateClientInstance() { - auto instance = InstanceBuilder().build(); + auto instance = InstanceBuilder().setModulePath("[[none]]").build(); + ContextPtr context = instance.getContext(); + ModuleManagerPtr manager = instance.getModuleManager(); + + manager.addModule(CreateClientOpcUaModule(context)); auto config = instance.createDefaultAddDeviceConfig(); PropertyObjectPtr general = config.getPropertyValue("General"); @@ -37,7 +49,6 @@ static InstancePtr CreateClientInstance() TEST_F(OpcuaDeviceModulesTest, ComponentActiveChangedRecursive) { - // SKIP_TEST_MAC_CI; auto server = CreateServerInstance(); auto client = CreateClientInstance(); @@ -63,8 +74,6 @@ TEST_F(OpcuaDeviceModulesTest, ComponentActiveChangedRecursive) TEST_F(OpcuaDeviceModulesTest, ComponentActiveChangedRecursiveGateway) { - // SKIP_TEST_MAC_CI; - // Create leaf server auto leaf = InstanceBuilder().setDefaultRootDeviceLocalId("leaf").build(); leaf.addServer("OpenDAQOPCUA", nullptr); diff --git a/modules/opcua_server_module/tests/CMakeLists.txt b/modules/opcua_server_module/tests/CMakeLists.txt index 67c6aca..7c0dbd0 100644 --- a/modules/opcua_server_module/tests/CMakeLists.txt +++ b/modules/opcua_server_module/tests/CMakeLists.txt @@ -12,6 +12,7 @@ target_link_libraries(${TEST_APP} PRIVATE ${OPENDAQ_SDK_TARGET_NAMESPACE}::opend ${OPENDAQ_SDK_TARGET_NAMESPACE}::opcuaclient ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_mocks ${OPENDAQ_SDK_TARGET_NAMESPACE}::${MODULE_NAME} + fmt::fmt ) add_test(NAME ${TEST_APP} diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt index 12e1146..5d05bfd 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt @@ -27,6 +27,7 @@ target_link_libraries(${TEST_APP} PRIVATE ${OPENDAQ_SDK_TARGET_NAMESPACE}::${MOD ${OPENDAQ_SDK_TARGET_NAMESPACE}::opcuatms_test_utils ${OPENDAQ_SDK_TARGET_NAMESPACE}::opcuaclient ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_mocks + fmt::fmt ) add_test(NAME ${TEST_APP} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt index d8e2e79..f5ff685 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt @@ -41,6 +41,7 @@ target_link_libraries(${TEST_APP} PRIVATE ${OPENDAQ_SDK_TARGET_NAMESPACE}::opcua ${OPENDAQ_SDK_TARGET_NAMESPACE}::opcuatms_client ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_mocks ${BCRYPT_LIB} + fmt::fmt ) if(SUPPORTS_ASAN) From a0c16f4a3c41b60ea184e12e340ee6d20fefe2aa Mon Sep 17 00:00:00 2001 From: Denis Erokhin Date: Fri, 27 Feb 2026 10:46:06 +0100 Subject: [PATCH 5/6] undo last commit --- modules/opcua_client_module/tests/CMakeLists.txt | 1 - modules/opcua_server_module/tests/CMakeLists.txt | 1 - shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt | 1 - .../opcuatms/tests/opcuatms_integration/CMakeLists.txt | 3 +-- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/modules/opcua_client_module/tests/CMakeLists.txt b/modules/opcua_client_module/tests/CMakeLists.txt index 4a637bc..6b684dd 100644 --- a/modules/opcua_client_module/tests/CMakeLists.txt +++ b/modules/opcua_client_module/tests/CMakeLists.txt @@ -12,7 +12,6 @@ add_executable(${TEST_APP} ${TEST_SOURCES} target_link_libraries(${TEST_APP} PRIVATE ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_test_utils gtest ${OPENDAQ_SDK_TARGET_NAMESPACE}::${MODULE_NAME} ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_mocks - fmt::fmt ) add_test(NAME ${TEST_APP} diff --git a/modules/opcua_server_module/tests/CMakeLists.txt b/modules/opcua_server_module/tests/CMakeLists.txt index 7c0dbd0..67c6aca 100644 --- a/modules/opcua_server_module/tests/CMakeLists.txt +++ b/modules/opcua_server_module/tests/CMakeLists.txt @@ -12,7 +12,6 @@ target_link_libraries(${TEST_APP} PRIVATE ${OPENDAQ_SDK_TARGET_NAMESPACE}::opend ${OPENDAQ_SDK_TARGET_NAMESPACE}::opcuaclient ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_mocks ${OPENDAQ_SDK_TARGET_NAMESPACE}::${MODULE_NAME} - fmt::fmt ) add_test(NAME ${TEST_APP} diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt index 5d05bfd..12e1146 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt @@ -27,7 +27,6 @@ target_link_libraries(${TEST_APP} PRIVATE ${OPENDAQ_SDK_TARGET_NAMESPACE}::${MOD ${OPENDAQ_SDK_TARGET_NAMESPACE}::opcuatms_test_utils ${OPENDAQ_SDK_TARGET_NAMESPACE}::opcuaclient ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_mocks - fmt::fmt ) add_test(NAME ${TEST_APP} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt index f5ff685..81c4921 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt @@ -40,8 +40,7 @@ target_link_libraries(${TEST_APP} PRIVATE ${OPENDAQ_SDK_TARGET_NAMESPACE}::opcua ${OPENDAQ_SDK_TARGET_NAMESPACE}::opcuatms_server ${OPENDAQ_SDK_TARGET_NAMESPACE}::opcuatms_client ${OPENDAQ_SDK_TARGET_NAMESPACE}::opendaq_mocks - ${BCRYPT_LIB} - fmt::fmt + ${BCRYPT_LIB} ) if(SUPPORTS_ASAN) From 41237610d87e25b01e278adf79cfc11b0fce31d1 Mon Sep 17 00:00:00 2001 From: Denis Erokhin Date: Mon, 23 Mar 2026 13:34:15 +0100 Subject: [PATCH 6/6] finish up with opcua --- .../tests/test_opcua_device_module.cpp | 103 +++++++++++++++--- opendaq_ref | 2 +- .../objects/tms_client_component_impl.h | 2 + .../objects/tms_client_device_impl.h | 1 + .../src/objects/tms_client_component_impl.cpp | 49 +++++++++ .../src/objects/tms_client_device_impl.cpp | 13 +++ .../objects/tms_server_component.h | 56 ++++++++-- 7 files changed, 201 insertions(+), 25 deletions(-) diff --git a/modules/opcua_client_module/tests/test_opcua_device_module.cpp b/modules/opcua_client_module/tests/test_opcua_device_module.cpp index e378321..c783a10 100644 --- a/modules/opcua_client_module/tests/test_opcua_device_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_device_module.cpp @@ -4,6 +4,7 @@ #include #include #include +#include using OpcuaDeviceModulesTest = testing::Test; @@ -47,6 +48,23 @@ static InstancePtr CreateClientInstance() return instance; } +const std::set& getDefaultComponentsIds() +{ + static const std::set ids = [] + { + std::set result; + result.insert("Sig"); + result.insert("FB"); + result.insert("IP"); + result.insert("Dev"); + result.insert("IO"); + result.insert("Synchronization"); + result.insert("Srv"); + return result; + }(); + return ids; +} + TEST_F(OpcuaDeviceModulesTest, ComponentActiveChangedRecursive) { auto server = CreateServerInstance(); @@ -57,19 +75,60 @@ TEST_F(OpcuaDeviceModulesTest, ComponentActiveChangedRecursive) // Get all components in clientDevice subtree auto clientDeviceComponents = clientDevice.getItems(search::Recursive(search::Any())); - - // Set client (Instance) active to false - client.setActive(false); - - // client itself should be inactive - ASSERT_FALSE(client.getActive()) << "client should be inactive"; - - // clientDevice should still be active (it's a root device, doesn't receive parentActive) - ASSERT_TRUE(clientDevice.getActive()) << "clientDevice should remain active as it's a root device"; - - // All clientDevice subtree components should still be active - for (const auto& comp : clientDeviceComponents) - ASSERT_TRUE(comp.getActive()) << "Component should be active: " << comp.getGlobalId(); + + // checking that the local active change is not propogating to the remote + { + // Set client (Instance) active to false + client.setActive(false); + + // client itself should be inactive + ASSERT_FALSE(client.getActive()) << "client should be inactive"; + + // clientDevice should still be active (it's a root device, doesn't receive parentActive) + ASSERT_TRUE(clientDevice.getActive()) << "clientDevice should remain active as it's a root device"; + + // All clientDevice subtree components should still be active + for (const auto& comp : clientDeviceComponents) + { + ASSERT_TRUE(comp.getLocalActive()) << "Component should be local active: " << comp.getGlobalId(); + ASSERT_TRUE(comp.getParentActive()) << "Component parent should be inactive: " << comp.getGlobalId(); + ASSERT_TRUE(comp.getActive()) << "Component should be inactive: " << comp.getGlobalId(); + } + + // undo changaings + client.setActive(true); + } + + // checking that the local active change is not propogating to the remote + { + // Set client (Instance) active to false + clientDevice.setActive(false); + + // client itself should be inactive + ASSERT_FALSE(clientDevice.getActive()) << "client clientDevice be inactive"; + + // clientDevice should still be active (it's a root device, doesn't receive parentActive) + ASSERT_TRUE(client.getActive()) << "client should remain active as its not child of client"; + + // All clientDevice subtree components should still be active + for (const auto& comp : clientDeviceComponents) + { + if (comp == clientDevice) + { + ASSERT_FALSE(comp.getLocalActive()) << "Component should be local inactive: " << comp.getGlobalId(); + ASSERT_TRUE(comp.getParentActive()) << "Component parent should be active: " << comp.getGlobalId(); + } + else + { + if (getDefaultComponentsIds().count(comp.getLocalId())) + continue; + ASSERT_TRUE(comp.getLocalActive()) << "Component should be local active: " << comp.getGlobalId(); + ASSERT_FALSE(comp.getParentActive()) << "Component parent should be inactive: " << comp.getGlobalId(); + } + ASSERT_FALSE(comp.getActive()) << "Component should be inactive: " << comp.getGlobalId(); + + } + } } TEST_F(OpcuaDeviceModulesTest, ComponentActiveChangedRecursiveGateway) @@ -92,6 +151,8 @@ TEST_F(OpcuaDeviceModulesTest, ComponentActiveChangedRecursiveGateway) // Get the leaf device through gateway auto clientLeafDevice = clientGatewayDevice.getDevices()[0]; + auto clientDeviceComponents = clientGatewayDevice.getItems(search::Recursive(search::InterfaceId(IDevice::Id))); + // Set clientGatewayDevice active to false (from client side) clientGatewayDevice.setActive(false); @@ -100,4 +161,20 @@ TEST_F(OpcuaDeviceModulesTest, ComponentActiveChangedRecursiveGateway) // clientLeafDevice should still be active (it's a root device) ASSERT_TRUE(clientLeafDevice.getActive()) << "clientLeafDevice should remain active as it's a root device"; + + for (const auto& comp : clientDeviceComponents) + { + if (comp == clientGatewayDevice) + { + ASSERT_FALSE(comp.getLocalActive()) << "Component should be local inactive: " << comp.getGlobalId(); + ASSERT_TRUE(comp.getParentActive()) << "Component parent should be active: " << comp.getGlobalId(); + ASSERT_FALSE(comp.getActive()) << "Component should be inactive: " << comp.getGlobalId(); + } + else if (const auto dev = comp.asPtrOrNull(true); dev.assigned()) + { + ASSERT_TRUE(comp.getLocalActive()) << "Component should be local active: " << comp.getGlobalId(); + ASSERT_TRUE(comp.getParentActive()) << "Component parent should be active: " << comp.getGlobalId(); + ASSERT_TRUE(comp.getActive()) << "Component should be active: " << comp.getGlobalId(); + } + } } diff --git a/opendaq_ref b/opendaq_ref index 494ec86..88d050b 100644 --- a/opendaq_ref +++ b/opendaq_ref @@ -1 +1 @@ -other/rework_active_attr \ No newline at end of file +main \ No newline at end of file diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index b6e1575..ed795fe 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -60,6 +60,8 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl // Component overrides ErrCode INTERFACE_FUNC getActive(Bool* active) override; + ErrCode INTERFACE_FUNC getLocalActive(Bool* active) override; + ErrCode INTERFACE_FUNC getParentActive(Bool* active) override; ErrCode INTERFACE_FUNC setActive(Bool active) override; ErrCode INTERFACE_FUNC getName(IString** name) override; ErrCode INTERFACE_FUNC setName(IString* name) override; diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 8af26ab..22a6495 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -38,6 +38,7 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl ErrCode TmsClientComponentBaseImpl::getActive(Bool* active) { + OPENDAQ_PARAM_NOT_NULL(active); + try { *active = this->template readValue("Active"); @@ -28,6 +30,53 @@ ErrCode TmsClientComponentBaseImpl::getActive(Bool* active) return OPENDAQ_SUCCESS; } +template +ErrCode TmsClientComponentBaseImpl::getLocalActive(Bool* active) +{ + OPENDAQ_PARAM_NOT_NULL(active); + + if (!this->hasReference("LocalActive")) + return this->getActive(active); + + try + { + *active = this->template readValue("LocalActive"); + } + catch(...) + { + *active = true; + auto loggerComponent = getLoggerComponent(); + LOG_D("Failed to get local active of component \"{}\". The default value was returned \"true\"", this->globalId); + } + + return OPENDAQ_SUCCESS; +} + +template +ErrCode TmsClientComponentBaseImpl::getParentActive(Bool* active) +{ + OPENDAQ_PARAM_NOT_NULL(active); + + if (!this->hasReference("ParentActive")) + { + *active = True; + return OPENDAQ_SUCCESS; + } + + try + { + *active = this->template readValue("ParentActive"); + } + catch(...) + { + *active = true; + auto loggerComponent = getLoggerComponent(); + LOG_D("Failed to get parent active of component \"{}\". The default value was returned \"true\"", this->globalId); + } + + return OPENDAQ_SUCCESS; +} + template ErrCode TmsClientComponentBaseImpl::setActive(Bool active) { diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 941de19..19990b7 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -477,6 +477,19 @@ PropertyObjectPtr TmsClientDeviceImpl::onCreateDefaultAddDeviceConfig() return PropertyObject(); } +ErrCode TmsClientDeviceImpl::getParentActive(Bool* active) +{ + OPENDAQ_PARAM_NOT_NULL(active); + + if (this->isRootDevice) + { + *active = True; + return OPENDAQ_SUCCESS; + } + + return Super::getParentActive(active); +} + void TmsClientDeviceImpl::findAndCreateFunctionBlocks() { std::map orderedFunctionBlocks; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index b221f73..034f652 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -156,6 +156,10 @@ void TmsServerComponent::bindCallbacks() }); } + this->addReadCallback("LocalActive", [this] { return VariantConverter::ToVariant( this->object.getLocalActive()); }); + + this->addReadCallback("ParentActive", [this] { return VariantConverter::ToVariant( this->object.getParentActive()); }); + this->addReadCallback("Visible", [this] { return VariantConverter::ToVariant( this->object.getVisible()); }); if (!this->object.template supportsInterface() || !this->object.isFrozen()) @@ -230,17 +234,47 @@ void TmsServerComponent::registerToTmsServerContext() template void TmsServerComponent::addChildNodes() { - OpcUaNodeId newNodeId(0); - AddVariableNodeParams params(newNodeId, this->nodeId); - params.setBrowseName("Visible"); - params.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_BOOLEAN].typeId)); - params.typeDefinition = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE)); - - OpcUaObject attr = UA_VariableAttributes_default; - attr->accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; - params.attr = attr; - - this->server->addVariableNode(params); + { + OpcUaNodeId newNodeId(0); + AddVariableNodeParams params(newNodeId, this->nodeId); + params.setBrowseName("Visible"); + params.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_BOOLEAN].typeId)); + params.typeDefinition = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE)); + + OpcUaObject attr = UA_VariableAttributes_default; + attr->accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + params.attr = attr; + + this->server->addVariableNode(params); + } + + { + OpcUaNodeId newNodeId(0); + AddVariableNodeParams params(newNodeId, this->nodeId); + params.setBrowseName("LocalActive"); + params.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_BOOLEAN].typeId)); + params.typeDefinition = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE)); + + OpcUaObject attr = UA_VariableAttributes_default; + attr->accessLevel = UA_ACCESSLEVELMASK_READ; + params.attr = attr; + + this->server->addVariableNode(params); + } + + { + OpcUaNodeId newNodeId(0); + AddVariableNodeParams params(newNodeId, this->nodeId); + params.setBrowseName("ParentActive"); + params.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_BOOLEAN].typeId)); + params.typeDefinition = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE)); + + OpcUaObject attr = UA_VariableAttributes_default; + attr->accessLevel = UA_ACCESSLEVELMASK_READ; + params.attr = attr; + + this->server->addVariableNode(params); + } tmsPropertyObject->registerToExistingOpcUaNode(this->nodeId); if (tmsComponentConfig)