From 5e59e495b40b74f209aa30422405406d3b8c0f0d Mon Sep 17 00:00:00 2001 From: sebastian Date: Wed, 17 May 2023 10:58:39 +0200 Subject: [PATCH 1/3] feat(core): add case distraction for extendedobject encoding --- .../Converter/UaDataValueToJsonValue.cpp | 137 ++++++++++-------- 1 file changed, 79 insertions(+), 58 deletions(-) diff --git a/OpcUaClient/Converter/UaDataValueToJsonValue.cpp b/OpcUaClient/Converter/UaDataValueToJsonValue.cpp index a3335dbe..b5d63f38 100644 --- a/OpcUaClient/Converter/UaDataValueToJsonValue.cpp +++ b/OpcUaClient/Converter/UaDataValueToJsonValue.cpp @@ -11,6 +11,7 @@ #include #include "../../deps/open62541/src/ua_types_encoding_json.h" +#include "../Exceptions/OpcUaNonGoodStatusCodeException.hpp" namespace Umati { namespace OpcUa { @@ -190,71 +191,91 @@ void UaDataValueToJsonValue::setValueFromScalarVariant(UA_Variant &variant, nloh case UA_DATATYPEKIND_EXTENSIONOBJECT: { UA_ExtensionObject exObj(*(UA_ExtensionObject *)variant.data); - if (exObj.encoding == UA_ExtensionObjectEncoding::UA_EXTENSIONOBJECT_DECODED) { - LOG(INFO) << "Known conversion from OpcUaType_ExtensionObject with DataTypeEncodingType: ns=" << exObj.content.encoded.typeId.namespaceIndex - << "; i=" << exObj.content.encoded.typeId.identifier.numeric; - - void *data = exObj.content.decoded.data; - for (size_t i = 0; i < exObj.content.decoded.type->membersSize; i++) { - UA_DataValue dataVal; - UA_DataValue_init(&dataVal); - if (exObj.content.decoded.type->members[i].isArray) { - size_t arraySize = *((size_t *)data); - void **pointerToArrayPointer = (void **)((UA_Byte *)data + sizeof(size_t)); - void *pointerToArray = *(pointerToArrayPointer); - - if (arraySize > 0) { - UA_Variant_setArray( - &dataVal.value, - (UA_Byte *)pointerToArray + exObj.content.decoded.type->members[i].padding, - arraySize, - exObj.content.decoded.type->members[i].memberType); - (*jsonValue)[std::string(exObj.content.decoded.type->members[i].memberName)] = - UaDataValueToJsonValue(dataVal, m_pClient, nodeId, serializeStatusInformation).getValue(); + switch (exObj.encoding) { + case UA_ExtensionObjectEncoding::UA_EXTENSIONOBJECT_DECODED: { + LOG(INFO) << "Known conversion from OpcUaType_ExtensionObject with DataTypeEncodingType: ns=" << exObj.content.encoded.typeId.namespaceIndex + << "; i=" << exObj.content.encoded.typeId.identifier.numeric; + + void *data = exObj.content.decoded.data; + for (size_t i = 0; i < exObj.content.decoded.type->membersSize; i++) { + UA_DataValue dataVal; + UA_DataValue_init(&dataVal); + if (exObj.content.decoded.type->members[i].isArray) { + size_t arraySize = *((size_t *)data); + void **pointerToArrayPointer = (void **)((UA_Byte *)data + sizeof(size_t)); + void *pointerToArray = *(pointerToArrayPointer); + + if (arraySize > 0) { + UA_Variant_setArray( + &dataVal.value, + (UA_Byte *)pointerToArray + exObj.content.decoded.type->members[i].padding, + arraySize, + exObj.content.decoded.type->members[i].memberType); + (*jsonValue)[std::string(exObj.content.decoded.type->members[i].memberName)] = + UaDataValueToJsonValue(dataVal, m_pClient, nodeId, serializeStatusInformation).getValue(); + } + } else { + void *dataPointer = (UA_Byte *)data + exObj.content.decoded.type->members[i].padding; + UA_Variant_setScalar(&dataVal.value, dataPointer, exObj.content.decoded.type->members[i].memberType); + auto json = UaDataValueToJsonValue(dataVal, m_pClient, nodeId, serializeStatusInformation).getValue(); + if (!json.is_null()) { + (*jsonValue)[std::string(exObj.content.decoded.type->members[i].memberName)] = json; + } } - } else { - void *dataPointer = (UA_Byte *)data + exObj.content.decoded.type->members[i].padding; - UA_Variant_setScalar(&dataVal.value, dataPointer, exObj.content.decoded.type->members[i].memberType); - auto json = UaDataValueToJsonValue(dataVal, m_pClient, nodeId, serializeStatusInformation).getValue(); - if (!json.is_null()) { - (*jsonValue)[std::string(exObj.content.decoded.type->members[i].memberName)] = json; + if (exObj.content.decoded.type->members[i].isArray) { + data = (UA_Byte *)data + sizeof(void *) + sizeof(size_t); + } else if (exObj.content.decoded.type->members[i].isOptional) { + data = (UA_Byte *)data + sizeof(void *); + } else { + data = (UA_Byte *)data + exObj.content.decoded.type->members[i].memberType->memSize; } + data = (UA_Byte *)data + exObj.content.decoded.type->members[i].padding; } - if (exObj.content.decoded.type->members[i].isArray) { - data = (UA_Byte *)data + sizeof(void *) + sizeof(size_t); - } else if (exObj.content.decoded.type->members[i].isOptional) { - data = (UA_Byte *)data + sizeof(void *); - } else { - data = (UA_Byte *)data + exObj.content.decoded.type->members[i].memberType->memSize; - } - data = (UA_Byte *)data + exObj.content.decoded.type->members[i].padding; + break; } - } else { - LOG(ERROR) << "Unknow conversion from OpcUaType_ExtensionObject with DataTypeEncodingType: ns=" << exObj.content.encoded.typeId.namespaceIndex - << "; i=" << exObj.content.encoded.typeId.identifier.numeric; - switch (nodeId.identifierType) { - case UA_NodeIdType::UA_NODEIDTYPE_STRING: - LOG(ERROR) << "The erroc originates from ns=" << nodeId.namespaceIndex - << "; s=" << std::string((char *)nodeId.identifier.string.data, nodeId.identifier.string.length); - break; - case UA_NodeIdType::UA_NODEIDTYPE_NUMERIC: - LOG(ERROR) << "The erroc originates from ns=" << nodeId.namespaceIndex << "; s=" << nodeId.identifier.numeric; + case UA_ExtensionObjectEncoding::UA_EXTENSIONOBJECT_ENCODED_NOBODY: { + LOG(DEBUG) << "Extension Object has no Body"; + *jsonValue = std::string(""); + break; + } + case UA_ExtensionObjectEncoding::UA_EXTENSIONOBJECT_DECODED_NODELETE: { + LOG(WARNING) << "UA_ExtensionObjectEncoding::UA_EXTENSIONOBJECT_DECODED_NODELETE"; } + case UA_ExtensionObjectEncoding::UA_EXTENSIONOBJECT_ENCODED_BYTESTRING: { + LOG(WARNING) << "UA_ExtensionObjectEncoding::UA_EXTENSIONOBJECT_ENCODED_BYTESTRING"; + } + case UA_ExtensionObjectEncoding::UA_EXTENSIONOBJECT_ENCODED_XML: { + LOG(WARNING) << "UA_ExtensionObjectEncoding::UA_EXTENSIONOBJECT_ENCODED_XML"; + } + default: { + LOG(ERROR) << "Unknow conversion from OpcUaType_ExtensionObject with DataTypeEncodingType: ns=" << exObj.content.encoded.typeId.namespaceIndex + << "; i=" << exObj.content.encoded.typeId.identifier.numeric; + UA_String tmp; + UA_NodeId_print(&nodeId, &tmp); + LOG(ERROR) << "The erroc originates from ns=" << tmp.data; + + UA_NodeId dataTypeNodeId; + UA_NodeId_init(&dataTypeNodeId); + UA_StatusCode ret = UA_Client_readDataTypeAttribute(m_pClient, nodeId, &dataTypeNodeId); + if (ret != UA_STATUSCODE_GOOD) { + LOG(ERROR) << "could not read DataType Attribute"; + throw Umati::Exceptions::OpcUaNonGoodStatusCodeException(ret, "Could not read DataType Attribute"); + } - UA_NodeId dataTypeNodeId; - UA_NodeId_init(&dataTypeNodeId); - UA_Client_readDataTypeAttribute(m_pClient, nodeId, &dataTypeNodeId); - UA_Variant v; - UA_Variant_init(&v); - UA_Client_readValueAttribute(m_pClient, nodeId, &v); - - // auto dataType = UA_Client_findDataType(m_pClient, &dataTypeNodeId); - auto dataType = v.type; - auto clientConfig = UA_Client_getConfig(m_pClient); - auto res = UA_decodeBinaryInternal(&exObj.content.encoded.body, NULL, exObj.content.decoded.data, dataType, clientConfig->customDataTypes); - LOG(ERROR) << "Found the Datatype=" << dataType->typeName << "And the decoding was success?: " << res; + UA_Variant v; + UA_Variant_init(&v); + ret = UA_Client_readValueAttribute(m_pClient, nodeId, &v); + if (ret != UA_STATUSCODE_GOOD) { + throw Umati::Exceptions::OpcUaNonGoodStatusCodeException(ret, "Could not read Value Attribute"); + throw ret; + } + // auto dataType = UA_Client_findDataType(m_pClient, &dataTypeNodeId); + auto dataType = v.type; + auto clientConfig = UA_Client_getConfig(m_pClient); + auto res = UA_decodeBinaryInternal(&exObj.content.encoded.body, NULL, exObj.content.decoded.data, dataType, clientConfig->customDataTypes); + LOG(INFO) << "Found the Datatype=" << dataType->typeName << "And the decoding Result was: " << res; + } break; } - break; } default: { From aca257ed0d93ca990d52d4b87176ec28a9795b7b Mon Sep 17 00:00:00 2001 From: Sebastian Friedl Date: Tue, 30 May 2023 21:23:19 +0000 Subject: [PATCH 2/3] fix: improve error handling if no type definition exist --- MachineObserver/MachineObserver.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/MachineObserver/MachineObserver.cpp b/MachineObserver/MachineObserver.cpp index 0e9b91e9..cfa85ee1 100644 --- a/MachineObserver/MachineObserver.cpp +++ b/MachineObserver/MachineObserver.cpp @@ -202,10 +202,15 @@ namespace Umati { } } if(machine.TypeDefinition == Umati::Dashboard::NodeId_BaseObjectType) { + LOG(DEBUG) << "machine is a BaseObjectType : " << machine.NodeId.Uri << machine.NodeId.Id << " Search for InterfaceTypes"; auto ifs = m_pDataClient->Browse(machine.NodeId, Dashboard::IDashboardDataClient::BrowseContext_t::HasInterface()); - machine.TypeDefinition = ifs.front().NodeId; - + if (ifs.empty()){ + LOG(WARNING) << "machine is a BaseObjectType without a InterfaceType :" << machine.NodeId.Uri << machine.NodeId.Id; + } + else{ + machine.TypeDefinition = ifs.front().NodeId; + } } auto typeDefinitionNodeId = m_pOpcUaTypeReader->getIdentificationTypeNodeId(machine.TypeDefinition); From 96178e90ef713631dc928e8c782b1911db10d25c Mon Sep 17 00:00:00 2001 From: Sebastian Friedl Date: Wed, 31 May 2023 06:09:25 +0000 Subject: [PATCH 3/3] refact: update format for MachineObserver.cpp --- MachineObserver/MachineObserver.cpp | 529 +++++++++++++--------------- 1 file changed, 250 insertions(+), 279 deletions(-) diff --git a/MachineObserver/MachineObserver.cpp b/MachineObserver/MachineObserver.cpp index cfa85ee1..59dc8956 100644 --- a/MachineObserver/MachineObserver.cpp +++ b/MachineObserver/MachineObserver.cpp @@ -1,7 +1,7 @@ - /* This Source Code Form is subject to the terms of the Mozilla Public +/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * + * * Copyright 2019-2021 (c) Christian von Arnim, ISW University of Stuttgart (for umati and VDW e.V.) * Copyright 2020 (c) Dominik Basner, Sotec GmbH (for VDW e.V.) * Copyright 2021 (c) Moritz Walker, ISW University of Stuttgart (for umati and VDW e.V.) @@ -16,302 +16,273 @@ #include namespace Umati { - namespace MachineObserver { +namespace MachineObserver { - MachineObserver::MachineObserver( - std::shared_ptr pDataClient, - std::shared_ptr pTypeReader, - std::vector machinesFilter - ) - : m_pDataClient(std::move(pDataClient)), m_pOpcUaTypeReader(std::move(pTypeReader)), m_machinesFilter(machinesFilter.begin(), machinesFilter.end()) { - } - - MachineObserver::~MachineObserver() {} - - /** - * index 1000 is the folder machineTools where all the machines are inside - */ - void MachineObserver::UpdateMachines() { - - /** - * Assumes that all machines are offline / to be removed - */ - std::set toBeRemovedMachines; - for(auto & knownMachine: m_knownMachines) - { - toBeRemovedMachines.insert(knownMachine.first); - } - std::list machineList; - /** - * Browses the machineList and fills the list if possiblenodeClassFromN - */ - if (!canBrowseMachineList(machineList)) { - return; - } - // Remove duplicate machines - machineList.sort([](const ModelOpcUa::BrowseResult_t &l, const ModelOpcUa::BrowseResult_t &r)-> bool { - return l.NodeId < r.NodeId; - }); - std::unique(machineList.begin(), machineList.end(), - [](const ModelOpcUa::BrowseResult_t &l, const ModelOpcUa::BrowseResult_t &r) -> bool{ - return l.NodeId == r.NodeId; - }); - - std::map machineList_map; - std::transform(machineList.begin(), machineList.end(), - std::inserter(machineList_map, machineList_map.end()), - [](const ModelOpcUa::BrowseResult_t &m) { return std::make_pair(m.NodeId, m); } - ); - - machineListsNotEqual(machineList); - std::set newMachines; - std::map machinesIdentification; - findNewAndOfflineMachines(machineList, toBeRemovedMachines, newMachines, machinesIdentification); +MachineObserver::MachineObserver( + std::shared_ptr pDataClient, + std::shared_ptr pTypeReader, + std::vector machinesFilter) + : m_pDataClient(std::move(pDataClient)), m_pOpcUaTypeReader(std::move(pTypeReader)), m_machinesFilter(machinesFilter.begin(), machinesFilter.end()) {} - removeOfflineMachines(toBeRemovedMachines); +MachineObserver::~MachineObserver() {} - for (auto &newMachineNodeId : newMachines) { - // Ignore known invalid machines for a specific time - if (ignoreInvalidMachinesTemporarily(newMachineNodeId)) { - continue; - }; - addNewMachine(machineList_map[newMachineNodeId]); - } - - { - std::unique_lock ul(m_machineIdentificationsCache_mutex); - m_machineIdentificationsCache = machinesIdentification; - } +/** + * index 1000 is the folder machineTools where all the machines are inside + */ +void MachineObserver::UpdateMachines() { + /** + * Assumes that all machines are offline / to be removed + */ + std::set toBeRemovedMachines; + for (auto &knownMachine : m_knownMachines) { + toBeRemovedMachines.insert(knownMachine.first); + } + std::list machineList; + /** + * Browses the machineList and fills the list if possiblenodeClassFromN + */ + if (!canBrowseMachineList(machineList)) { + return; + } + // Remove duplicate machines + machineList.sort([](const ModelOpcUa::BrowseResult_t &l, const ModelOpcUa::BrowseResult_t &r) -> bool { return l.NodeId < r.NodeId; }); + std::unique(machineList.begin(), machineList.end(), [](const ModelOpcUa::BrowseResult_t &l, const ModelOpcUa::BrowseResult_t &r) -> bool { + return l.NodeId == r.NodeId; + }); + + std::map machineList_map; + std::transform(machineList.begin(), machineList.end(), std::inserter(machineList_map, machineList_map.end()), [](const ModelOpcUa::BrowseResult_t &m) { + return std::make_pair(m.NodeId, m); + }); + + machineListsNotEqual(machineList); + std::set newMachines; + std::map machinesIdentification; + findNewAndOfflineMachines(machineList, toBeRemovedMachines, newMachines, machinesIdentification); + + removeOfflineMachines(toBeRemovedMachines); + + for (auto &newMachineNodeId : newMachines) { + // Ignore known invalid machines for a specific time + if (ignoreInvalidMachinesTemporarily(newMachineNodeId)) { + continue; + }; + addNewMachine(machineList_map[newMachineNodeId]); + } + + { + std::unique_lock ul(m_machineIdentificationsCache_mutex); + m_machineIdentificationsCache = machinesIdentification; + } +} - } +bool MachineObserver::machineListsNotEqual(std::list &machineList) { + /// \TODO Is this function still required? Is this handled by the reset logic? + + std::set newMachines; + // Use a set for a quick compare, as there might be duplicates in machineList! + for (const auto &machineTool : machineList) { + newMachines.insert(machineTool.NodeId); + } + if (newMachines != m_knownMachineToolsSet) { + LOG(INFO) << "Different set of machines, reset known machines."; + recreateKnownMachineToolsMap(machineList); + return true; + } + return false; +} - bool MachineObserver::machineListsNotEqual(std::list &machineList) { - /// \TODO Is this function still required? Is this handled by the reset logic? +void MachineObserver::recreateKnownMachineToolsMap(std::list &machineList) { + LOG(WARNING) << "Lists differ, recreating known machine tools map"; + removeOfflineMachines(m_knownMachineToolsSet); + m_knownMachineToolsSet.clear(); + for (const auto &machineTool : machineList) { + m_knownMachineToolsSet.insert(machineTool.NodeId); + } +} - std::set newMachines; - // Use a set for a quick compare, as there might be duplicates in machineList! - for (const auto &machineTool : machineList) { - newMachines.insert(machineTool.NodeId); - } - if(newMachines != m_knownMachineToolsSet) - { - LOG(INFO) << "Different set of machines, reset known machines."; - recreateKnownMachineToolsMap(machineList); - return true; - } - return false; - } +bool MachineObserver::ignoreInvalidMachinesTemporarily(const ModelOpcUa::NodeId_t &newMachineId) { + auto it = m_invalidMachines.find(newMachineId); + if (it != m_invalidMachines.end()) { + --(it->second.first); + if (it->second.first <= 0) { + m_invalidMachines.erase(it); // todo or does it need to be it++? + } else { + return true; + } + } + return false; +} - void MachineObserver::recreateKnownMachineToolsMap(std::list &machineList) { - LOG(WARNING) << "Lists differ, recreating known machine tools map"; - removeOfflineMachines(m_knownMachineToolsSet); - m_knownMachineToolsSet.clear(); - for (const auto &machineTool : machineList) { - m_knownMachineToolsSet.insert(machineTool.NodeId); - } - } +bool MachineObserver::canBrowseMachineList(std::list &machineList) { + try { + LOG(INFO) << "Searching for machines"; + machineList.empty(); + std::function filter; + if (m_machinesFilter.size()) { + filter = [&](ModelOpcUa::NodeId_t machine) { return m_machinesFilter.find(machine) != m_machinesFilter.end(); }; + } + machineList = browseForMachines(Umati::Dashboard::NodeId_MachinesFolder, Umati::Dashboard::NodeId_MachinesFolder, filter); + } catch (const Umati::Exceptions::OpcUaException &ex) { + LOG(ERROR) << "Browse new machines failed with: " << ex.what(); + return false; + } catch (const Umati::Exceptions::ClientNotConnected &ex) { + LOG(ERROR) << "OPC UA Client not connected." << ex.what(); + return false; + } + return true; +} - bool MachineObserver::ignoreInvalidMachinesTemporarily(const ModelOpcUa::NodeId_t &newMachineId) { - auto it = m_invalidMachines.find(newMachineId); - if (it != m_invalidMachines.end()) { - --(it->second.first); - if (it->second.first <= 0) { - m_invalidMachines.erase(it); // todo or does it need to be it++? - } else { - return true; - } - } - return false; - } +std::list MachineObserver::findComponentsFolder(ModelOpcUa::NodeId_t nodeid) { + std::list newMachines; + try { + auto componentFolder = m_pDataClient->TranslateBrowsePathToNodeId(nodeid, Umati::Dashboard::QualifiedName_ComponentsFolder); + if (!componentFolder.isNull()) { + newMachines = browseForMachines(componentFolder, nodeid); + } + } catch (const Umati::Exceptions::OpcUaException &ex) { + } + return newMachines; +} - bool MachineObserver::canBrowseMachineList(std::list &machineList) { - try { - LOG(INFO) << "Searching for machines"; - machineList.empty(); - std::function filter; - if(m_machinesFilter.size()){ - filter = [&](ModelOpcUa::NodeId_t machine){ - return m_machinesFilter.find(machine) != m_machinesFilter.end(); - }; - } - machineList = browseForMachines(Umati::Dashboard::NodeId_MachinesFolder, Umati::Dashboard::NodeId_MachinesFolder, filter); - } - catch (const Umati::Exceptions::OpcUaException &ex) { - LOG(ERROR) << "Browse new machines failed with: " << ex.what(); - return false; - } - catch (const Umati::Exceptions::ClientNotConnected &ex) { - LOG(ERROR) << "OPC UA Client not connected." << ex.what(); - return false; - } - return true; +std::list MachineObserver::browseForMachines( + ModelOpcUa::NodeId_t nodeid, ModelOpcUa::NodeId_t parentNodeId, std::function filter) { + std::list newMachines; + auto potentialMachines = m_pDataClient->Browse(nodeid, Dashboard::IDashboardDataClient::BrowseContext_t::Hierarchical()); + for (auto &machine : potentialMachines) { + if (filter && !filter(machine.NodeId)) { + continue; + } + if (machine.TypeDefinition == Dashboard::NodeId_MissingType) { + try { + auto defs = m_pDataClient->Browse(machine.NodeId, Dashboard::IDashboardDataClient::BrowseContext_t::HasTypeDefinition()); + machine.TypeDefinition = defs.front().NodeId; + LOG(INFO) << "Fixing missing type definition in opc asyncio. Parent: " << machine.NodeId << " TypeDefinition: " << machine.TypeDefinition; + } catch (const Umati::Exceptions::UmatiException &ex) { + LOG(INFO) << "Could not fix missing type definition in browse result for machine " << machine.NodeId << ' ' << ex.what(); + } + } + try { + auto subTypeToBaseType = m_pOpcUaTypeReader->m_subTypeDefinitionToKnownMachineTypeDefinition.find(machine.TypeDefinition); + if (subTypeToBaseType == m_pOpcUaTypeReader->m_subTypeDefinitionToKnownMachineTypeDefinition.end()) { + // If the machine does not have a proper, configured machine (Super)TypeDefinition, mark it as invalid + // to prevent search for following machines with the same invalid (Super)TypeDefinition + auto typeToSupertype = std::make_pair(machine.TypeDefinition, Dashboard::NodeId_UndefinedType); + m_pOpcUaTypeReader->m_subTypeDefinitionToKnownMachineTypeDefinition.insert(typeToSupertype); + for (const auto &md : m_pOpcUaTypeReader->m_knownMachineTypeDefinitions) { + if (m_pDataClient->isSameOrSubtype(md, machine.TypeDefinition, 3)) { + m_pOpcUaTypeReader->m_subTypeDefinitionToKnownMachineTypeDefinition[machine.TypeDefinition] = md; + machine.TypeDefinition = md; + break; + } } - - std::list MachineObserver::findComponentsFolder(ModelOpcUa::NodeId_t nodeid) - { - std::list newMachines; - try { - auto componentFolder = m_pDataClient->TranslateBrowsePathToNodeId(nodeid, Umati::Dashboard::QualifiedName_ComponentsFolder); - if (!componentFolder.isNull()) { - newMachines = browseForMachines(componentFolder, nodeid); - } - } - catch (const Umati::Exceptions::OpcUaException &ex) {} - return newMachines; + } else { + // Check if machines (Super)TypeDefinition is an invalid or not configured + if (!(subTypeToBaseType->second == Dashboard::NodeId_UndefinedType)) { + machine.TypeDefinition = subTypeToBaseType->second; } - - std::list MachineObserver::browseForMachines(ModelOpcUa::NodeId_t nodeid, ModelOpcUa::NodeId_t parentNodeId, std::function filter) - { - std::list newMachines; - auto potentialMachines = m_pDataClient->Browse(nodeid, Dashboard::IDashboardDataClient::BrowseContext_t::Hierarchical()); - for(auto &machine: potentialMachines) { - if(filter && !filter(machine.NodeId)) - { - continue; - } - if (machine.TypeDefinition == Dashboard::NodeId_MissingType) { - try { - auto defs = m_pDataClient->Browse(machine.NodeId, - Dashboard::IDashboardDataClient::BrowseContext_t::HasTypeDefinition()); - machine.TypeDefinition = defs.front().NodeId; - LOG(INFO) << "Fixing missing type definition in opc asyncio. Parent: " << machine.NodeId - << " TypeDefinition: " << machine.TypeDefinition; - } - catch (const Umati::Exceptions::UmatiException &ex) { - LOG(INFO) << "Could not fix missing type definition in browse result for machine " << machine.NodeId << ' ' << ex.what(); - } - } - try { - auto subTypeToBaseType = m_pOpcUaTypeReader->m_subTypeDefinitionToKnownMachineTypeDefinition.find(machine.TypeDefinition); - if (subTypeToBaseType == m_pOpcUaTypeReader->m_subTypeDefinitionToKnownMachineTypeDefinition.end()) { - // If the machine does not have a proper, configured machine (Super)TypeDefinition, mark it as invalid - // to prevent search for following machines with the same invalid (Super)TypeDefinition - auto typeToSupertype = std::make_pair(machine.TypeDefinition, Dashboard::NodeId_UndefinedType); - m_pOpcUaTypeReader->m_subTypeDefinitionToKnownMachineTypeDefinition.insert(typeToSupertype); - for (const auto &md: m_pOpcUaTypeReader->m_knownMachineTypeDefinitions) { - if (m_pDataClient->isSameOrSubtype(md, machine.TypeDefinition, 3)) { - m_pOpcUaTypeReader->m_subTypeDefinitionToKnownMachineTypeDefinition[machine.TypeDefinition] = md; - machine.TypeDefinition = md; - break; - } - } - } else { - // Check if machines (Super)TypeDefinition is an invalid or not configured - if (!(subTypeToBaseType->second == Dashboard::NodeId_UndefinedType)) { - machine.TypeDefinition = subTypeToBaseType->second; - } - } - if(machine.TypeDefinition == Umati::Dashboard::NodeId_BaseObjectType) { - LOG(DEBUG) << "machine is a BaseObjectType : " << machine.NodeId.Uri << machine.NodeId.Id << " Search for InterfaceTypes"; - auto ifs = m_pDataClient->Browse(machine.NodeId, - Dashboard::IDashboardDataClient::BrowseContext_t::HasInterface()); - if (ifs.empty()){ - LOG(WARNING) << "machine is a BaseObjectType without a InterfaceType :" << machine.NodeId.Uri << machine.NodeId.Id; - } - else{ - machine.TypeDefinition = ifs.front().NodeId; - } - } - - auto typeDefinitionNodeId = m_pOpcUaTypeReader->getIdentificationTypeNodeId(machine.TypeDefinition); - auto ident = m_pDataClient->BrowseWithResultTypeFilter(machine.NodeId, Dashboard::IDashboardDataClient::BrowseContext_t::Hierarchical(), - typeDefinitionNodeId); - if (!ident.empty()) { - newMachines.push_back(machine); - newMachines.splice(newMachines.end(), findComponentsFolder(machine.NodeId)); - m_parentOfMachine.insert(std::make_pair(machine.NodeId, parentNodeId)); - } else { - LOG(INFO) << "Identification is empty for " << machine.NodeId.Uri << machine.NodeId.Id; - } - } catch (const Umati::Exceptions::OpcUaException &ex) { - LOG(INFO) << "Err " << ex.what(); - } catch (const Umati::MachineObserver::Exceptions::MachineInvalidException &ex) { - LOG(INFO) << ex.what(); - } - } - - return newMachines; + } + if (machine.TypeDefinition == Umati::Dashboard::NodeId_BaseObjectType) { + LOG(DEBUG) << "machine is a BaseObjectType : " << machine.NodeId.Uri << machine.NodeId.Id << " Search for InterfaceTypes"; + auto ifs = m_pDataClient->Browse(machine.NodeId, Dashboard::IDashboardDataClient::BrowseContext_t::HasInterface()); + if (ifs.empty()) { + LOG(WARNING) << "machine is a BaseObjectType without a InterfaceType :" << machine.NodeId.Uri << machine.NodeId.Id; + } else { + machine.TypeDefinition = ifs.front().NodeId; } + } + + auto typeDefinitionNodeId = m_pOpcUaTypeReader->getIdentificationTypeNodeId(machine.TypeDefinition); + auto ident = + m_pDataClient->BrowseWithResultTypeFilter(machine.NodeId, Dashboard::IDashboardDataClient::BrowseContext_t::Hierarchical(), typeDefinitionNodeId); + if (!ident.empty()) { + newMachines.push_back(machine); + newMachines.splice(newMachines.end(), findComponentsFolder(machine.NodeId)); + m_parentOfMachine.insert(std::make_pair(machine.NodeId, parentNodeId)); + } else { + LOG(INFO) << "Identification is empty for " << machine.NodeId.Uri << machine.NodeId.Id; + } + } catch (const Umati::Exceptions::OpcUaException &ex) { + LOG(INFO) << "Err " << ex.what(); + } catch (const Umati::MachineObserver::Exceptions::MachineInvalidException &ex) { + LOG(INFO) << ex.what(); + } + } - void MachineObserver::findNewAndOfflineMachines(std::list &machineList, - std::set &toBeRemovedMachines, - std::set &newMachines, - std::map &machinesIdentifications) { - LOG(INFO) << "Checking which machines are online / offline"; - - for (auto &machineTool : machineList) { - - // Check if Machine is known as online machine - auto it = toBeRemovedMachines.find(machineTool.NodeId); - - // Machine known - try { - // Check if machine is still online. If so, remove it from the removed machines. If it is not on there, it must be a new machine - nlohmann::json identificationAsJson; - if (isOnline(machineTool.NodeId, identificationAsJson, machineTool.TypeDefinition)) { - if (it != toBeRemovedMachines.end()) { - toBeRemovedMachines.erase(it);// todo or does it need to be it++? - } else { - newMachines.insert(machineTool.NodeId); - } - machinesIdentifications.insert(std::make_pair(machineTool.NodeId, identificationAsJson)); - } else { - LOG(INFO) << "Machine " << machineTool.BrowseName.Name << " not identified as online"; - } - } - // Catch exceptions during CheckOnline, this will cause that the machine stay in the toBeRemovedMachines list - catch (const Umati::Exceptions::OpcUaException &) { - LOG(INFO) << "Machine disconnected: '" << machineTool.BrowseName.Name << "' (" - << machineTool.NodeId.Uri << ")"; - } - } + return newMachines; +} - logMachinesChanging("To be removed machines: ", toBeRemovedMachines); - logMachinesChanging("New / Staying machines: ", newMachines); +void MachineObserver::findNewAndOfflineMachines( + std::list &machineList, + std::set &toBeRemovedMachines, + std::set &newMachines, + std::map &machinesIdentifications) { + LOG(INFO) << "Checking which machines are online / offline"; + + for (auto &machineTool : machineList) { + // Check if Machine is known as online machine + auto it = toBeRemovedMachines.find(machineTool.NodeId); + + // Machine known + try { + // Check if machine is still online. If so, remove it from the removed machines. If it is not on there, it must be a new machine + nlohmann::json identificationAsJson; + if (isOnline(machineTool.NodeId, identificationAsJson, machineTool.TypeDefinition)) { + if (it != toBeRemovedMachines.end()) { + toBeRemovedMachines.erase(it); // todo or does it need to be it++? + } else { + newMachines.insert(machineTool.NodeId); } + machinesIdentifications.insert(std::make_pair(machineTool.NodeId, identificationAsJson)); + } else { + LOG(INFO) << "Machine " << machineTool.BrowseName.Name << " not identified as online"; + } + } + // Catch exceptions during CheckOnline, this will cause that the machine stay in the toBeRemovedMachines list + catch (const Umati::Exceptions::OpcUaException &) { + LOG(INFO) << "Machine disconnected: '" << machineTool.BrowseName.Name << "' (" << machineTool.NodeId.Uri << ")"; + } + } - void MachineObserver::logMachinesChanging(const std::string &text, - const std::map &machines) { - std::stringstream machinesStringStream; - for (auto &machine : machines) { - machinesStringStream << machine.first.Uri << "\n"; - } - LOG(INFO) << text << "\n" << machinesStringStream.str().c_str(); - } + logMachinesChanging("To be removed machines: ", toBeRemovedMachines); + logMachinesChanging("New / Staying machines: ", newMachines); +} - void MachineObserver::logMachinesChanging(const std::string &text, - const std::set &machines) { - std::stringstream machinesStringStream; - for (auto &machine : machines) { - machinesStringStream << machine.Uri << "\n"; - } - LOG(INFO) << text << "\n" << machinesStringStream.str().c_str(); - } +void MachineObserver::logMachinesChanging(const std::string &text, const std::map &machines) { + std::stringstream machinesStringStream; + for (auto &machine : machines) { + machinesStringStream << machine.first.Uri << "\n"; + } + LOG(INFO) << text << "\n" << machinesStringStream.str().c_str(); +} - void MachineObserver::removeOfflineMachines( - std::set &toBeRemovedMachines) { +void MachineObserver::logMachinesChanging(const std::string &text, const std::set &machines) { + std::stringstream machinesStringStream; + for (auto &machine : machines) { + machinesStringStream << machine.Uri << "\n"; + } + LOG(INFO) << text << "\n" << machinesStringStream.str().c_str(); +} - logMachinesChanging("Removing machines: ", toBeRemovedMachines); +void MachineObserver::removeOfflineMachines(std::set &toBeRemovedMachines) { + logMachinesChanging("Removing machines: ", toBeRemovedMachines); - for (auto &toBeRemovedMachine : toBeRemovedMachines) { - removeMachine(toBeRemovedMachine); - } - } + for (auto &toBeRemovedMachine : toBeRemovedMachines) { + removeMachine(toBeRemovedMachine); + } +} - void - MachineObserver::addNewMachine(const ModelOpcUa::BrowseResult_t &newMachine) { - try { - addMachine(newMachine); - m_knownMachines.insert(std::make_pair(newMachine.NodeId, newMachine)); - } - catch (const Exceptions::MachineInvalidException &machineInvalidException) { - LOG(INFO) << "Machine invalid: " << static_cast(newMachine.NodeId); - m_invalidMachines.insert(std::make_pair(newMachine.NodeId, std::make_pair(NumSkipAfterInvalid, machineInvalidException.what()))); - } - catch (const Exceptions::MachineOfflineException &machineOfflineException) { - LOG(INFO) << "Machine offline: " << static_cast(newMachine.NodeId); - m_invalidMachines.insert(std::make_pair(newMachine.NodeId, std::make_pair(NumSkipAfterInvalid, machineOfflineException.what()))); - } - } - } +void MachineObserver::addNewMachine(const ModelOpcUa::BrowseResult_t &newMachine) { + try { + addMachine(newMachine); + m_knownMachines.insert(std::make_pair(newMachine.NodeId, newMachine)); + } catch (const Exceptions::MachineInvalidException &machineInvalidException) { + LOG(INFO) << "Machine invalid: " << static_cast(newMachine.NodeId); + m_invalidMachines.insert(std::make_pair(newMachine.NodeId, std::make_pair(NumSkipAfterInvalid, machineInvalidException.what()))); + } catch (const Exceptions::MachineOfflineException &machineOfflineException) { + LOG(INFO) << "Machine offline: " << static_cast(newMachine.NodeId); + m_invalidMachines.insert(std::make_pair(newMachine.NodeId, std::make_pair(NumSkipAfterInvalid, machineOfflineException.what()))); + } } +} // namespace MachineObserver +} // namespace Umati