From 362cd0851580ba180d20265f04d2d7006ab14375 Mon Sep 17 00:00:00 2001 From: Kazeem Oladipupo <67549739+Kaz040@users.noreply.github.com> Date: Mon, 2 Jun 2025 15:06:36 +0200 Subject: [PATCH 1/8] add bacnet project --- .../AidBacnetConnection.cs | 13 ++++ .../AidInterfaceStatus.cs | 14 +++- .../AssetInterfaceOptions.cs | 1 + .../MappingsAssetInterfacesDescription.cs | 66 +++++++++++++++++++ 4 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs diff --git a/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs b/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs new file mode 100644 index 000000000..d5ec0b65c --- /dev/null +++ b/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs @@ -0,0 +1,13 @@ +using AasxPluginAssetInterfaceDescription; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AasxPluginAssetInterfaceDescription +{ + public class AidBacnetConnection : AidBaseConnection + { + } +} diff --git a/src/AasxPluginAssetInterfaceDesc/AidInterfaceStatus.cs b/src/AasxPluginAssetInterfaceDesc/AidInterfaceStatus.cs index d492efaab..2f200c37b 100644 --- a/src/AasxPluginAssetInterfaceDesc/AidInterfaceStatus.cs +++ b/src/AasxPluginAssetInterfaceDesc/AidInterfaceStatus.cs @@ -29,6 +29,7 @@ This source code may use other Open Source software components (see LICENSE.txt) using System.IO; using Newtonsoft.Json.Linq; using Newtonsoft.Json; +using AasxPluginAssetInterfaceDescription; namespace AasxPluginAssetInterfaceDescription { @@ -97,7 +98,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 { @@ -451,7 +452,7 @@ public class AidAllInterfaceStatus /// /// Current setting, which technologies shall be used. /// - public bool[] UseTech = { false, false, false, true }; + public bool[] UseTech = { false, false, false, true, false }; /// /// Will hold connections steady and continously update values, either by @@ -473,6 +474,9 @@ public class AidAllInterfaceStatus public AidGenericConnections OpcUaConnections = new AidGenericConnections(); + public AidGenericConnections BacnetConnections = + new AidGenericConnections(); + public AidAllInterfaceStatus(LogInstance log = null) { _log = log; @@ -503,6 +507,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; } } @@ -539,6 +544,10 @@ protected AidBaseConnection GetOrCreate( case AidInterfaceTechnology.OPCUA: conn = OpcUaConnections.GetOrCreate(endpointBase, log); break; + + case AidInterfaceTechnology.BACNET: + conn = BacnetConnections.GetOrCreate(endpointBase, log); + break; } conn.UpdateFreqMs = ifcStatus.UpdateFreqMs; @@ -821,6 +830,7 @@ public void PrepareAidInformation(Aas.ISubmodel smAid, Aas.ISubmodel smMapping = if (tech == AidInterfaceTechnology.Modbus) ifxs = dataAid?.InterfaceMODBUS; if (tech == AidInterfaceTechnology.MQTT) ifxs = dataAid?.InterfaceMQTT; if (tech == AidInterfaceTechnology.OPCUA) ifxs = dataAid?.InterfaceOPCUA; + if (tech == AidInterfaceTechnology.BACNET) ifxs = dataAid?.InterfaceBACNET; if (ifxs == null || ifxs.Count < 1) continue; foreach (var ifx in ifxs) diff --git a/src/AasxPluginAssetInterfaceDesc/AssetInterfaceOptions.cs b/src/AasxPluginAssetInterfaceDesc/AssetInterfaceOptions.cs index f9dff1301..2cd204d52 100644 --- a/src/AasxPluginAssetInterfaceDesc/AssetInterfaceOptions.cs +++ b/src/AasxPluginAssetInterfaceDesc/AssetInterfaceOptions.cs @@ -29,6 +29,7 @@ public class AssetInterfaceOptionsRecord : AasxPluginOptionsLookupRecordBase public bool UseModbus = true; public bool UseMqtt = true; public bool UseOpcUa = true; + public bool UseBacnet = true; } public class AssetInterfaceOptions : AasxPluginLookupOptionsBase diff --git a/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs b/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs index b36edc765..7837e85b3 100644 --- a/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs +++ b/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs @@ -371,6 +371,9 @@ 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://www.w3.org/2019/wot/td#hasForm", Card = AasxPredefinedCardinality.One)] public CD_Forms Forms = new CD_Forms(); @@ -476,6 +479,12 @@ public class CD_Forms [AasConcept(Cd = "https://www.w3.org/2019/wot/mqtt#hasQoSFlag", Card = AasxPredefinedCardinality.ZeroToOne)] public string Mqv_qos; + [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; + [AasConcept(Cd = "https://www.w3.org/2019/wot/opc-ua#pollingTime", Card = AasxPredefinedCardinality.ZeroToOne)] public string OpcUa_pollingTime; @@ -502,6 +511,59 @@ 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#hasNamedMember", Card = AasxPredefinedCardinality.ZeroToOne)] + public List bacv_hasNamedMember = new List(); + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasValueMap ", Card = AasxPredefinedCardinality.ZeroToOne)] + public List bacv_hasValueMap = new List(); + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#isIso8601", Card = AasxPredefinedCardinality.ZeroToOne)] + public string 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; + + // auto-generated informations + public AasClassMapperInfo __Info__ = null; + } + + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasNamedMember")] + public class CD_Bacv_hasNamedMember + { + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasDataType", Card = AasxPredefinedCardinality.ZeroToOne)] + public CD_Bacv_hasDataType bacv_hasDataType = null; + + [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.One)] + public string bacv_hasContextTag; + + // auto-generated informations + public AasClassMapperInfo __Info__ = null; + } + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasValueMap")] + 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 string bacv_hasProtocolVal; + + // auto-generated informations + public AasClassMapperInfo __Info__ = null; + } + [AasConcept(Cd = "https://www.w3.org/2019/wot/td#ActionAffordance")] public class CD_Actions { @@ -545,6 +607,10 @@ public class CD_AssetInterfacesDescription SupplSemId = "http://www.w3.org/2011/opc-ua")] 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; } From 4237f7a41bd9763af84ff55345d5eab0358bf2df Mon Sep 17 00:00:00 2001 From: PratikTarpara Date: Mon, 2 Jun 2025 17:22:40 +0200 Subject: [PATCH 2/8] Add Bacnet logo --- .../AasxPluginAssetInterfaceDesc.csproj | 2 ++ .../Resources/logo-bacnet.png | Bin 0 -> 31735 bytes 2 files changed, 2 insertions(+) create mode 100644 src/AasxPluginAssetInterfaceDesc/Resources/logo-bacnet.png diff --git a/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.csproj b/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.csproj index 6166ed62c..0f71db403 100644 --- a/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.csproj +++ b/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.csproj @@ -15,6 +15,7 @@ + @@ -33,6 +34,7 @@ + diff --git a/src/AasxPluginAssetInterfaceDesc/Resources/logo-bacnet.png b/src/AasxPluginAssetInterfaceDesc/Resources/logo-bacnet.png new file mode 100644 index 0000000000000000000000000000000000000000..dff86fc9aedcee92f5c1a526a1bc64545d6d8b3a GIT binary patch literal 31735 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 E1{}(K6aWAK literal 0 HcmV?d00001 From af60787898e2613bc2802186a0b410d346d0e2ae Mon Sep 17 00:00:00 2001 From: PratikTarpara Date: Mon, 2 Jun 2025 18:05:15 +0200 Subject: [PATCH 3/8] Update BACnet logo --- .../Resources/logo-bacnet.png | Bin 31735 -> 5712 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/AasxPluginAssetInterfaceDesc/Resources/logo-bacnet.png b/src/AasxPluginAssetInterfaceDesc/Resources/logo-bacnet.png index dff86fc9aedcee92f5c1a526a1bc64545d6d8b3a..7a59b61c1afc5e7eb6a13b6b6c7905545c899bb9 100644 GIT binary patch literal 5712 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 E1{}(K6aWAK From 89703aca6dc7f3dacf6e8297b32ade915d211c81 Mon Sep 17 00:00:00 2001 From: PratikTarpara Date: Tue, 3 Jun 2025 10:36:31 +0200 Subject: [PATCH 4/8] Edit MappingAssetInterfacesDescription --- .../AssetInterfaceAnyUiControl.cs | 4 ++++ .../MappingsAssetInterfacesDescription.cs | 21 +++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/AasxPluginAssetInterfaceDesc/AssetInterfaceAnyUiControl.cs b/src/AasxPluginAssetInterfaceDesc/AssetInterfaceAnyUiControl.cs index a9678dc28..e1442f9e9 100644 --- a/src/AasxPluginAssetInterfaceDesc/AssetInterfaceAnyUiControl.cs +++ b/src/AasxPluginAssetInterfaceDesc/AssetInterfaceAnyUiControl.cs @@ -125,6 +125,10 @@ public void Start( AnyUiGdiHelper.CreateAnyUiBitmapFromResource( "AasxPluginAssetInterfaceDesc.Resources.logo-opc-ua.png", assembly: Assembly.GetExecutingAssembly())); + _dictTechnologyToBitmap.Add(AidInterfaceTechnology.BACNET, + AnyUiGdiHelper.CreateAnyUiBitmapFromResource( + "AasxPluginAssetInterfaceDesc.Resources.logo-bacnet.png", + assembly: Assembly.GetExecutingAssembly())); } // fill given panel diff --git a/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs b/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs index 7837e85b3..62df64c55 100644 --- a/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs +++ b/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs @@ -514,12 +514,6 @@ public class CD_Htv_headers [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasDataType")] public class CD_Bacv_hasDataType { - [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasNamedMember", Card = AasxPredefinedCardinality.ZeroToOne)] - public List bacv_hasNamedMember = new List(); - - [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasValueMap ", Card = AasxPredefinedCardinality.ZeroToOne)] - public List bacv_hasValueMap = new List(); - [AasConcept(Cd = "http://www.w3.org/2022/bacnet#isIso8601", Card = AasxPredefinedCardinality.ZeroToOne)] public string bacv_isISO8601; @@ -529,23 +523,28 @@ public class CD_Bacv_hasDataType [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 = new List(); + + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasValueMap ", Card = AasxPredefinedCardinality.ZeroToOne)] + public List bacv_hasValueMap = new List(); + // auto-generated informations public AasClassMapperInfo __Info__ = null; } - [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasNamedMember")] public class CD_Bacv_hasNamedMember { - [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasDataType", Card = AasxPredefinedCardinality.ZeroToOne)] - public CD_Bacv_hasDataType bacv_hasDataType = null; - [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.One)] + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasContextTag", Card = AasxPredefinedCardinality.ZeroToOne)] public string 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; } From 8141e808c4a90c0e76e52ffc76b767a6c14280ca Mon Sep 17 00:00:00 2001 From: PratikTarpara Date: Fri, 6 Jun 2025 00:32:16 +0200 Subject: [PATCH 5/8] Changes --- .../AasxPluginAssetInterfaceDesc.csproj | 1 + .../AidBacnetConnection.cs | 25 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.csproj b/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.csproj index 0f71db403..02599e40f 100644 --- a/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.csproj +++ b/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.csproj @@ -44,6 +44,7 @@ + diff --git a/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs b/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs index d5ec0b65c..b2ea82aa6 100644 --- a/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs +++ b/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs @@ -4,10 +4,33 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using AasxPredefinedConcepts; +using Aas = AasCore.Aas3_0; +using AdminShellNS; +using Extensions; +using AasxIntegrationBase; +using AasxPredefinedConcepts.AssetInterfacesDescription; +using FluentModbus; +using System.Net; +using System.Text.RegularExpressions; +using System.Globalization; +using System.Net.Http; +using AdminShellNS.DiaryData; +using AasxIntegrationBase.AdminShellEvents; +using System.Drawing; +using MQTTnet; +using MQTTnet.Client; +using System.Web.Services.Description; +using AasxOpcUa2Client; +using System.IO.BACnet; +using System.Threading; +using System.Diagnostics; namespace AasxPluginAssetInterfaceDescription { public class AidBacnetConnection : AidBaseConnection { - } + + } } + \ No newline at end of file From 0c94ec2efa108ba60548aee0f8be855f29c12f3f Mon Sep 17 00:00:00 2001 From: PratikTarpara Date: Sun, 8 Jun 2025 17:14:19 +0200 Subject: [PATCH 6/8] Update BACnet Plugin --- .../AidBacnetConnection.cs | 87 ++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs b/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs index b2ea82aa6..a727d328f 100644 --- a/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs +++ b/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs @@ -30,7 +30,92 @@ namespace AasxPluginAssetInterfaceDescription { public class AidBacnetConnection : AidBaseConnection { + public BacnetClient Client; - } + override public async Task Open() + { + try + { + // Simple initialization + Client = new BacnetClient(); + + // Parse device ID from URI (bacnet://1234) + //string deviceIdStr = TargetUri.Host; + //if (!uint.TryParse(deviceIdStr, out DeviceId)) + // return false; + + // Set timeout if specified + if (TimeOutMs >= 10) + Client.Timeout = (int)TimeOutMs; + + // Start the client + Client.Start(); + + Client.OnIam += new BacnetClient.IamHandler(handler_OnIam); + + Client.WhoIs(); + Thread.Sleep(1000); // Allow time for responses + + Console.WriteLine("Devices discovered:"); + lock (DevicesList) + { + foreach (var device in DevicesList) + { + Console.WriteLine($"Device ID: {device.device_id}, Address: {device.adr}"); + } + } + + await Task.Yield(); + return true; + } + catch + { + Client = null; + return false; + } + } + + override public bool IsConnected() + { + // nothing to do, this simple http connection is stateless + return Client != null; + } + + override public void Close() + { + // nothing to do, this simple http connection is stateless + } + + override public async Task UpdateItemValueAsync(AidIfxItemStatus item) + { + // access + if (item?.FormData?.Href?.HasContent() != true + || item.FormData.Modv_function?.HasContent() != true + || !IsConnected()) + return 0; + int res = 0; + + // Decode address and value + var match = Regex.Match(item.FormData.Href, @"^(\d+)(\?value=(\d+))?$"); + if (!match.Success) + return 0; + if (!uint.TryParse(match.Groups[1].ToString(), out var address)) + return 0; + if (match.Groups[3].Success && !uint.TryParse(match.Groups[3].ToString(), out var value)) + return 0; + // Perform the write operation + try + { + Client.WriteProperty(address, BacnetPropertyIds.PROP_PRESENT_VALUE, value); + res = 1; // Success + } + catch (Exception ex) + { + Debug.WriteLine($"Bacnet write error: {ex.Message}"); + res = -1; // Error + } + await Task.Yield(); + return res; + } } \ No newline at end of file From 4761fcd996324eb8b4debfb05c7e9d98abc9398a Mon Sep 17 00:00:00 2001 From: PratikTarpara Date: Tue, 10 Jun 2025 09:30:39 +0200 Subject: [PATCH 7/8] Bacnet Implemntation Chnages --- .../AasxPluginAssetInterfaceDesc.options.json | 3 +- .../AidBacnetConnection.cs | 79 ++++++++++++------- .../AidInterfaceStatus.cs | 32 ++++---- .../AssetInterfaceAnyUiControl.cs | 26 +++--- .../AssetInterfaceOptions.cs | 4 +- .../MappingsAssetInterfacesDescription.cs | 30 +++---- 6 files changed, 100 insertions(+), 74 deletions(-) diff --git a/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.options.json b/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.options.json index 15734b7b6..1d653b268 100644 --- a/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.options.json +++ b/src/AasxPluginAssetInterfaceDesc/AasxPluginAssetInterfaceDesc.options.json @@ -12,7 +12,8 @@ "UseHttp": false, "UseModbus": false, "UseMqtt": false, - "UseOpcUa": true + "UseOpcUa": true, + "UseBacnet": true }, { "IsDescription": false, diff --git a/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs b/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs index a727d328f..c98dbf85a 100644 --- a/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs +++ b/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs @@ -31,7 +31,20 @@ namespace AasxPluginAssetInterfaceDescription public class AidBacnetConnection : AidBaseConnection { public BacnetClient Client; + static List DevicesList = new List(); + static void handler_OnIam(BacnetClient sender, BacnetAddress adr, uint device_id, uint max_apdu, BacnetSegmentations segmentation, ushort vendor_id) + { + lock (DevicesList) + { + // Device already registered? + foreach (BacNode bn in DevicesList) + if (bn.getAdd(device_id) != null) return; // Yes + + // Not already in the list + DevicesList.Add(new BacNode(adr, device_id)); // Add it + } // Closing brace added here + } // Closing brace added here override public async Task Open() { try @@ -42,7 +55,7 @@ override public async Task Open() // Parse device ID from URI (bacnet://1234) //string deviceIdStr = TargetUri.Host; //if (!uint.TryParse(deviceIdStr, out DeviceId)) - // return false; + //return false; // Set timeout if specified if (TimeOutMs >= 10) @@ -86,36 +99,48 @@ override public void Close() // nothing to do, this simple http connection is stateless } - override public async Task UpdateItemValueAsync(AidIfxItemStatus item) - { - // access - if (item?.FormData?.Href?.HasContent() != true - || item.FormData.Modv_function?.HasContent() != true - || !IsConnected()) - return 0; - int res = 0; - - // Decode address and value - var match = Regex.Match(item.FormData.Href, @"^(\d+)(\?value=(\d+))?$"); - if (!match.Success) - return 0; - if (!uint.TryParse(match.Groups[1].ToString(), out var address)) - return 0; - if (match.Groups[3].Success && !uint.TryParse(match.Groups[3].ToString(), out var value)) - return 0; - // Perform the write operation + override public int UpdateItemValue(AidIfxItemStatus item) + { try { - Client.WriteProperty(address, BacnetPropertyIds.PROP_PRESENT_VALUE, value); - res = 1; // Success + // Example logic to update item value + if (item != null && !string.IsNullOrEmpty(item.Location)) + { + // Simulate updating the value + item.Value = "UpdatedValue"; + return 0; // Return success code + } + else + { + return -1; // Return error code for invalid item + } } catch (Exception ex) { - Debug.WriteLine($"Bacnet write error: {ex.Message}"); - res = -1; // Error + // Log the exception if necessary + Console.WriteLine($"Error updating item value: {ex.Message}"); + return -2; // Return error code for exception + } + } + + public class BacNode + { + public BacnetAddress adr; + public uint device_id; + + public BacNode(BacnetAddress adr, uint device_id) + { + this.adr = adr; + this.device_id = device_id; + } + + public BacnetAddress getAdd(uint device_id) + { + if (this.device_id == device_id) + return adr; + else + return null; } - await Task.Yield(); - return res; } -} - \ No newline at end of file + } +} \ No newline at end of file diff --git a/src/AasxPluginAssetInterfaceDesc/AidInterfaceStatus.cs b/src/AasxPluginAssetInterfaceDesc/AidInterfaceStatus.cs index 2f200c37b..b4f6e687b 100644 --- a/src/AasxPluginAssetInterfaceDesc/AidInterfaceStatus.cs +++ b/src/AasxPluginAssetInterfaceDesc/AidInterfaceStatus.cs @@ -29,7 +29,6 @@ This source code may use other Open Source software components (see LICENSE.txt) using System.IO; using Newtonsoft.Json.Linq; using Newtonsoft.Json; -using AasxPluginAssetInterfaceDescription; namespace AasxPluginAssetInterfaceDescription { @@ -121,7 +120,7 @@ public class AidInterfaceStatus /// /// The information items (properties, actions, events) /// - public MultiValueDictionary Items = + public MultiValueDictionary Items = new MultiValueDictionary(); /// @@ -202,7 +201,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; @@ -220,7 +219,7 @@ public void AddItem(AidIfxItemStatus item) // compute key var key = ComputeKey(item?.FormData?.Href); - + // now add Items.Add(key, item); } @@ -402,7 +401,7 @@ public void NotifyOutputItems(AidIfxItemStatus item, string strval) } } - + } } } @@ -452,7 +451,7 @@ public class AidAllInterfaceStatus /// /// Current setting, which technologies shall be used. /// - public bool[] UseTech = { false, false, false, true, false }; + public bool[] UseTech = { false, false, false, true, true }; /// /// Will hold connections steady and continously update values, either by @@ -465,7 +464,7 @@ public class AidAllInterfaceStatus public AidGenericConnections HttpConnections = new AidGenericConnections(); - public AidGenericConnections ModbusConnections = + public AidGenericConnections ModbusConnections = new AidGenericConnections(); public AidGenericConnections MqttConnections = @@ -548,6 +547,7 @@ protected AidBaseConnection GetOrCreate( case AidInterfaceTechnology.BACNET: conn = BacnetConnections.GetOrCreate(endpointBase, log); break; + } conn.UpdateFreqMs = ifcStatus.UpdateFreqMs; @@ -771,17 +771,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)); + }); } } } @@ -863,7 +863,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(); @@ -884,7 +884,7 @@ public void PrepareAidInformation(Aas.ISubmodel smAid, Aas.ISubmodel smMapping = aidIfx.AddItem(ifcItem); ifcItem.MapOutputItems = lst; } - + // directly recurse? if (propName?.Properties?.Property != null) @@ -894,7 +894,7 @@ public void PrepareAidInformation(Aas.ISubmodel smAid, Aas.ISubmodel smMapping = child.Forms = propName.Forms; recurseProp(location + " . " + ifcItem.DisplayName, child); } - + }; if (ifx.InteractionMetadata?.Properties?.Property == null) diff --git a/src/AasxPluginAssetInterfaceDesc/AssetInterfaceAnyUiControl.cs b/src/AasxPluginAssetInterfaceDesc/AssetInterfaceAnyUiControl.cs index e1442f9e9..ac3de740d 100644 --- a/src/AasxPluginAssetInterfaceDesc/AssetInterfaceAnyUiControl.cs +++ b/src/AasxPluginAssetInterfaceDesc/AssetInterfaceAnyUiControl.cs @@ -46,7 +46,7 @@ public class AssetInterfaceAnyUiControl protected AnyUiSmallWidgetToolkit _uitk = new AnyUiSmallWidgetToolkit(); - protected Dictionary _dictTechnologyToBitmap = + protected Dictionary _dictTechnologyToBitmap = new Dictionary(); private System.Timers.Timer _dispatcherTimer = null; @@ -287,13 +287,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], @@ -306,7 +306,7 @@ protected void RenderPanelInner( // uitk.AddSmallLabelTo(grid, 1, 0, content: "Startup:"); - + AnyUiUIElement.RegisterControl( uitk.AddSmallButtonTo(grid, 1, 1, margin: new AnyUiThickness(2), setHeight: 21, @@ -327,7 +327,7 @@ protected void RenderPanelInner( _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 @@ -349,7 +349,7 @@ protected void RenderPanelInner( setValueAsync: async (o) => { try - { + { // locked? if (_allInterfaceStatus?.ContinousRun == true) { @@ -455,7 +455,7 @@ public void Update(params object[] args) #region Interface items //===================== - + protected void RenderTripleRowData( AnyUiStackPanel view, AnyUiSmallWidgetToolkit uitk, List interfaces) @@ -465,7 +465,7 @@ protected void RenderTripleRowData( return; // 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) @@ -483,7 +483,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]); @@ -507,13 +507,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() { @@ -538,7 +538,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); diff --git a/src/AasxPluginAssetInterfaceDesc/AssetInterfaceOptions.cs b/src/AasxPluginAssetInterfaceDesc/AssetInterfaceOptions.cs index 2cd204d52..425f5698a 100644 --- a/src/AasxPluginAssetInterfaceDesc/AssetInterfaceOptions.cs +++ b/src/AasxPluginAssetInterfaceDesc/AssetInterfaceOptions.cs @@ -45,8 +45,8 @@ public static AssetInterfaceOptions CreateDefault() var rec1 = new AssetInterfaceOptionsRecord(); rec1.IsDescription = true; - rec1.AllowSubmodelSemanticId = new[] { - new Aas.Key(Aas.KeyTypes.Submodel, + rec1.AllowSubmodelSemanticId = new[] { + new Aas.Key(Aas.KeyTypes.Submodel, "https://admin-shell.io/idta/AssetInterfacesDescription/1/0/Submodel") }.ToList(); var rec2 = new AssetInterfaceOptionsRecord(); diff --git a/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs b/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs index 62df64c55..d88ce3dfa 100644 --- a/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs +++ b/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs @@ -479,18 +479,18 @@ public class CD_Forms [AasConcept(Cd = "https://www.w3.org/2019/wot/mqtt#hasQoSFlag", Card = AasxPredefinedCardinality.ZeroToOne)] public string Mqv_qos; - [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; - [AasConcept(Cd = "https://www.w3.org/2019/wot/opc-ua#pollingTime", Card = AasxPredefinedCardinality.ZeroToOne)] public string OpcUa_pollingTime; [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; } @@ -515,7 +515,7 @@ public class CD_Htv_headers public class CD_Bacv_hasDataType { [AasConcept(Cd = "http://www.w3.org/2022/bacnet#isIso8601", Card = AasxPredefinedCardinality.ZeroToOne)] - public string bacv_isISO8601; + public bool? bacv_isISO8601; [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasBinaryRepresentation", Card = AasxPredefinedCardinality.ZeroToOne)] public string bacv_hasBinaryRepresentation; @@ -524,23 +524,23 @@ public class CD_Bacv_hasDataType public CD_Bacv_hasDataType bacv_hasMember = null; [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasNamedMember", Card = AasxPredefinedCardinality.ZeroToOne)] - public List bacv_hasNamedMember = new List(); + public List bacv_hasNamedMember = null; - [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasValueMap ", Card = AasxPredefinedCardinality.ZeroToOne)] - public List bacv_hasValueMap = new List(); + [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#hasNamedMember")] + [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 string bacv_hasContextTag; + public bool? bacv_hasContextTag; [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasDataType", Card = AasxPredefinedCardinality.ZeroToOne)] public CD_Bacv_hasDataType bacv_hasDataType = null; @@ -549,7 +549,7 @@ public class CD_Bacv_hasNamedMember public AasClassMapperInfo __Info__ = null; } - [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasValueMap")] + [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasMapEntry")] public class CD_Bacv_hasValueMap { @@ -557,7 +557,7 @@ public class CD_Bacv_hasValueMap public string bacv_hasLogicalVal; [AasConcept(Cd = "http://www.w3.org/2022/bacnet#hasProtocolVal", Card = AasxPredefinedCardinality.One)] - public string bacv_hasProtocolVal; + public int bacv_hasProtocolVal; // auto-generated informations public AasClassMapperInfo __Info__ = null; @@ -607,7 +607,7 @@ public class CD_AssetInterfacesDescription 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")] + SupplSemId = "http://www.w3.org/2022/bacnet")] public List InterfaceBACNET = new List(); // auto-generated informations From 41047de4f3a003bf6c62b3ba828590ae446f9f99 Mon Sep 17 00:00:00 2001 From: PratikTarpara Date: Wed, 11 Jun 2025 15:25:13 +0200 Subject: [PATCH 8/8] Bacnet Working Implimentation --- .../AidBacnetConnection.cs | 192 +++++++++--------- .../MappingsAssetInterfacesDescription.cs | 2 +- 2 files changed, 100 insertions(+), 94 deletions(-) diff --git a/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs b/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs index c98dbf85a..4e8449554 100644 --- a/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs +++ b/src/AasxPluginAssetInterfaceDesc/AidBacnetConnection.cs @@ -1,146 +1,152 @@ -using AasxPluginAssetInterfaceDescription; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using AasxIntegrationBase; +using AasxIntegrationBase.AdminShellEvents; +using AasxPluginAssetInterfaceDescription; using AasxPredefinedConcepts; -using Aas = AasCore.Aas3_0; +using AasxPredefinedConcepts.AssetInterfacesDescription; using AdminShellNS; +using AdminShellNS.DiaryData; using Extensions; -using AasxIntegrationBase; -using AasxPredefinedConcepts.AssetInterfacesDescription; using FluentModbus; -using System.Net; -using System.Text.RegularExpressions; -using System.Globalization; -using System.Net.Http; -using AdminShellNS.DiaryData; -using AasxIntegrationBase.AdminShellEvents; +using System; +using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; -using MQTTnet; -using MQTTnet.Client; -using System.Web.Services.Description; -using AasxOpcUa2Client; +using System.Globalization; using System.IO.BACnet; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Text.RegularExpressions; using System.Threading; -using System.Diagnostics; +using System.Threading.Tasks; +using System.Web.Services.Description; +using Aas = AasCore.Aas3_0; namespace AasxPluginAssetInterfaceDescription { public class AidBacnetConnection : AidBaseConnection { public BacnetClient Client; - static List DevicesList = new List(); - - static void handler_OnIam(BacnetClient sender, BacnetAddress adr, uint device_id, uint max_apdu, BacnetSegmentations segmentation, ushort vendor_id) - { - lock (DevicesList) - { - // Device already registered? - foreach (BacNode bn in DevicesList) - if (bn.getAdd(device_id) != null) return; // Yes - - // Not already in the list - DevicesList.Add(new BacNode(adr, device_id)); // Add it - } // Closing brace added here - } // Closing brace added here + private Dictionary DeviceAddresses = new Dictionary(); override public async Task Open() { try { - // Simple initialization Client = new BacnetClient(); + Client.OnIam += OnIamHandler; - // Parse device ID from URI (bacnet://1234) - //string deviceIdStr = TargetUri.Host; - //if (!uint.TryParse(deviceIdStr, out DeviceId)) - //return false; - - // Set timeout if specified if (TimeOutMs >= 10) + { Client.Timeout = (int)TimeOutMs; + } - // Start the client Client.Start(); - - Client.OnIam += new BacnetClient.IamHandler(handler_OnIam); - - Client.WhoIs(); - Thread.Sleep(1000); // Allow time for responses - - Console.WriteLine("Devices discovered:"); - lock (DevicesList) - { - foreach (var device in DevicesList) - { - Console.WriteLine($"Device ID: {device.device_id}, Address: {device.adr}"); - } - } - + LastActive = DateTime.Now; + await Task.Yield(); return true; } - catch + catch (Exception ex) { 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() { - // nothing to do, this simple http connection is stateless + // nothing to do, this simple bacnet connection is stateless return Client != null; } override public void Close() { - // nothing to do, this simple http connection is stateless + // Dispose client + if (Client != null) + { + Client.Dispose(); + Client = null; + } } - override public int UpdateItemValue(AidIfxItemStatus item) + override public async Task UpdateItemValueAsync(AidIfxItemStatus item) { - try + // access + if (item?.FormData?.Href?.HasContent() != true + || item.FormData.Bacv_useService?.HasContent() != true + || !IsConnected()) + return 0; + int res = 0; + + // GET? + if (item.FormData.Bacv_useService.Trim().ToLower() == "readproperty") { - // Example logic to update item value - if (item != null && !string.IsNullOrEmpty(item.Location)) + try { - // Simulate updating the value - item.Value = "UpdatedValue"; - return 0; // Return success code + // Extract device ID + uint deviceId = uint.Parse(TargetUri.Host); + + // Find device address + BacnetAddress deviceAddress; + if (!DeviceAddresses.ContainsKey(deviceId)) + { + // Perform WhoIs request + Client.WhoIs((int)deviceId, (int)deviceId); + await Task.Delay(1000); // Wait for response + } + + if (!DeviceAddresses.TryGetValue(deviceId, out deviceAddress)) + { + throw new Exception($"Device {deviceId} not found."); + } + + + // get object type,instance, and property + var href = item.FormData.Href.TrimStart('/'); + string[] mainParts = href.Split('/'); + string[] objectParts = mainParts[0].Split(','); + + // Create objectId + var objectType = (BacnetObjectTypes)int.Parse(objectParts[0]); + uint instance = uint.Parse(objectParts[1]); + BacnetObjectId objectId = new BacnetObjectId(objectType, instance); + + // Get property from href + var propertyId = (BacnetPropertyIds)int.Parse(mainParts[1]); + + // Read Property + IList values; + bool result = Client.ReadPropertyRequest( + deviceAddress, + objectId, + propertyId, + out values + ); + + if (result) + { + var value = values[0].Value.ToString(); + item.Value = value; + res = 1; + NotifyOutputItems(item, value); + } } - else + catch (Exception ex) { - return -1; // Return error code for invalid item + // set breakpoint in order to get failed connections! } } - catch (Exception ex) - { - // Log the exception if necessary - Console.WriteLine($"Error updating item value: {ex.Message}"); - return -2; // Return error code for exception - } - } - public class BacNode - { - public BacnetAddress adr; - public uint device_id; + return res; + } - public BacNode(BacnetAddress adr, uint device_id) - { - this.adr = adr; - this.device_id = device_id; - } - public BacnetAddress getAdd(uint device_id) - { - if (this.device_id == device_id) - return adr; - else - return null; - } - } } } \ No newline at end of file diff --git a/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs b/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs index d88ce3dfa..a1c4e0868 100644 --- a/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs +++ b/src/AasxPredefinedConcepts/Mappings/MappingsAssetInterfacesDescription.cs @@ -607,7 +607,7 @@ public class CD_AssetInterfacesDescription 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")] + SupplSemId = "http://www.w3.org/2022/bacnet")] public List InterfaceBACNET = new List(); // auto-generated informations