diff --git a/src/AasxOpcUa2Client/AasOpcUaClient2.cs b/src/AasxOpcUa2Client/AasOpcUaClient2.cs index 00d85657..49bfa821 100644 --- a/src/AasxOpcUa2Client/AasOpcUaClient2.cs +++ b/src/AasxOpcUa2Client/AasOpcUaClient2.cs @@ -19,6 +19,7 @@ This source code may use other Open Source software components (see LICENSE.txt) using System.Threading.Tasks; using AasxIntegrationBase; using AdminShellNS; +using AnyUi; using Workstation.ServiceModel.Ua; using Workstation.ServiceModel.Ua.Channels; @@ -58,12 +59,22 @@ public class AasOpcUaClient2 protected string _password; protected uint _timeOutMs = 2000; + //Optional parameters for secured OPC UA interface in AID + protected MessageSecurityMode _securityMode; + protected string _securityPolicy; + protected static bool _autoConnect = false; + protected ClientSessionChannel _channel = null; - public AasOpcUaClient2(string endpointURL, bool autoAccept, + public AasOpcUaClient2( + string endpointURL, + bool autoAccept, string userName, string password, uint timeOutMs = 2000, - LogInstance log = null) + LogInstance log = null, + MessageSecurityMode? securityMode = MessageSecurityMode.None, + string? securityPolicy = SecurityPolicyUris.None, + bool? autoConnect = false) { _endpointURL = endpointURL; _autoAccept = autoAccept; @@ -71,6 +82,9 @@ public AasOpcUaClient2(string endpointURL, bool autoAccept, _password = password; _timeOutMs = timeOutMs; _log = log; + _securityMode = (MessageSecurityMode)securityMode; + _securityPolicy = securityPolicy; + _autoConnect = (bool)autoConnect; } public async Task DirectConnect() @@ -98,19 +112,97 @@ public async Task StartClientAsync() ApplicationType = ApplicationType.Client }; - // create a 'ClientSessionChannel', a client-side channel that opens a 'session' with the server. - _channel = new ClientSessionChannel( - clientDescription, - null, // no x509 certificates - new AnonymousIdentity(), // no user identity - "" + _endpointURL, - SecurityPolicyUris.None); // no encryption + // Create Endpoint + var Endpoint = new EndpointDescription + { + EndpointUrl = _endpointURL, + SecurityPolicyUri = _securityPolicy, + SecurityMode = _securityMode, + }; + + /// + ///Set up auto connection by getting all endpoints from server and using one of these endpoints + ///Used by AID Submodel + /// + if (_autoConnect) + { + + var endpointRequest = new GetEndpointsRequest() + { + EndpointUrl = _endpointURL, + }; + GetEndpointsResponse endpoints = await DiscoveryService.GetEndpointsAsync(endpointRequest); + if (endpoints.Endpoints != null) + { + foreach (var endpoint in endpoints.Endpoints) + { + if (endpoint.SecurityMode.ToString().ToLower() == "none" && + endpoint.SecurityPolicyUri.Split("#").Last().ToLower() == "none") + { + _log?.Info("Using auto connect option..."); + _log?.Info($"Creating channel from one of {endpoints.Endpoints.Length} Endpoints"); + _log?.Info($"Using Endpoint : Security Mode = {endpoint.SecurityMode} and Security Policy: {endpoint.SecurityPolicyUri.Split("#").Last()}"); + Endpoint.EndpointUrl = endpoint.EndpointUrl; + Endpoint.SecurityMode = endpoint.SecurityMode; + Endpoint.SecurityPolicyUri = endpoint.SecurityPolicyUri; + _channel = new ClientSessionChannel( + clientDescription, + null, // no x509 certificates + new AnonymousIdentity(), // no user identity + Endpoint); + + } + break; + } + } + + } + + /// + ///Set up Secure Session. Used by AID Submodel + /// + + else if (_securityMode != MessageSecurityMode.None && _securityPolicy != SecurityPolicyUris.None) + { + /// + ///create directory for client certificate. + ///certificate will be created if none is existing. + ///If the server does not auto accept certificates, it is mandatory to copy this client's public key + ///in ./pki/own/certs folder and add it to the server's trusted folders + /// + _log?.Info($"....Creating Secure channel with security mode: {_securityMode} and security policy: {_securityPolicy}"); + var certificatestore = new DirectoryStore("./pki"); + // create a 'ClientSessionChannel', a client-side channel that opens a 'session' with the server. + _channel = new ClientSessionChannel( + clientDescription, + certificatestore, + new AnonymousIdentity(), // no user identity + Endpoint // endpoint built for opc ua security + ); + + } + /// + /// Set up Unsecure Session. Used by AID, MTP and UaClient plugins + /// + + else if (_securityMode == MessageSecurityMode.None) + { + // create a 'ClientSessionChannel', a client-side channel that opens a 'session' with the server. + _log?.Info($"....Creating Unsecure channel with security mode: {_securityMode} and security policy: {_securityPolicy}"); + _channel = new ClientSessionChannel( + clientDescription, + null, // no x509 certificates + new AnonymousIdentity(), // no user identity + + Endpoint); + } // try opening a session and reading a few nodes. try { await _channel.OpenAsync(); - } catch (Exception ex) + } + catch (Exception ex) { ClientStatus = AasOpcUaClientStatus.ErrorCreateSession; _log?.Error(ex, "open async"); diff --git a/src/AasxPackageExplorer.sln b/src/AasxPackageExplorer.sln index c1906122..15961177 100644 --- a/src/AasxPackageExplorer.sln +++ b/src/AasxPackageExplorer.sln @@ -264,7 +264,6 @@ Global {EBAE658A-3ECE-4C98-89BC-F79809AB4A5E}.ReleaseWithoutCEF|x86.ActiveCfg = Release|Any CPU {EBAE658A-3ECE-4C98-89BC-F79809AB4A5E}.ReleaseWithoutCEF|x86.Build.0 = Release|Any CPU {967E60E3-D668-42A3-AA0B-1A031C20D871}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {967E60E3-D668-42A3-AA0B-1A031C20D871}.Debug|Any CPU.Build.0 = Debug|Any CPU {967E60E3-D668-42A3-AA0B-1A031C20D871}.Debug|x64.ActiveCfg = Debug|Any CPU {967E60E3-D668-42A3-AA0B-1A031C20D871}.Debug|x64.Build.0 = Debug|Any CPU {967E60E3-D668-42A3-AA0B-1A031C20D871}.Debug|x86.ActiveCfg = Debug|Any CPU @@ -802,7 +801,6 @@ Global {7788AC2B-7F97-4755-B343-C4196FA90198}.ReleaseWithoutCEF|x86.ActiveCfg = Release|Any CPU {7788AC2B-7F97-4755-B343-C4196FA90198}.ReleaseWithoutCEF|x86.Build.0 = Release|Any CPU {2F21FEFF-F0EF-40B5-BA05-09FC9F499AE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2F21FEFF-F0EF-40B5-BA05-09FC9F499AE9}.Debug|Any CPU.Build.0 = Debug|Any CPU {2F21FEFF-F0EF-40B5-BA05-09FC9F499AE9}.Debug|x64.ActiveCfg = Debug|Any CPU {2F21FEFF-F0EF-40B5-BA05-09FC9F499AE9}.Debug|x64.Build.0 = Debug|Any CPU {2F21FEFF-F0EF-40B5-BA05-09FC9F499AE9}.Debug|x86.ActiveCfg = Debug|Any CPU @@ -1552,7 +1550,6 @@ Global {4EB64F40-1A01-46BB-BEED-D1A75313C7F8}.ReleaseWithoutCEF|x86.ActiveCfg = Release|Any CPU {4EB64F40-1A01-46BB-BEED-D1A75313C7F8}.ReleaseWithoutCEF|x86.Build.0 = Release|Any CPU {BE68E42C-28CB-4298-9F34-A18AF92FC4DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BE68E42C-28CB-4298-9F34-A18AF92FC4DE}.Debug|Any CPU.Build.0 = Debug|Any CPU {BE68E42C-28CB-4298-9F34-A18AF92FC4DE}.Debug|x64.ActiveCfg = Debug|Any CPU {BE68E42C-28CB-4298-9F34-A18AF92FC4DE}.Debug|x64.Build.0 = Debug|Any CPU {BE68E42C-28CB-4298-9F34-A18AF92FC4DE}.Debug|x86.ActiveCfg = Debug|Any CPU diff --git a/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.csproj b/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.csproj index 6166ed62..02599e40 100644 --- a/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.csproj +++ b/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.csproj @@ -15,6 +15,7 @@ + @@ -33,6 +34,7 @@ + @@ -42,6 +44,7 @@ + diff --git a/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.options.json b/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.options.json index 15734b7b..6a29021c 100644 --- a/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.options.json +++ b/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.options.json @@ -1,7 +1,8 @@ { "Records": [ { - "IsDescription": true, + "IsDescription1_0": true, + "IsDescription1_1": false, "IsMapping": false, "AllowSubmodelSemanticId": [ { @@ -9,13 +10,31 @@ "value": "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Submodel" } ], - "UseHttp": false, + "UseHttp": true, "UseModbus": false, "UseMqtt": false, - "UseOpcUa": true + "UseOpcUa": false, + "UseBacnet": false }, { - "IsDescription": false, + "IsDescription1_0": false, + "IsDescription1_1": true, + "IsMapping": false, + "AllowSubmodelSemanticId": [ + { + "type": "Submodel", + "value": "https://admin-shell.io/idta/AssetInterfacesDescription/1/1/Submodel" + } + ], + "UseHttp": true, + "UseModbus": false, + "UseMqtt": false, + "UseOpcUa": false, + "UseBacnet": false + }, + { + "IsDescription1_0": false, + "IsDescription1_1": false, "IsMapping": true, "AllowSubmodelSemanticId": [ { diff --git a/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs b/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs new file mode 100644 index 00000000..bf7aa5ea --- /dev/null +++ b/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs @@ -0,0 +1,125 @@ +using AdminShellNS; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO.BACnet; +using System.Threading.Tasks; +using Aas = AasCore.Aas3_0; + +namespace AasxPluginAssetInterfaceDescription +{ + public class AidBacnetConnection : AidBaseConnection + { + public BacnetClient Client; + private Dictionary DeviceAddresses = new Dictionary(); + public BacnetAddress deviceAddress; + + override public async Task Open() + { + try + { + Client = new BacnetClient(); + Client.OnIam += OnIamHandler; + + if (TimeOutMs >= 10) + { + Client.Timeout = (int)TimeOutMs; + } + + Client.Start(); + + // Extract device ID from the URI + uint deviceId = uint.Parse(TargetUri.Host); + if (!DeviceAddresses.ContainsKey(deviceId)) + { + Client.WhoIs((int)deviceId, (int)deviceId); + await Task.Delay(1000); + } + if (!DeviceAddresses.TryGetValue(deviceId, out deviceAddress)) + { + return false; + } + + await Task.Yield(); + return true; + } + catch (Exception) + { + Client = null; + return false; + } + } + + private void OnIamHandler(BacnetClient sender, BacnetAddress adr, uint deviceId, uint maxAPDU, BacnetSegmentations segmentation, ushort vendorId) + { + // Store the device address from I-Am response + DeviceAddresses[deviceId] = adr; + } + + override public bool IsConnected() + { + return Client != null; + } + + override public void Close() + { + // Dispose client + if (Client != null) + { + Client.Dispose(); + Client = null; + } + } + + override public int UpdateItemValue(AidIfxItemStatus item) + { + int res = 0; + if (item?.FormData?.Href?.HasContent() != true || + item.FormData.Bacv_useService?.HasContent() != true || + !IsConnected() || + Client == null) + { + return res; + } + try + { + + var href = item.FormData.Href.TrimStart('/'); + string[] mainParts = href.Split('/'); + string[] objectParts = mainParts[0].Split(','); + + var objectType = (BacnetObjectTypes)int.Parse(objectParts[0]); + uint instance = uint.Parse(objectParts[1]); + BacnetObjectId objectId = new BacnetObjectId(objectType, instance); + + var propertyId = (BacnetPropertyIds)int.Parse(mainParts[1]); + + // READ operation + if (item.FormData.Bacv_useService.Trim().ToLower() == "readproperty") + { + try + { + IList values_r1 = new List(); + bool result_r1 = Client.ReadPropertyRequest(deviceAddress, objectId, propertyId, out values_r1); + if (result_r1 && values_r1.Count > 0 && values_r1[0].Value != null) + { + float val_r1 = (float)values_r1[0].Value; + item.Value = val_r1.ToString("R", CultureInfo.InvariantCulture); + NotifyOutputItems(item, item.Value); + res = 1; + } + } + catch (Exception) + { + return res; + } + } + } + catch (Exception) + { + return res; + } + return res; + } + } +} \ No newline at end of file diff --git a/src/AasxPluginAssetInterfaceDesc/AidInterfaceStatus.cs b/src/AasxPluginAssetInterfaceDesc/AidInterfaceStatus.cs index 6ae8d03f..5b416085 100644 --- a/src/AasxPluginAssetInterfaceDesc/AidInterfaceStatus.cs +++ b/src/AasxPluginAssetInterfaceDesc/AidInterfaceStatus.cs @@ -7,28 +7,31 @@ This source code is licensed under the Apache License 2.0 (see LICENSE.txt). This source code may use other Open Source software components (see LICENSE.txt). */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using AasCore.Aas3_1; +using AasxIntegrationBase; +using AasxIntegrationBase.AdminShellEvents; using AasxPredefinedConcepts; -using Aas = AasCore.Aas3_1; +using AasxPredefinedConcepts.AssetInterfacesDescription; using AdminShellNS; using AdminShellNS.DiaryData; +using AnyUi; using Extensions; -using AasxIntegrationBase; -using AasxPredefinedConcepts.AssetInterfacesDescription; using FluentModbus; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; using System.Net; +using System.Text; using System.Text.RegularExpressions; -using System.Globalization; -using AnyUi; +using System.Threading.Tasks; +using System.Windows.Controls; using System.Windows.Media.Animation; -using AasxIntegrationBase.AdminShellEvents; -using System.IO; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json; +using static System.Net.WebRequestMethods; +using Aas = AasCore.Aas3_1; namespace AasxPluginAssetInterfaceDescription { @@ -97,7 +100,7 @@ public class AidIfxItemStatus public AnyUiUIElement RenderedUiElement = null; } - public enum AidInterfaceTechnology { HTTP, Modbus, MQTT, OPCUA } + public enum AidInterfaceTechnology { HTTP, Modbus, MQTT, OPCUA, BACNET } public class AidInterfaceStatus { @@ -120,7 +123,7 @@ public class AidInterfaceStatus /// /// The information items (properties, actions, events) /// - public MultiValueDictionary Items = + public MultiValueDictionary Items = new MultiValueDictionary(); /// @@ -128,6 +131,27 @@ public class AidInterfaceStatus /// public string EndpointBase = ""; + /// + /// For creating OPC UA secured channel. it can be either None, Sign, SignAndEncrypt + /// + + public int SecurityMode = 1; + + /// + /// For creating OPC UA security channel. For this version, only + /// None, Basic256Sha256, Aes128_Sha256_RsaOaep, Aes256_Sha256_RsaPss, + /// Outdated(not recommended policies):Basic256, Basic128Rsa15 + /// + + public string SecurityPolicy = "http://opcfoundation.org/UA/SecurityPolicy#None"; + + /// + /// For creating OPC UA security channel. + /// when AutoConnection is true, the client gets endpoints from server + /// and pick one from the list of endpoints to set up the session. + /// + + public bool OPCAutoConnection = false; /// /// Used by byteStream payload for decoding, presently, mainly used by Modbus but other protocols will also be using it @@ -201,7 +225,7 @@ protected string ComputeKey(string key) return key; } - public void SetLogLine (StoredPrint.Color color, string line) + public void SetLogLine(StoredPrint.Color color, string line) { LogColor = color; LogLine = line; @@ -219,7 +243,7 @@ public void AddItem(AidIfxItemStatus item) // compute key var key = ComputeKey(item?.FormData?.Href); - + // now add Items.Add(key, item); } @@ -257,6 +281,28 @@ public class AidBaseConnection /// public string Password = null; + /// + /// For creating OPC UA secured channel. it can be either None, Sign, SignAndEncrypt + /// + + public int SecurityMode = 1; + + /// + /// For creating OPC UA security channel. For this version, only + /// None, Basic256Sha256, Aes128_Sha256_RsaOaep, Aes256_Sha256_RsaPss, + /// Outdated(not recommended policies):Basic256, Basic128Rsa15 + /// + + public string SecurityPolicy = null; + + /// + /// For creating OPC UA security channel. + /// when AutoConnection is true, the client gets endpoints from server + /// and pick one from the list of endpoints to set up the session. + /// + + public bool OPCAutoConnection = false; + /// /// Used by byteStream payload for decoding, presently, mainly used by Modbus but other protocols will also be using it /// @@ -401,7 +447,7 @@ public void NotifyOutputItems(AidIfxItemStatus item, string strval) } } - + } } } @@ -428,6 +474,13 @@ public T GetOrCreate(string target, LogInstance log = null) /// public class AidAllInterfaceStatus { + /// + /// Flag to enable or disable protocols in the UI based on AID version. + /// Version 1.0 will enable HTTP, MODBUS and MQTT. + /// version 1.1 will enable HTTP, MODBUS, MQTT, OPCUA and BACNET. + /// + public bool AidVersion1_1 = false; + /// /// Set to logger, if logging is desired. /// @@ -451,7 +504,7 @@ public class AidAllInterfaceStatus /// /// Current setting, which technologies shall be used. /// - public bool[] UseTech = { false, false, false, true }; + public bool[] UseTech = { true, false, false, false, false }; /// /// Will hold connections steady and continously update values, either by @@ -464,7 +517,7 @@ public class AidAllInterfaceStatus public AidGenericConnections HttpConnections = new AidGenericConnections(); - public AidGenericConnections ModbusConnections = + public AidGenericConnections ModbusConnections = new AidGenericConnections(); public AidGenericConnections MqttConnections = @@ -473,6 +526,9 @@ public class AidAllInterfaceStatus public AidGenericConnections OpcUaConnections = new AidGenericConnections(); + public AidGenericConnections BacnetConnections = + new AidGenericConnections(); + public AidAllInterfaceStatus(LogInstance log = null) { _log = log; @@ -494,7 +550,7 @@ public void RememberAidSubmodel(Aas.ISubmodel sm, AssetInterfaceOptionsRecord op if (sm == null || optRec == null) return; - if (optRec.IsDescription) + if (optRec.IsDescription1_0 || optRec.IsDescription1_1) SmAidDescription = sm; if (adoptUseFlags) @@ -503,6 +559,7 @@ public void RememberAidSubmodel(Aas.ISubmodel sm, AssetInterfaceOptionsRecord op UseTech[(int)AidInterfaceTechnology.Modbus] = optRec.UseModbus; UseTech[(int)AidInterfaceTechnology.MQTT] = optRec.UseMqtt; UseTech[(int)AidInterfaceTechnology.OPCUA] = optRec.UseOpcUa; + UseTech[(int)AidInterfaceTechnology.BACNET] = optRec.UseBacnet; } } @@ -538,7 +595,15 @@ protected AidBaseConnection GetOrCreate( case AidInterfaceTechnology.OPCUA: conn = OpcUaConnections.GetOrCreate(endpointBase, log); + conn.OPCAutoConnection = ifcStatus.OPCAutoConnection; + conn.SecurityMode = ifcStatus.SecurityMode; + conn.SecurityPolicy = ifcStatus.SecurityPolicy; + break; + + case AidInterfaceTechnology.BACNET: + conn = BacnetConnections.GetOrCreate(endpointBase, log); break; + } conn.UpdateFreqMs = ifcStatus.UpdateFreqMs; @@ -762,17 +827,17 @@ public async Task UpdateValuesContinousByTickAsyc() // go thru all items (sync) foreach (var item in ifc.Items.Values) - ifc.ValueChanges += (UInt64) ifc.Connection.UpdateItemValue(item); + ifc.ValueChanges += (UInt64)ifc.Connection.UpdateItemValue(item); // go thru all items (async) // see: https://www.hanselman.com/blog/parallelforeachasync-in-net-6 await Parallel.ForEachAsync( - ifc.Items.Values, - new ParallelOptions() { MaxDegreeOfParallelism = 10 }, + ifc.Items.Values, + new ParallelOptions() { MaxDegreeOfParallelism = 10 }, async (item, token) => - { - ifc.ValueChanges += (UInt64) (await ifc.Connection.UpdateItemValueAsync(item)); - }); + { + ifc.ValueChanges += (UInt64)(await ifc.Connection.UpdateItemValueAsync(item)); + }); } } } @@ -810,17 +875,20 @@ public void PrepareAidInformation(Aas.ISubmodel smAid, Aas.ISubmodel smMapping = // get data MC var dataMc = (smMapping != null) ? - new AasxPredefinedConcepts.AssetInterfacesMappingConfiguration. - CD_AssetInterfacesMappingConfiguration() : null; + new AasxPredefinedConcepts.AssetInterfacesMappingConfiguration. + CD_AssetInterfacesMappingConfiguration() : null; PredefinedConceptsClassMapper.ParseAasElemsToObject(smMapping, dataMc, lambdaLookupReference); // prepare foreach (var tech in AdminShellUtil.GetEnumValues()) { var ifxs = dataAid?.InterfaceHTTP; + ifxs = null; + if (tech == AidInterfaceTechnology.HTTP) ifxs = dataAid?.InterfaceHTTP; if (tech == AidInterfaceTechnology.Modbus) ifxs = dataAid?.InterfaceMODBUS; if (tech == AidInterfaceTechnology.MQTT) ifxs = dataAid?.InterfaceMQTT; - if (tech == AidInterfaceTechnology.OPCUA) ifxs = dataAid?.InterfaceOPCUA; + if (tech == AidInterfaceTechnology.OPCUA && AidVersion1_1) ifxs = dataAid?.InterfaceOPCUA; + if (tech == AidInterfaceTechnology.BACNET && AidVersion1_1) ifxs = dataAid?.InterfaceBACNET; if (ifxs == null || ifxs.Count < 1) continue; foreach (var ifx in ifxs) @@ -829,6 +897,7 @@ public void PrepareAidInformation(Aas.ISubmodel smAid, Aas.ISubmodel smMapping = var dn = AdminShellUtil.TakeFirstContent(ifx.Title, ifx.__Info__?.Referable?.IdShort); var aidIfx = new AidInterfaceStatus() { + Technology = tech, DisplayName = $"{dn}", Info = $"{ifx.EndpointMetadata?.Base}", @@ -853,7 +922,7 @@ public void PrepareAidInformation(Aas.ISubmodel smAid, Aas.ISubmodel smMapping = FormData = propName.Forms, Value = "???" }; - + // does (some) mapping have a source with this property name? var lst = new List(); @@ -874,7 +943,7 @@ public void PrepareAidInformation(Aas.ISubmodel smAid, Aas.ISubmodel smMapping = aidIfx.AddItem(ifcItem); ifcItem.MapOutputItems = lst; } - + // directly recurse? if (propName?.Properties?.Property != null) @@ -884,17 +953,113 @@ public void PrepareAidInformation(Aas.ISubmodel smAid, Aas.ISubmodel smMapping = child.Forms = propName.Forms; recurseProp(location + " . " + ifcItem.DisplayName, child); } - + }; if (ifx.InteractionMetadata?.Properties?.Property == null) continue; foreach (var propName in ifx.InteractionMetadata?.Properties?.Property) recurseProp("\u2302", propName); + + //Handling of opc ua security + if (aidIfx.Technology == AidInterfaceTechnology.OPCUA) + { + ExtractSecurityData(ifx, aidIfx); + + } + } } } + protected void ExtractSecurityData(CD_GenericInterface ifx, AidInterfaceStatus aidIfx) + { + if (ifx.EndpointMetadata.Security.SecurityRef.Count > 0 && + ifx.EndpointMetadata.Security.SecurityRef[0].ValueHint != null && + ifx.EndpointMetadata.Security.SecurityRef[0].ValueHint is SubmodelElementCollection securityRef) + { + + if (securityRef.SemanticId?.GetAsExactlyOneKey().Value == "https://www.w3.org/2019/wot/security#NoSecurityScheme") + { + aidIfx.SecurityMode = 1; + aidIfx.SecurityPolicy = "http://opcfoundation.org/UA/SecurityPolicy#None"; + return; + } + else if (securityRef.SemanticId?.GetAsExactlyOneKey().Value == "https://www.w3.org/2019/wot/security#AutoSecurityScheme") + { + aidIfx.OPCAutoConnection = true; + return; + + } + else if(securityRef.SemanticId?.GetAsExactlyOneKey().Value == "https://www.w3.org/2019/wot/security#ComboSecurityScheme") + { + //Combo Security implementation here + // Handling allOf + foreach(var opcuaSecurityRef in ifx.EndpointMetadata.SecurityDefinitions.Combo_sc.AllOf.SecurityRef) + { + if(opcuaSecurityRef != null && opcuaSecurityRef.ValueHint is SubmodelElementCollection opcuasec) + { + if(opcuasec.SemanticId.GetAsExactlyOneKey().Value == "http://opcfoundation.org/UA/WoT-Binding/OPCUASecurityChannelScheme") + { + switch(ifx.EndpointMetadata.SecurityDefinitions.Opcua_channel_sc.Uav_securityMode.ToLower()) + { + case "none": + aidIfx.SecurityMode = 1; + break; + case "sign": + aidIfx.SecurityMode = 2; + break; + case "signandencrypt": + aidIfx.SecurityMode = 3; + break; + default: + aidIfx.SecurityMode = 1; + break; + + + } + switch (ifx.EndpointMetadata.SecurityDefinitions.Opcua_channel_sc.Uav_securityPolicy.ToLower()) + { + case "basic256sha256": + aidIfx.SecurityPolicy = "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256"; + break; + case "aes128_sha256_rsaoaep": + aidIfx.SecurityPolicy = "http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep"; + break; + case "aes256_sha256_rsapss": + aidIfx.SecurityPolicy = "http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss"; + break; + case "basic256": + aidIfx.SecurityPolicy = "http://opcfoundation.org/UA/SecurityPolicy#Basic256"; + break; + case "basic128rsa15": + aidIfx.SecurityPolicy = "http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15"; + break; + default: + aidIfx.SecurityPolicy = "http://opcfoundation.org/UA/SecurityPolicy#None"; + break; + } + } + + } + + } + return; + } + else + { + aidIfx.SecurityMode = 1; + aidIfx.SecurityPolicy = "http://opcfoundation.org/UA/SecurityPolicy#None"; + return; + } + } + else + { + aidIfx.SecurityMode = 1; + aidIfx.SecurityPolicy = "http://opcfoundation.org/UA/SecurityPolicy#None"; + return; + } + } protected List SelectValuesToIntList( IEnumerable items, Func selectStringValue) where ITEM : class @@ -956,20 +1121,6 @@ public void SetAidInformationForUpdateAndTimeout( ref ifc.TimeOutMs, 10.0, defaultTimeOutMs, SelectValuesToIntList(ifc?.Items?.Values, (it) => it.FormData?.Modv_timeout)); } - - // for OPC UA, analyze update frequency and timeout - foreach (var ifc in InterfaceStatus.Where((i) => i.Technology == AidInterfaceTechnology.OPCUA)) - { - // polltimes - SetDoubleOnDefaultOrAvgOfIntList( - ref ifc.UpdateFreqMs, 10.0, defaultUpdateFreqMs, - SelectValuesToIntList(ifc?.Items?.Values, (it) => it.FormData?.OpcUa_pollingTime)); - - // time out - SetDoubleOnDefaultOrAvgOfIntList( - ref ifc.TimeOutMs, 10.0, defaultTimeOutMs, - SelectValuesToIntList(ifc?.Items?.Values, (it) => it.FormData?.OpcUa_timeout)); - } } } diff --git a/src/AasxPluginAssetInterfaceDesc/AidOpcUaConnection.cs b/src/AasxPluginAssetInterfaceDesc/AidOpcUaConnection.cs index 0778dd59..f0cd3e51 100644 --- a/src/AasxPluginAssetInterfaceDesc/AidOpcUaConnection.cs +++ b/src/AasxPluginAssetInterfaceDesc/AidOpcUaConnection.cs @@ -29,6 +29,8 @@ This source code may use other Open Source software components (see LICENSE.txt) using MQTTnet.Client; using System.Web.Services.Description; using AasxOpcUa2Client; +using System.IO; + #if OPCUA2 @@ -75,13 +77,18 @@ override public async Task Open() // make client // use the full target uri as endpoint (first) #if OPCUA2 + Client = new AasOpcUaClient2( TargetUri.ToString(), autoAccept: true, userName: this.User, password: this.Password, timeOutMs: (TimeOutMs >= 10) ? (uint)TimeOutMs : 2000, - log: Log); + log: Log, + securityMode: (MessageSecurityMode?)this.SecurityMode, + securityPolicy: this.SecurityPolicy, + autoConnect: this.OPCAutoConnection); + #else Client = new AasOpcUaClient( TargetUri.ToString(), @@ -138,12 +145,17 @@ override public async Task UpdateItemValueAsync(AidIfxItemStatus item) // careful try { + var nodePath = "" + item.FormData?.Href; + nodePath = nodePath.Replace("/?id =", "").Trim(); // get an node id? - var nid = Client.ParseAndCreateNodeId(item?.FormData?.Href); + var nid = Client.ParseAndCreateNodeId(nodePath); // direct read possible? var dv = await Client.ReadNodeIdAsync(nid); item.Value = AdminShellUtil.ToStringInvariant(dv?.Value); + + // notify + NotifyOutputItems(item, item.Value); LastActive = DateTime.Now; // success @@ -198,11 +210,14 @@ override public async Task PrepareContinousRunAsync(IEnumerable _dictTechnologyToBitmap = + protected Dictionary _dictTechnologyToBitmap = new Dictionary(); private System.Timers.Timer _dispatcherTimer = null; @@ -109,6 +110,10 @@ public void Start( _dictTechnologyToBitmap = new Dictionary(); if (OperatingSystem.IsWindowsVersionAtLeast(7)) { + _dictTechnologyToBitmap.Add(AidInterfaceTechnology.BACNET, + AnyUiGdiHelper.CreateAnyUiBitmapFromResource( + "AasxPluginAssetInterfaceDesc.Resources.logo-bacnet.png", + assembly: Assembly.GetExecutingAssembly())); _dictTechnologyToBitmap.Add(AidInterfaceTechnology.HTTP, AnyUiGdiHelper.CreateAnyUiBitmapFromResource( "AasxPluginAssetInterfaceDesc.Resources.logo-http.png", @@ -283,13 +288,13 @@ protected void RenderPanelInner( uitk.AddSmallLabelTo(grid, 0, 0, content: "Technologies:"); - var gridTech = uitk.AddSmallGridTo(grid, 0, 1, rows: 1, cols: 6, + var gridTech = uitk.AddSmallGridTo(grid, 0, 1, rows: 1, cols: 6, colWidths: new[] { "#", "#", "#", "#", "#", "#" }); foreach (var tech in AdminShellUtil.GetEnumValues()) { AnyUiUIElement.SetBoolFromControl( - uitk.AddSmallCheckBoxTo(gridTech, 0, 0 + ((int) tech), + uitk.AddSmallCheckBoxTo(gridTech, 0, 0 + ((int)tech), margin: new AnyUiThickness(0, 0, 10, 0), content: "" + tech.ToString(), isChecked: _allInterfaceStatus.UseTech[(int)tech], @@ -302,7 +307,7 @@ protected void RenderPanelInner( // uitk.AddSmallLabelTo(grid, 1, 0, content: "Startup:"); - + AnyUiUIElement.RegisterControl( uitk.AddSmallButtonTo(grid, 1, 1, margin: new AnyUiThickness(2), setHeight: 21, @@ -319,11 +324,18 @@ protected void RenderPanelInner( return new AnyUiLambdaActionNone(); } + // Check if at least one technology is selected + if (!_allInterfaceStatus.UseTech.Any(tech => tech)) + { + _log.Info(StoredPrint.Color.Blue, "Please select at least one technology."); + return new AnyUiLambdaActionNone(); + } + // build up data structures _allInterfaceStatus.PrepareAidInformation( _allInterfaceStatus.SmAidDescription, _allInterfaceStatus.SmAidMapping, - lambdaLookupReference: (rf) => package?.AasEnv?.FindReferableByReference(rf) ); + lambdaLookupReference: (rf) => package?.AasEnv?.FindReferableByReference(rf)); _allInterfaceStatus.SetAidInformationForUpdateAndTimeout(); // trigger a complete redraw, as the regions might emit @@ -345,7 +357,7 @@ protected void RenderPanelInner( setValueAsync: async (o) => { try - { + { // locked? if (_allInterfaceStatus?.ContinousRun == true) { @@ -451,7 +463,7 @@ public void Update(params object[] args) #region Interface items //===================== - + protected void RenderTripleRowData( AnyUiStackPanel view, AnyUiSmallWidgetToolkit uitk, List interfaces) @@ -460,11 +472,16 @@ protected void RenderTripleRowData( if (interfaces == null) return; + // Filter interfaces based on selected technologies + var filteredInterfaces = interfaces.Where(ifx => + _allInterfaceStatus.UseTech[(int)ifx.Technology]).ToList(); + // ok - var grid = view.Add(uitk.AddSmallGrid(rows: interfaces.Count, cols: 5, + var grid = view.Add(uitk.AddSmallGrid(rows: interfaces.Count, cols: 5, colWidths: new[] { "40:", "1*", "1*", "1*", "180:" })); int rowIndex = 0; - foreach (var ifx in interfaces) + + foreach (var ifx in filteredInterfaces) { // // heading @@ -479,7 +496,7 @@ protected void RenderTripleRowData( colSpan: 5); if (_dictTechnologyToBitmap.ContainsKey(ifx.Technology)) - uitk.AddSmallImageTo(headGrid, 0, 0, + uitk.AddSmallImageTo(headGrid, 0, 0, margin: new AnyUiThickness(0, 4, 10, 4), bitmap: _dictTechnologyToBitmap[ifx.Technology]); @@ -503,13 +520,13 @@ protected void RenderTripleRowData( { // normal row, 5 bordered cells grid.RowDefinitions.Add(new AnyUiRowDefinition()); - var cols = new[] { + var cols = new[] { "Prop.", item.Location, item.DisplayName, "" + item.FormData?.Href, item.Value }; for (int ci = 0; ci < 5; ci++) { var brd = uitk.AddSmallBorderTo(grid, rowIndex, ci, - margin: (ci == 0) ? new AnyUiThickness(0, -1, 0, 0) - : new AnyUiThickness(-1, -1, 0, 0), + margin: (ci == 0) ? new AnyUiThickness(0, -1, 0, 0) + : new AnyUiThickness(-1, -1, 0, 0), borderThickness: new AnyUiThickness(1.0), borderBrush: AnyUiBrushes.DarkGray); brd.Child = new AnyUiSelectableTextBlock() { @@ -534,7 +551,7 @@ protected void RenderTripleRowData( var innerGrid = uitk.Set( uitk.AddSmallGridTo(grid, rowIndex++, 1, - rows: item.MapOutputItems.Count, + rows: item.MapOutputItems.Count, cols: 3, colWidths: new[] { "#", "*", "#" }, margin: new AnyUiThickness(2, 0, 0, 6)), colSpan: 4); @@ -656,4 +673,4 @@ private void DispatcherTimer_Tick(object sender, EventArgs e) #endregion } -} +} \ No newline at end of file diff --git a/src/AasxPluginAssetInterfaceDesc/AssetInterfaceOptions.cs b/src/AasxPluginAssetInterfaceDesc/AssetInterfaceOptions.cs index 708c464b..9a6cc528 100644 --- a/src/AasxPluginAssetInterfaceDesc/AssetInterfaceOptions.cs +++ b/src/AasxPluginAssetInterfaceDesc/AssetInterfaceOptions.cs @@ -22,13 +22,15 @@ namespace AasxPluginAssetInterfaceDescription { public class AssetInterfaceOptionsRecord : AasxPluginOptionsLookupRecordBase { - public bool IsDescription = false; + public bool IsDescription1_0 = false; + public bool IsDescription1_1 = false; public bool IsMapping = false; public bool UseHttp = true; public bool UseModbus = true; public bool UseMqtt = true; public bool UseOpcUa = true; + public bool UseBacnet = true; } public class AssetInterfaceOptions : AasxPluginLookupOptionsBase @@ -43,13 +45,19 @@ public static AssetInterfaceOptions CreateDefault() var defs = new DefinitionsMTP.ModuleTypePackage(); var rec1 = new AssetInterfaceOptionsRecord(); - rec1.IsDescription = true; - rec1.AllowSubmodelSemanticId = new[] { - new Aas.Key(Aas.KeyTypes.Submodel, + rec1.IsDescription1_0 = true; + rec1.AllowSubmodelSemanticId = new[] { + new Aas.Key(Aas.KeyTypes.Submodel, "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Submodel") }.ToList(); var rec2 = new AssetInterfaceOptionsRecord(); - rec2.IsMapping = true; + rec2.IsDescription1_1 = true; + rec1.AllowSubmodelSemanticId = new[] { + new Aas.Key(Aas.KeyTypes.Submodel, + "https://admin-shell.io/idta/AssetInterfacesDescription/1/1/Submodel") }.ToList(); + + var rec3 = new AssetInterfaceOptionsRecord(); + rec3.IsMapping = true; rec1.AllowSubmodelSemanticId = new[] { new Aas.Key(Aas.KeyTypes.Submodel, "https://admin-shell.io/idta/AssetInterfacesMappingConfiguration/1/0/Submodel") }.ToList(); diff --git a/src/AasxPluginAssetInterfaceDesc/Plugin.cs b/src/AasxPluginAssetInterfaceDesc/Plugin.cs index 374490ad..b7a07f08 100644 --- a/src/AasxPluginAssetInterfaceDesc/Plugin.cs +++ b/src/AasxPluginAssetInterfaceDesc/Plugin.cs @@ -118,9 +118,22 @@ public class Session : PluginSessionBase return null; // remember for later / background - if (foundOptRec.IsDescription) + if (foundOptRec.IsDescription1_0) + { + _allInterfaceStatus.RememberAidSubmodel(sm, foundOptRec, + adoptUseFlags: true); + _allInterfaceStatus.AidVersion1_1 = false; + } + + + // remember for later / background + if (foundOptRec.IsDescription1_1) + { _allInterfaceStatus.RememberAidSubmodel(sm, foundOptRec, adoptUseFlags: true); + _allInterfaceStatus.AidVersion1_1 = true; + } + if (foundOptRec.IsMapping) _allInterfaceStatus.RememberMappingSubmodel(sm); @@ -273,7 +286,7 @@ public class Session : PluginSessionBase if (foundOptRec == null) continue; - if (foundOptRec.IsDescription) + if (foundOptRec.IsDescription1_0) _allInterfaceStatus.RememberAidSubmodel(sm, foundOptRec, adoptUseFlags: true); if (foundOptRec.IsMapping) diff --git a/src/AasxPluginAssetInterfaceDesc/Resources/logo-bacnet.png b/src/AasxPluginAssetInterfaceDesc/Resources/logo-bacnet.png new file mode 100644 index 00000000..cefb4d60 Binary files /dev/null and b/src/AasxPluginAssetInterfaceDesc/Resources/logo-bacnet.png differ diff --git a/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs b/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs index 28e3f272..2c012f6e 100644 --- a/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs +++ b/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs @@ -12,6 +12,7 @@ This source code may use other Open Source software components (see LICENSE.txt) using Extensions; using System; using System.Collections.Generic; +using static AasxPredefinedConcepts.ConceptModel.ConceptModelZveiTechnicalData; using Aas = AasCore.Aas3_1; // These classes were serialized by "export predefined concepts" @@ -20,7 +21,7 @@ This source code may use other Open Source software components (see LICENSE.txt) namespace AasxPredefinedConcepts.AssetInterfacesDescription { - + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Interface")] public class CD_GenericInterface { @@ -40,7 +41,7 @@ public class CD_GenericInterface public CD_EndpointMetadata EndpointMetadata = new CD_EndpointMetadata(); [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/InteractionMetadata", Card = AasxPredefinedCardinality.One)] - public CD_InterfaceMetadata InteractionMetadata = new CD_InterfaceMetadata(); + public CD_InteractionMetadata InteractionMetadata = new CD_InteractionMetadata(); [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/ExternalDescriptor", Card = AasxPredefinedCardinality.ZeroToOne)] public CD_ExternalDescriptor ExternalDescriptor = null; @@ -77,7 +78,9 @@ public class CD_EndpointMetadata [AasConcept(Cd = "https://www.w3.org/2019/wot/td#hasSecurityConfiguration")] public class CD_Security { - + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme", Card = AasxPredefinedCardinality.ZeroToMany)] + public List SecurityRef = new List(); + // auto-generated informations public AasClassMapperInfo __Info__ = null; } @@ -112,6 +115,12 @@ public class CD_SecurityDefinitions [AasConcept(Cd = "https://www.w3.org/2019/wot/security#OAuth2SecurityScheme", Card = AasxPredefinedCardinality.ZeroToOne)] public CD_Oauth2_sc Oauth2_sc = null; + [AasConcept(Cd = "http://opcfoundation.org/UA/WoT-Binding/OPCUASecurityChannelScheme", Card = AasxPredefinedCardinality.ZeroToOne)] + public CD_Opcua_channel_sc Opcua_channel_sc = null; + + [AasConcept(Cd = "http://opcfoundation.org/UA/WoT-Binding/OPCUASecurityAuthenticationScheme ", Card = AasxPredefinedCardinality.ZeroToOne)] + public CD_Opcua_authentication_sc Opcua_authentication_sc = null; + // auto-generated informations public AasClassMapperInfo __Info__ = null; } @@ -164,10 +173,10 @@ public class CD_Combo_sc [AasConcept(Cd = "https://www.w3.org/2019/wot/security#SecurityScheme", Card = AasxPredefinedCardinality.One)] public string Scheme; - [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#oneOf", Card = AasxPredefinedCardinality.One)] + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#oneOf", Card = AasxPredefinedCardinality.One)] public CD_OneOf OneOf = new CD_OneOf(); - [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#allOf", Card = AasxPredefinedCardinality.One)] + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#allOf", Card = AasxPredefinedCardinality.One)] public CD_AllOf AllOf = new CD_AllOf(); [AasConcept(Cd = "https://www.w3.org/2019/wot/security#proxy", Card = AasxPredefinedCardinality.ZeroToOne)] @@ -177,18 +186,20 @@ public class CD_Combo_sc public AasClassMapperInfo __Info__ = null; } - [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#oneOf")] + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#oneOf")] public class CD_OneOf { - + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme", Card = AasxPredefinedCardinality.ZeroToMany)] + public List SecurityRef = new List(); // auto-generated informations public AasClassMapperInfo __Info__ = null; } - [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#allOf")] + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#allOf")] public class CD_AllOf { - + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#definesSecurityScheme", Card = AasxPredefinedCardinality.ZeroToMany)] + public List SecurityRef = new List(); // auto-generated informations public AasClassMapperInfo __Info__ = null; } @@ -305,8 +316,46 @@ public class CD_Oauth2_sc public AasClassMapperInfo __Info__ = null; } - [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/InterfaceMetadata")] - public class CD_InterfaceMetadata + [AasConcept(Cd = "http://opcfoundation.org/UA/WoT-Binding/OPCUASecurityChannelScheme")] + public class CD_Opcua_channel_sc + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#SecurityScheme", Card = AasxPredefinedCardinality.One)] + public string Scheme; + + [AasConcept(Cd = "http://opcfoundation.org/UA/WoT-Binding/securityMode ", Card = AasxPredefinedCardinality.One)] + public string Uav_securityMode; + + [AasConcept(Cd = "http://opcfoundation.org/UA/WoT-Binding/securityPolicy", Card = AasxPredefinedCardinality.One)] + public string Uav_securityPolicy; + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#proxy", Card = AasxPredefinedCardinality.ZeroToOne)] + public string Proxy; + + // auto-generated informations + public AasClassMapperInfo __Info__ = null; + } + + [AasConcept(Cd = "http://opcfoundation.org/UA/WoT-Binding/OPCUASecurityAuthenticationScheme")] + public class CD_Opcua_authentication_sc + { + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#SecurityScheme", Card = AasxPredefinedCardinality.One)] + public string Scheme; + + [AasConcept(Cd = "http://opcfoundation.org/UA/WoT-Binding/userIdentityToken", Card = AasxPredefinedCardinality.One)] + public string Uav_userIdentityToken; + + [AasConcept(Cd = "http://opcfoundation.org/UA/WoT-Binding/issueToken", Card = AasxPredefinedCardinality.ZeroToOne)] + public AasClassMapperHintedReference Uav_issueToken = new AasClassMapperHintedReference(); + + [AasConcept(Cd = "https://www.w3.org/2019/wot/security#proxy", Card = AasxPredefinedCardinality.ZeroToOne)] + public string Proxy; + + // auto-generated informations + public AasClassMapperInfo __Info__ = null; + } + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/InteractionMetadata")] + public class CD_InteractionMetadata { [AasConcept(Cd = "https://www.w3.org/2019/wot/td#PropertyAffordance", Card = AasxPredefinedCardinality.ZeroToOne)] public CD_PropertiesAffordance Properties = null; @@ -350,6 +399,9 @@ public class CD_PropertyName [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#const", Card = AasxPredefinedCardinality.ZeroToOne)] public int? Const; + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#enum", Card = AasxPredefinedCardinality.ZeroToOne)] + public CD_Enum Enum = new CD_Enum(); + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#default", Card = AasxPredefinedCardinality.ZeroToOne)] public string Default; @@ -371,6 +423,12 @@ public class CD_PropertyName [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#properties", Card = AasxPredefinedCardinality.ZeroToOne)] public CD_Properties Properties = null; + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#hasUriTemplateSchema", Card = AasxPredefinedCardinality.ZeroToOne)] + public CD_Properties UriVariables = null; + + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/valueSemantics", Card = AasxPredefinedCardinality.ZeroToOne)] + public AasClassMapperHintedReference ValueSemanticas = new AasClassMapperHintedReference(); + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#hasForm", Card = AasxPredefinedCardinality.One)] public CD_Forms Forms = new CD_Forms(); @@ -378,6 +436,13 @@ public class CD_PropertyName public AasClassMapperInfo __Info__ = null; } + public class CD_Enum + { + + // auto-generated informations + public AasClassMapperInfo __Info__ = null; + } + [AasConcept(Cd = "https://www.w3.org/2019/wot/json-schema#items")] public class CD_Items { @@ -405,6 +470,9 @@ public class CD_Items [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/lengthRange", Card = AasxPredefinedCardinality.ZeroToOne)] public AasClassMapperRange LengthRange = null; + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/valueSemantics", Card = AasxPredefinedCardinality.ZeroToOne)] + public AasClassMapperHintedReference ValueSemanticas = new AasClassMapperHintedReference(); + // auto-generated informations public AasClassMapperInfo __Info__ = null; } @@ -476,11 +544,14 @@ public class CD_Forms [AasConcept(Cd = "https://www.w3.org/2019/wot/mqtt#hasQoSFlag", Card = AasxPredefinedCardinality.ZeroToOne)] public string Mqv_qos; - [AasConcept(Cd = "https://www.w3.org/2019/wot/opc-ua#pollingTime", Card = AasxPredefinedCardinality.ZeroToOne)] - public string OpcUa_pollingTime; + [AasConcept(Cd = "http://opcfoundation.org/UA/WoT-Binding#browsePath", Card = AasxPredefinedCardinality.ZeroToOne)] + public string Uav_browsePath; - [AasConcept(Cd = "https://www.w3.org/2019/wot/opc-ua#timeout", Card = AasxPredefinedCardinality.ZeroToOne)] - public string OpcUa_timeout; + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#usesService", Card = AasxPredefinedCardinality.ZeroToOne)] + public string Bacv_useService; + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasDataType", Card = AasxPredefinedCardinality.ZeroToOne)] + public CD_Bacv_hasDataType Bacv_hasDataType = null; // auto-generated informations public AasClassMapperInfo __Info__ = null; @@ -502,6 +573,58 @@ public class CD_Htv_headers public AasClassMapperInfo __Info__ = null; } + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasDataType")] + public class CD_Bacv_hasDataType + { + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#isIso8601", Card = AasxPredefinedCardinality.ZeroToOne)] + public bool? bacv_isISO8601; + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasBinaryRepresentation", Card = AasxPredefinedCardinality.ZeroToOne)] + public string bacv_hasBinaryRepresentation; + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasMember", Card = AasxPredefinedCardinality.ZeroToOne)] + public CD_Bacv_hasDataType bacv_hasMember = null; + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasNamedMember", Card = AasxPredefinedCardinality.ZeroToOne)] + public List bacv_hasNamedMember = null; + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasValueMap", Card = AasxPredefinedCardinality.ZeroToOne)] + public List bacv_hasValueMap = null; + + // auto-generated informations + public AasClassMapperInfo __Info__ = null; + } + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#NamedMember")] + public class CD_Bacv_hasNamedMember + { + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasfieldName", Card = AasxPredefinedCardinality.One)] + public string bacv_hasFieldName; + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasContextTag", Card = AasxPredefinedCardinality.ZeroToOne)] + public bool? bacv_hasContextTag; + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasDataType", Card = AasxPredefinedCardinality.ZeroToOne)] + public CD_Bacv_hasDataType bacv_hasDataType = null; + + // auto-generated informations + public AasClassMapperInfo __Info__ = null; + } + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasMapEntry")] + public class CD_Bacv_hasValueMap + { + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasLogicalVal", Card = AasxPredefinedCardinality.One)] + public string bacv_hasLogicalVal; + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasProtocolVal", Card = AasxPredefinedCardinality.One)] + public int bacv_hasProtocolVal; + + // auto-generated informations + public AasClassMapperInfo __Info__ = null; + } + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#ActionAffordance")] public class CD_Actions { @@ -525,9 +648,9 @@ public class CD_ExternalDescriptor // auto-generated informations public AasClassMapperInfo __Info__ = null; } - + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Submodel")] - public class CD_AssetInterfacesDescription + public class CD_AssetInterfacesDescription { [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Interface", Card = AasxPredefinedCardinality.ZeroToMany, SupplSemId = "http://www.w3.org/2011/http")] @@ -542,11 +665,14 @@ public class CD_AssetInterfacesDescription public List InterfaceMQTT = new List(); [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Interface", Card = AasxPredefinedCardinality.ZeroToMany, - SupplSemId = "http://www.w3.org/2011/opc-ua")] + SupplSemId = "http://opcfoundation.org/UA/WoT-Binding")] public List InterfaceOPCUA = new List(); + [AasConcept(Cd = "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Interface", Card = AasxPredefinedCardinality.ZeroToMany, + SupplSemId = "http://www.w3.org/2022/bacnet")] + public List InterfaceBACNET = new List(); + // auto-generated informations public AasClassMapperInfo __Info__ = null; } -} - +} \ No newline at end of file