diff --git a/MTConnect.NET.sln b/MTConnect.NET.sln index 450946b3..08e55d65 100644 --- a/MTConnect.NET.sln +++ b/MTConnect.NET.sln @@ -108,7 +108,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MTConnect.NET-Client-MQTT", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MTConnect.NET-Client-SHDR", "examples\MTConnect.NET-Client-SHDR\MTConnect.NET-Client-SHDR.csproj", "{A9DF36FC-4EF7-4BFB-B47D-F1C10227631A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MTConnect.NET-Agent-Embedded", "examples\MTConnect.NET-Agent-Embedded\MTConnect.NET-Agent-Embedded.csproj", "{24C98CF3-CC93-4696-A036-8FD1E16F2E7E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MTConnect.NET-Agent-Embedded", "examples\MTConnect.NET-Agent-Embedded\MTConnect.NET-Agent-Embedded.csproj", "{24C98CF3-CC93-4696-A036-8FD1E16F2E7E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/agent/MTConnect.NET-Agent/agent.config.yaml b/agent/MTConnect.NET-Agent/agent.config.yaml index fbb3007b..298c73f4 100644 --- a/agent/MTConnect.NET-Agent/agent.config.yaml +++ b/agent/MTConnect.NET-Agent/agent.config.yaml @@ -81,23 +81,23 @@ modules: # privateKeyPath: c:\test-cert\trakhound.key # privateKeyPassword: trakhound -# - mqtt-relay: # - Add MQTT Relay module (Document Structure) -# server: localhost -# port: 1883 -# currentInterval: 10000 -# sampleInterval: 500 -# documentFormat: JSON-CPPAGENT -# topicPrefix: MTConnect/Document -# topicStructure: Document - -- mqtt-relay: # - Add MQTT Relay module (Entity Structure) +- mqtt-relay: # - Add MQTT Relay module (Document Structure) server: localhost port: 1883 currentInterval: 10000 sampleInterval: 500 - documentFormat: JSON - topicPrefix: MTConnect/Entity - topicStructure: Entity + documentFormat: JSON-CPPAGENT-MQTT + topicPrefix: MTConnect/Document + topicStructure: Document + +# - mqtt-relay: # - Add MQTT Relay module (Entity Structure) +# server: localhost +# port: 1883 +# currentInterval: 10000 +# sampleInterval: 500 +# documentFormat: JSON +# topicPrefix: MTConnect/Entity +# topicStructure: Entity # - mqtt-relay: # - Add MQTT Relay module (TLS) # server: localhost diff --git a/build/AssemblyInfo.cs b/build/AssemblyInfo.cs index c0e501d1..b2ba11b0 100644 --- a/build/AssemblyInfo.cs +++ b/build/AssemblyInfo.cs @@ -1,6 +1,6 @@ using System.Reflection; -[assembly: AssemblyVersion("6.2.2")] -[assembly: AssemblyFileVersion("6.2.2")] +[assembly: AssemblyVersion("6.3.0")] +[assembly: AssemblyFileVersion("6.3.0")] [assembly: AssemblyCompany("TrakHound Inc.")] [assembly: AssemblyCopyright("Copyright (c) 2024 TrakHound Inc., All Rights Reserved.")] diff --git a/examples/MTConnect.NET-Agent-Embedded/MTConnect.NET-Agent-Embedded.csproj b/examples/MTConnect.NET-Agent-Embedded/MTConnect.NET-Agent-Embedded.csproj index 972be305..79e5c6f0 100644 --- a/examples/MTConnect.NET-Agent-Embedded/MTConnect.NET-Agent-Embedded.csproj +++ b/examples/MTConnect.NET-Agent-Embedded/MTConnect.NET-Agent-Embedded.csproj @@ -5,7 +5,6 @@ net8.0 MTConnect.NET_Agent_Embedded enable - enable diff --git a/examples/MTConnect.NET-Agent-Embedded/Program.cs b/examples/MTConnect.NET-Agent-Embedded/Program.cs index 7a18df53..53aef55e 100644 --- a/examples/MTConnect.NET-Agent-Embedded/Program.cs +++ b/examples/MTConnect.NET-Agent-Embedded/Program.cs @@ -18,6 +18,7 @@ public class ModuleConfiguration { public string DeviceUuid { get; set; } public string DeviceName { get; set; } + public string SerialNumber { get; set; } } @@ -46,12 +47,14 @@ public Module(IMTConnectAgentBroker agent, object configuration) : base(agent) protected override IDevice OnAddDevice() { var device = new Device(); - device.Uuid = "7E647B2D-C6A3-40BF-9CE9-FB09834850C9"; - device.Id = "dev-001"; + device.Uuid = _configuration.DeviceUuid; + device.Id = _configuration.DeviceName; + device.Name = _configuration.DeviceName; device.Description = new Description() { Manufacturer = "ACME", - Model = "dm-500" + Model = "dm-500", + SerialNumber = _configuration.SerialNumber }; // Add an Availability DataItem to the Device diff --git a/examples/MTConnect.NET-Agent-Embedded/agent.config.yaml b/examples/MTConnect.NET-Agent-Embedded/agent.config.yaml index d36e92fa..fc9959d8 100644 --- a/examples/MTConnect.NET-Agent-Embedded/agent.config.yaml +++ b/examples/MTConnect.NET-Agent-Embedded/agent.config.yaml @@ -1,6 +1,9 @@ modules: - demo: + deviceUuid: 7E647B2D-C6A3-40BF-9CE9-FB09834850C9 + deviceName: dev-001 + serialNumber: 123456 readInterval: 1000 - http-server: diff --git a/examples/MTConnect.NET-Client-HTTP/Program.cs b/examples/MTConnect.NET-Client-HTTP/Program.cs index 8b0ece42..af67f8dc 100644 --- a/examples/MTConnect.NET-Client-HTTP/Program.cs +++ b/examples/MTConnect.NET-Client-HTTP/Program.cs @@ -17,7 +17,9 @@ static void Main(string[] args) static void DocumentClient() { //var client = new MTConnectHttpClient("http://mtconnect.mazakcorp.com/", 5719); - var client = new MTConnectHttpClient("localhost", 5000); + //var client = new MTConnectHttpClient("localhost", 5006, "OKUMA-Lathe"); + //var client = new MTConnectHttpClient("localhost", 5006); + var client = new MTConnectHttpClient("localhost", 5000, "Okuma-Lathe"); //var client = new MTConnectHttpClient("localhost", 5001); client.Interval = 100; //client.Heartbeat = 0; @@ -40,8 +42,8 @@ static void DocumentClient() { Console.WriteLine($"Observation Received : {observation.DataItemId} : {string.Join(";", observation.Values.Select(o => o.Value))}"); - var validationResult = observation.Validate(); - Console.WriteLine($"Observation Validation : {observation.DataItemId} : {validationResult.IsValid} : {validationResult.Message}"); + //var validationResult = observation.Validate(); + //Console.WriteLine($"Observation Validation : {observation.DataItemId} : {validationResult.IsValid} : {validationResult.Message}"); } } } @@ -57,8 +59,8 @@ static void DocumentClient() { Console.WriteLine($"Observation Received : {observation.DataItemId} : {string.Join(";", observation.Values.Select(o => o.Value))}"); - var validationResult = observation.Validate(); - Console.WriteLine($"Observation Validation : {observation.DataItemId} : {validationResult.IsValid} : {validationResult.Message}"); + //var validationResult = observation.Validate(); + //Console.WriteLine($"Observation Validation : {observation.DataItemId} : {validationResult.IsValid} : {validationResult.Message}"); } } } @@ -72,7 +74,8 @@ static void DocumentClient() } }; - client.Start(); + client.StartFromBuffer(); + //client.Start(); } static void EntityClient() diff --git a/examples/MTConnect.NET-Client-MQTT/Program.cs b/examples/MTConnect.NET-Client-MQTT/Program.cs index 21c68bfb..bbfb0db5 100644 --- a/examples/MTConnect.NET-Client-MQTT/Program.cs +++ b/examples/MTConnect.NET-Client-MQTT/Program.cs @@ -1,4 +1,6 @@ -using MTConnect.Formatters; +using MTConnect.Configurations; +using MTConnect.Formatters; +using MTConnect.Observations; namespace MTConnect.Clients.HTTP { @@ -14,53 +16,60 @@ static void Main(string[] args) static void DocumentClient() { - var client = new MTConnectMqttClient("localhost", 1883); + var config = new MTConnectMqttClientConfiguration(); + config.Server = "localhost"; + config.Port = 1883; + config.TopicPrefix = "MTConnect/Document"; + + var client = new MTConnectMqttClient(config); client.ClientStarted += (s, args) => { Console.WriteLine("Client Started"); }; client.ClientStopped += (s, args) => { Console.WriteLine("Client Stopped"); }; //client.MessageReceived += (topic, payload) => Console.WriteLine($"Message Received : {topic} : {payload.Length}"); + client.DeviceReceived += (topic, device) => Console.WriteLine($"Device Received : {device.Uuid} : {device.Name}"); + client.ObservationReceived += (topic, observation) => Console.WriteLine($"Observation Received : {observation.DataItemId} : {string.Join(";", observation.Values.Select(o => o.Value))}"); - client.ProbeReceived += (s, response) => - { - foreach (var device in response.Devices) Console.WriteLine($"Device Received : {device.Uuid} : {device.Name}"); - }; + //client.ProbeReceived += (s, response) => + //{ + // foreach (var device in response.Devices) Console.WriteLine($"Device Received : {device.Uuid} : {device.Name}"); + //}; - client.CurrentReceived += (s, response) => - { - foreach (var stream in response.Streams) - { - foreach (var componentStream in stream.ComponentStreams) - { - foreach (var observation in componentStream.Observations) - { - Console.WriteLine($"Observation Received : {observation.DataItemId} : {string.Join(";", observation.Values.Select(o => o.Value))}"); - } - } - } - }; + //client.CurrentReceived += (s, response) => + //{ + // foreach (var stream in response.Streams) + // { + // foreach (var componentStream in stream.ComponentStreams) + // { + // foreach (var observation in componentStream.Observations) + // { + // Console.WriteLine($"Observation Received : {observation.DataItemId} : {string.Join(";", observation.Values.Select(o => o.Value))}"); + // } + // } + // } + //}; - client.SampleReceived += (s, response) => - { - foreach (var stream in response.Streams) - { - foreach (var componentStream in stream.ComponentStreams) - { - foreach (var observation in componentStream.Observations) - { - Console.WriteLine($"Observation Received : {observation.DataItemId} : {string.Join(";", observation.Values.Select(o => o.Value))}"); - } - } - } - }; + //client.SampleReceived += (s, response) => + //{ + // foreach (var stream in response.Streams) + // { + // foreach (var componentStream in stream.ComponentStreams) + // { + // foreach (var observation in componentStream.Observations) + // { + // Console.WriteLine($"Observation Received : {observation.DataItemId} : {string.Join(";", observation.Values.Select(o => o.Value))}"); + // } + // } + // } + //}; - client.AssetsReceived += (s, response) => - { - foreach (var asset in response.Assets) - { - var result = EntityFormatter.Format("XML", asset); - //if (result.Success) Console.WriteLine(System.Text.Encoding.UTF8.GetString(result.Content)); - } - }; + //client.AssetsReceived += (s, response) => + //{ + // foreach (var asset in response.Assets) + // { + // var result = EntityFormatter.Format("XML", asset); + // //if (result.Success) Console.WriteLine(System.Text.Encoding.UTF8.GetString(result.Content)); + // } + //}; client.Start(); } diff --git a/libraries/MTConnect.NET-Common/Adapters/IMTConnectAdapter.cs b/libraries/MTConnect.NET-Common/Adapters/IMTConnectAdapter.cs index 262bbd3c..f64f3eff 100644 --- a/libraries/MTConnect.NET-Common/Adapters/IMTConnectAdapter.cs +++ b/libraries/MTConnect.NET-Common/Adapters/IMTConnectAdapter.cs @@ -60,6 +60,8 @@ public interface IMTConnectAdapter /// bool SendLast(long timestamp = 0); + bool SendBuffer(); + /// /// Set all items to Unavailable diff --git a/libraries/MTConnect.NET-Common/Agents/IMTConnectAgentBroker.cs b/libraries/MTConnect.NET-Common/Agents/IMTConnectAgentBroker.cs index bef6bbe5..bd2bb3db 100644 --- a/libraries/MTConnect.NET-Common/Agents/IMTConnectAgentBroker.cs +++ b/libraries/MTConnect.NET-Common/Agents/IMTConnectAgentBroker.cs @@ -129,6 +129,15 @@ public interface IMTConnectAgentBroker : IMTConnectAgent /// MTConnectStreams Response Document IStreamsResponseOutputDocument GetDeviceStreamsResponseDocument(ulong at, uint count = 0, Version mtconnectVersion = null, string deviceType = null); + /// + /// Get a MTConnectStreams Document containing all devices. + /// + /// A list of DataItemId's to specify what observations to include in the response + /// The maximum number of observations to include in the response + /// MTConnectStreams Response Document + IStreamsResponseOutputDocument GetDeviceStreamsResponseDocument(IEnumerable dataItemIds, uint count = 0, Version mtconnectVersion = null, string deviceType = null); + + /// /// Get a MTConnectStreams Document containing all devices. /// diff --git a/libraries/MTConnect.NET-Common/Agents/MTConnectAgent.cs b/libraries/MTConnect.NET-Common/Agents/MTConnectAgent.cs index b4e991cd..fe37a0f8 100644 --- a/libraries/MTConnect.NET-Common/Agents/MTConnectAgent.cs +++ b/libraries/MTConnect.NET-Common/Agents/MTConnectAgent.cs @@ -43,8 +43,6 @@ public class MTConnectAgent : IMTConnectAgent, IDisposable private readonly ConcurrentDictionary _currentObservations = new ConcurrentDictionary(); private readonly ConcurrentDictionary> _currentConditions = new ConcurrentDictionary>(); - //private readonly ConcurrentDictionary _currentObservations = new ConcurrentDictionary(); - //private readonly ConcurrentDictionary> _currentConditions = new ConcurrentDictionary>(); private readonly List _assetIds = new List(); private MTConnectAgentMetrics _metrics; private readonly string _uuid; diff --git a/libraries/MTConnect.NET-Common/Agents/MTConnectAgentBroker.cs b/libraries/MTConnect.NET-Common/Agents/MTConnectAgentBroker.cs index a0c47d22..66bea397 100644 --- a/libraries/MTConnect.NET-Common/Agents/MTConnectAgentBroker.cs +++ b/libraries/MTConnect.NET-Common/Agents/MTConnectAgentBroker.cs @@ -608,7 +608,7 @@ public IDevicesResponseDocument GetDevicesResponseDocument(string deviceKey, Ver #region "Internal" - private IObservationBufferResults GetObservations(IEnumerable bufferKeys, ulong from = 0, ulong to = 0, ulong at = 0, uint count = 0) + private IObservationBufferResults GetObservations(IEnumerable bufferKeys, ulong from = 0, ulong to = 0, ulong? at = null, uint count = 0) { IObservationBufferResults results; if (from > 0 || to > 0) @@ -619,9 +619,9 @@ private IObservationBufferResults GetObservations(IEnumerable bufferKeys, u { results = _observationBuffer.GetObservations(bufferKeys, count: count); } - else if (at > 0) + else if (at.HasValue) { - results = _observationBuffer.GetCurrentObservations(bufferKeys, at); + results = _observationBuffer.GetCurrentObservations(bufferKeys, at.Value); } else { @@ -701,6 +701,45 @@ public IStreamsResponseOutputDocument GetDeviceStreamsResponseDocument(ulong at, return null; } + /// + /// Get a MTConnectStreams Document containing all devices. + /// + /// A list of DataItemId's to specify what observations to include in the response + /// The maximum number of observations to include in the response + /// MTConnectStreams Response Document + public IStreamsResponseOutputDocument GetDeviceStreamsResponseDocument(IEnumerable dataItemIds, uint count = 0, Version mtconnectVersion = null, string deviceType = null) + { + StreamsRequestReceived?.Invoke(null); + + if (_observationBuffer != null) + { + var devices = GetDevices(deviceType); + if (!devices.IsNullOrEmpty()) + { + // Create list of BufferKeys + var bufferKeys = new List(); + foreach (var device in devices) + { + var deviceBufferKeys = GenerateBufferKeys(device.Uuid, dataItemIds); + if (!deviceBufferKeys.IsNullOrEmpty()) bufferKeys.AddRange(deviceBufferKeys); + } + + // Query the Observation Buffer + var results = GetObservations(bufferKeys, count: count); + + // Create Response Document + var document = CreateDeviceStreamsDocument(devices, ref results, mtconnectVersion); + if (document != null) + { + StreamsResponseSent?.Invoke(this, new EventArgs()); + return document; + } + } + } + + return null; + } + /// /// Get a MTConnectStreams Document containing all devices. /// diff --git a/libraries/MTConnect.NET-Common/Buffers/MTConnectObservationBuffer.cs b/libraries/MTConnect.NET-Common/Buffers/MTConnectObservationBuffer.cs index 134aefdb..e362f654 100644 --- a/libraries/MTConnect.NET-Common/Buffers/MTConnectObservationBuffer.cs +++ b/libraries/MTConnect.NET-Common/Buffers/MTConnectObservationBuffer.cs @@ -390,12 +390,14 @@ public IObservationBufferResults GetCurrentObservations(IEnumerable bufferK lock (_lock) { - firstSequence = Math.Max(1, _sequence - BufferSize); + firstSequence = _sequence > BufferSize ? _sequence - BufferSize : 1; lastSequence = _sequence > 1 ? _sequence - 1 : 1; nextSequence = _sequence; // Determine Indexes - var atIndex = (int)(at - firstSequence); + int atIndex; + if (at < 1) atIndex = 0; + else atIndex = (int)(at - firstSequence); if (_archiveObservations.Size > 0) { @@ -420,13 +422,21 @@ public IObservationBufferResults GetCurrentObservations(IEnumerable bufferK // Get From Current Observations if (_currentObservations.TryGetValue(oBufferKeys[i], out var observation)) { - observations[i] = observation; + if (observation.IsValid) + { + if (at < 1 && observation.Sequence <= firstSequence) observations[i] = observation; + else if (observation.Sequence <= at) observations[i] = observation; + } } // Get From Current Observations if (_currentConditions.TryGetValue(oBufferKeys[i], out var conditions)) { - observations[i] = observation; + if (observation.IsValid) + { + if (at < 1 && observation.Sequence <= firstSequence) observations[i] = observation; + else if (observation.Sequence <= at) observations[i] = observation; + } } } } @@ -483,7 +493,6 @@ public IObservationBufferResults GetObservations(IEnumerable bufferKeys, ul nextSequence = _sequence; // Determine Indexes - //var fromIndex = (int)Math.Max(0, from - firstSequence); int fromIndex = from > firstSequence ? (int)(from - firstSequence) : 0; int toIndex = (int)(lastSequence - firstSequence); if (to > 0) diff --git a/libraries/MTConnect.NET-Common/Devices/Component.cs b/libraries/MTConnect.NET-Common/Devices/Component.cs index 38484b45..d28ae027 100644 --- a/libraries/MTConnect.NET-Common/Devices/Component.cs +++ b/libraries/MTConnect.NET-Common/Devices/Component.cs @@ -53,8 +53,13 @@ private struct IdFormatConfiguration /// public IContainer Parent { get; set; } + /// + /// The Agent InstanceId that produced this Device + /// + public ulong InstanceId { get; set; } - private string _hash; + + private string _hash; /// /// Condensed message digest from a secure one-way hash function. FIPS PUB 180-4 /// @@ -1461,12 +1466,14 @@ public static bool IsCompatible(IComponent component, Version mtconnectVersion) return false; } - public static IComponent Process(IComponent component, Version mtconnectVersion) + public static Component Process(IComponent component, Version mtconnectVersion = null) { if (component != null) { + var version = mtconnectVersion != null ? mtconnectVersion : MTConnectVersions.Max; + // Check Version Compatibilty - if (component.MinimumVersion != null && mtconnectVersion < component.MinimumVersion) return null; + if (component.MinimumVersion != null && version < component.MinimumVersion) return null; // Create a new Instance of the Component that will instantiate a new Derived class (if found) var obj = Create(component.Type); @@ -1482,18 +1489,18 @@ public static IComponent Process(IComponent component, Version mtconnectVersion) { var description = new Description(); description.Manufacturer = component.Description.Manufacturer; - if (mtconnectVersion >= MTConnectVersions.Version12) description.Model = component.Description.Model; + if (version >= MTConnectVersions.Version12) description.Model = component.Description.Model; description.SerialNumber = component.Description.SerialNumber; description.Station = component.Description.Station; description.Value = component.Description.Value; obj.Description = description; } - if (mtconnectVersion < MTConnectVersions.Version12) obj.SampleRate = component.SampleRate; - if (mtconnectVersion >= MTConnectVersions.Version12) obj.SampleInterval = component.SampleInterval; - if (mtconnectVersion >= MTConnectVersions.Version13) obj.References = component.References; - if (mtconnectVersion >= MTConnectVersions.Version17) obj.Configuration = component.Configuration; - if (mtconnectVersion >= MTConnectVersions.Version18) obj.CoordinateSystemIdRef = component.CoordinateSystemIdRef; + if (version < MTConnectVersions.Version12) obj.SampleRate = component.SampleRate; + if (version >= MTConnectVersions.Version12) obj.SampleInterval = component.SampleInterval; + if (version >= MTConnectVersions.Version13) obj.References = component.References; + if (version >= MTConnectVersions.Version17) obj.Configuration = component.Configuration; + if (version >= MTConnectVersions.Version18) obj.CoordinateSystemIdRef = component.CoordinateSystemIdRef; // Add DataItems if (!component.DataItems.IsNullOrEmpty()) @@ -1502,7 +1509,7 @@ public static IComponent Process(IComponent component, Version mtconnectVersion) foreach (var dataItem in component.DataItems) { - var dataItemObj = DataItem.Process(dataItem, mtconnectVersion); + var dataItemObj = DataItem.Process(dataItem, version); if (dataItemObj != null) dataItems.Add(dataItemObj); } @@ -1516,7 +1523,7 @@ public static IComponent Process(IComponent component, Version mtconnectVersion) foreach (var composition in component.Compositions) { - var compositionObj = Composition.Process(composition, mtconnectVersion); + var compositionObj = Composition.Process(composition, version); if (compositionObj != null) compositions.Add(compositionObj); } @@ -1530,7 +1537,7 @@ public static IComponent Process(IComponent component, Version mtconnectVersion) foreach (var subcomponent in component.Components) { - var subcomponentObj = Process(subcomponent, mtconnectVersion); + var subcomponentObj = Process(subcomponent, version); if (subcomponentObj != null) subcomponents.Add(subcomponentObj); } diff --git a/libraries/MTConnect.NET-Common/Devices/Composition.cs b/libraries/MTConnect.NET-Common/Devices/Composition.cs index edb38e66..962845f7 100644 --- a/libraries/MTConnect.NET-Common/Devices/Composition.cs +++ b/libraries/MTConnect.NET-Common/Devices/Composition.cs @@ -43,11 +43,16 @@ public string Hash } } + /// + /// The Agent InstanceId that produced this Device + /// + public ulong InstanceId { get; set; } - /// - /// The text description that describes what the Composition Type represents - /// - public virtual string TypeDescription => DescriptionText; + + /// + /// The text description that describes what the Composition Type represents + /// + public virtual string TypeDescription => DescriptionText; /// @@ -338,12 +343,14 @@ private static Dictionary GetAllTypes() } - public static IComposition Process(IComposition composition, Version mtconnectVersion) + public static Composition Process(IComposition composition, Version mtconnectVersion = null) { if (composition != null) { + var version = mtconnectVersion != null ? mtconnectVersion : MTConnectVersions.Max; + // Check Version Compatibilty - if (composition.MinimumVersion != null && mtconnectVersion < composition.MinimumVersion) return null; + if (composition.MinimumVersion != null && version < composition.MinimumVersion) return null; // Create a new Instance of the Composition that will instantiate a new Derived class (if found) var obj = Create(composition.Type); @@ -359,18 +366,18 @@ public static IComposition Process(IComposition composition, Version mtconnectVe { var description = new Description(); description.Manufacturer = composition.Description.Manufacturer; - if (mtconnectVersion >= MTConnectVersions.Version12) description.Model = composition.Description.Model; + if (version >= MTConnectVersions.Version12) description.Model = composition.Description.Model; description.SerialNumber = composition.Description.SerialNumber; description.Station = composition.Description.Station; description.Value = composition.Description.Value; obj.Description = description; } - if (mtconnectVersion < MTConnectVersions.Version12) obj.SampleRate = composition.SampleRate; - if (mtconnectVersion >= MTConnectVersions.Version12) obj.SampleInterval = composition.SampleInterval; - if (mtconnectVersion >= MTConnectVersions.Version13) obj.References = composition.References; - if (mtconnectVersion >= MTConnectVersions.Version17) obj.Configuration = composition.Configuration; - if (mtconnectVersion >= MTConnectVersions.Version18) obj.CoordinateSystemIdRef = composition.CoordinateSystemIdRef; + if (version < MTConnectVersions.Version12) obj.SampleRate = composition.SampleRate; + if (version >= MTConnectVersions.Version12) obj.SampleInterval = composition.SampleInterval; + if (version >= MTConnectVersions.Version13) obj.References = composition.References; + if (version >= MTConnectVersions.Version17) obj.Configuration = composition.Configuration; + if (version >= MTConnectVersions.Version18) obj.CoordinateSystemIdRef = composition.CoordinateSystemIdRef; // Add DataItems if (!composition.DataItems.IsNullOrEmpty()) @@ -379,7 +386,7 @@ public static IComposition Process(IComposition composition, Version mtconnectVe foreach (var dataItem in composition.DataItems) { - var dataItemObj = DataItem.Process(dataItem, mtconnectVersion); + var dataItemObj = DataItem.Process(dataItem, version); if (dataItemObj != null) dataItems.Add(dataItemObj); } diff --git a/libraries/MTConnect.NET-Common/Devices/DataItem.cs b/libraries/MTConnect.NET-Common/Devices/DataItem.cs index 82176f11..b61211da 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItem.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItem.cs @@ -58,8 +58,13 @@ public string Uuid /// public IContainer Container { get; set; } + /// + /// The Agent InstanceId that produced this Device + /// + public ulong InstanceId { get; set; } + - private string _hash; + private string _hash; /// /// Condensed message digest from a secure one-way hash function. FIPS PUB 180-4 /// @@ -258,12 +263,12 @@ public static string GenerateTypePath(IDataItem dataItem) } - public IDataItem Process(Version mtconnectVersion) + public DataItem Process(Version mtconnectVersion) { return Process(this, mtconnectVersion); } - protected virtual IDataItem OnProcess(IDataItem dataItem, Version mtconnectVersion) + protected virtual DataItem OnProcess(DataItem dataItem, Version mtconnectVersion) { return dataItem; } @@ -484,12 +489,12 @@ public static string GetPascalCaseType(string type) switch (type) { - case Devices.DataItems.AdapterUriDataItem.TypeId: return "AdapterURI"; - case Devices.DataItems.MTConnectVersionDataItem.TypeId: return "MTConnectVersion"; - case Devices.DataItems.AmperageACDataItem.TypeId: return "AmperageAC"; - case Devices.DataItems.AmperageDCDataItem.TypeId: return "AmperageDC"; - case Devices.DataItems.VoltageACDataItem.TypeId: return "VoltageAC"; - case Devices.DataItems.VoltageDCDataItem.TypeId: return "VoltageDC"; + case AdapterUriDataItem.TypeId: return "AdapterURI"; + case MTConnectVersionDataItem.TypeId: return "MTConnectVersion"; + case AmperageACDataItem.TypeId: return "AmperageAC"; + case AmperageDCDataItem.TypeId: return "AmperageDC"; + case VoltageACDataItem.TypeId: return "VoltageAC"; + case VoltageDCDataItem.TypeId: return "VoltageDC"; } lock (_lock) @@ -554,25 +559,29 @@ public static DataItem Create(Type type) { if (type != null) { - var constructor = type.GetConstructor(System.Type.EmptyTypes); - if (constructor != null) + try { - try + var constructor = type.GetConstructor(System.Type.EmptyTypes); + if (constructor != null) { + return (DataItem)Activator.CreateInstance(type); } - catch { } } - } + catch { } + } return new DataItem(); } public static IEnumerable GetTypes() { - if (_types == null) _types = GetAllTypes(); + lock (_lock) + { + if (_types == null) _types = GetAllTypes(); - return _types.Keys; + return _types.Keys; + } } public static IEnumerable GetConditionTypes() @@ -718,9 +727,14 @@ public static IEnumerable> GetSubTypeDescriptions() { if (_subtypeDescriptions == null) { - if (_types == null) _types = GetAllTypes(); + bool typesFound; + lock (_lock) + { + if (_types == null) _types = GetAllTypes(); + typesFound = !_types.IsNullOrEmpty(); + } - if (!_types.IsNullOrEmpty()) + if (typesFound) { _subtypeDescriptions = new Dictionary(); @@ -850,19 +864,16 @@ public static Type GetDataItemType(string type) { if (!string.IsNullOrEmpty(type)) { - if (_types == null) _types = GetAllTypes(); - - if (_types != null) + lock (_lock) { - string typeId; - lock (_lock) + // Initialize Type List + if (_types == null) _types = GetAllTypes(); + + _typeIds.TryGetValue(type, out string typeId); + if (typeId == null) { - _typeIds.TryGetValue(type, out typeId); - if (typeId == null) - { - typeId = type.ToPascalCase(); - _typeIds.Add(type, typeId); - } + typeId = type.ToPascalCase(); + _typeIds.Add(type, typeId); } if (_types.TryGetValue(typeId, out Type t)) @@ -1009,27 +1020,29 @@ public static bool IsCompatible(IDataItem dataItem, Version mtconnectVersion) return false; } - public static IDataItem Process(IDataItem dataItem, Version mtconnectVersion) + public static DataItem Process(IDataItem dataItem, Version mtconnectVersion = null) { if (dataItem != null) { + var version = mtconnectVersion != null ? mtconnectVersion : MTConnectVersions.Max; + // Check Version Compatibilty - if (dataItem.MinimumVersion != null && mtconnectVersion < dataItem.MinimumVersion) return null; + if (dataItem.MinimumVersion != null && version < dataItem.MinimumVersion) return null; // Don't return if Condition and Version < 1.1 - if (dataItem.Category == DataItemCategory.CONDITION && mtconnectVersion < MTConnectVersions.Version11) return null; + if (dataItem.Category == DataItemCategory.CONDITION && version < MTConnectVersions.Version11) return null; // Don't return if TimeSeries and Version < 1.2 - if (dataItem.Representation == DataItemRepresentation.TIME_SERIES && mtconnectVersion < MTConnectVersions.Version12) return null; + if (dataItem.Representation == DataItemRepresentation.TIME_SERIES && version < MTConnectVersions.Version12) return null; // Don't return if Discrete and Version < 1.3 OR Version >= 1.5 - if (dataItem.Representation == DataItemRepresentation.DISCRETE && (mtconnectVersion < MTConnectVersions.Version13 || mtconnectVersion >= MTConnectVersions.Version15)) return null; + if (dataItem.Representation == DataItemRepresentation.DISCRETE && (version < MTConnectVersions.Version13 || version >= MTConnectVersions.Version15)) return null; // Don't return if DataSet and Version < 1.3 - if (dataItem.Representation == DataItemRepresentation.DATA_SET && mtconnectVersion < MTConnectVersions.Version13) return null; + if (dataItem.Representation == DataItemRepresentation.DATA_SET && version < MTConnectVersions.Version13) return null; // Don't return if Table and Version < 1.6 - if (dataItem.Representation == DataItemRepresentation.TABLE && mtconnectVersion < MTConnectVersions.Version16) return null; + if (dataItem.Representation == DataItemRepresentation.TABLE && version < MTConnectVersions.Version16) return null; // Create a new Instance of the DataItem that will instantiate a new Derived class (if found) var obj = Create(dataItem.Type); @@ -1048,14 +1061,14 @@ public static IDataItem Process(IDataItem dataItem, Version mtconnectVersion) obj.Device = dataItem.Device; // Check SampleRate - if (mtconnectVersion >= MTConnectVersions.Version12) obj.SampleRate = dataItem.SampleRate; + if (version >= MTConnectVersions.Version12) obj.SampleRate = dataItem.SampleRate; // Check Source - if (dataItem.Source != null && mtconnectVersion >= MTConnectVersions.Version12) + if (dataItem.Source != null && version >= MTConnectVersions.Version12) { var source = new Source(); source.ComponentId = dataItem.Source.ComponentId; - if (mtconnectVersion >= MTConnectVersions.Version14) source.CompositionId = dataItem.Source.CompositionId; + if (version >= MTConnectVersions.Version14) source.CompositionId = dataItem.Source.CompositionId; source.DataItemId = dataItem.Source.DataItemId; if (!string.IsNullOrEmpty(source.ComponentId) || !string.IsNullOrEmpty(source.CompositionId) || !string.IsNullOrEmpty(source.DataItemId)) @@ -1065,7 +1078,7 @@ public static IDataItem Process(IDataItem dataItem, Version mtconnectVersion) } // Check Relationships - if (dataItem.Relationships != null && mtconnectVersion >= MTConnectVersions.Version15) + if (dataItem.Relationships != null && version >= MTConnectVersions.Version15) { var relationships = new List(); foreach (var relationship in dataItem.Relationships) @@ -1079,7 +1092,7 @@ public static IDataItem Process(IDataItem dataItem, Version mtconnectVersion) // DataItem Relationship if (relationship.GetType() == typeof(DataItemRelationship)) { - if (mtconnectVersion >= MTConnectVersions.Version17) relationships.Add(relationship); + if (version >= MTConnectVersions.Version17) relationships.Add(relationship); } // Device Relationship @@ -1091,7 +1104,7 @@ public static IDataItem Process(IDataItem dataItem, Version mtconnectVersion) // Specification Relationship if (relationship.GetType() == typeof(SpecificationRelationship)) { - if (mtconnectVersion >= MTConnectVersions.Version17) relationships.Add(relationship); + if (version >= MTConnectVersions.Version17) relationships.Add(relationship); } } @@ -1099,19 +1112,19 @@ public static IDataItem Process(IDataItem dataItem, Version mtconnectVersion) } // Check Representation - if (mtconnectVersion >= MTConnectVersions.Version12) obj.Representation = dataItem.Representation; + if (version >= MTConnectVersions.Version12) obj.Representation = dataItem.Representation; // Check ResetTrigger - if (mtconnectVersion >= MTConnectVersions.Version14) obj.ResetTrigger = dataItem.ResetTrigger; + if (version >= MTConnectVersions.Version14) obj.ResetTrigger = dataItem.ResetTrigger; // Check CoordinateSystem - if (mtconnectVersion < MTConnectVersions.Version20) obj.CoordinateSystem = dataItem.CoordinateSystem; + if (version < MTConnectVersions.Version20) obj.CoordinateSystem = dataItem.CoordinateSystem; // Check CoordinateSystemIdRef - if (mtconnectVersion >= MTConnectVersions.Version15) obj.CoordinateSystemIdRef = dataItem.CoordinateSystemIdRef; + if (version >= MTConnectVersions.Version15) obj.CoordinateSystemIdRef = dataItem.CoordinateSystemIdRef; // Check CompositionId - if (mtconnectVersion >= MTConnectVersions.Version14) + if (version >= MTConnectVersions.Version14) { obj.CompositionId = dataItem.CompositionId; } @@ -1122,26 +1135,26 @@ public static IDataItem Process(IDataItem dataItem, Version mtconnectVersion) } // Check Constraints - if (mtconnectVersion >= MTConnectVersions.Version11) obj.Constraints = dataItem.Constraints; + if (version >= MTConnectVersions.Version11) obj.Constraints = dataItem.Constraints; // Check Definition - if (mtconnectVersion >= MTConnectVersions.Version16) obj.Definition = dataItem.Definition; + if (version >= MTConnectVersions.Version16) obj.Definition = dataItem.Definition; // Check Statistic - if (mtconnectVersion >= MTConnectVersions.Version12) obj.Statistic = dataItem.Statistic; + if (version >= MTConnectVersions.Version12) obj.Statistic = dataItem.Statistic; // Check Filters - if (mtconnectVersion >= MTConnectVersions.Version13) obj.Filters = dataItem.Filters; + if (version >= MTConnectVersions.Version13) obj.Filters = dataItem.Filters; // Check InitialValue - if (mtconnectVersion >= MTConnectVersions.Version14) obj.InitialValue = dataItem.InitialValue; + if (version >= MTConnectVersions.Version14) obj.InitialValue = dataItem.InitialValue; // Check Discrete - if (mtconnectVersion >= MTConnectVersions.Version15) obj.Discrete = dataItem.Discrete; + if (version >= MTConnectVersions.Version15) obj.Discrete = dataItem.Discrete; } // Call overridable method (used to process based on Type) - return obj.OnProcess(obj, mtconnectVersion); + return obj.OnProcess(obj, version); } return null; diff --git a/libraries/MTConnect.NET-Common/Devices/Device.cs b/libraries/MTConnect.NET-Common/Devices/Device.cs index df126f08..56c28b38 100644 --- a/libraries/MTConnect.NET-Common/Devices/Device.cs +++ b/libraries/MTConnect.NET-Common/Devices/Device.cs @@ -996,17 +996,19 @@ public void RemoveDataItem(string dataItemId) #endregion - public static Device Process(IDevice device, Version mtconnectVersion) + public static Device Process(IDevice device, Version mtconnectVersion = null) { if (device != null) { + var version = mtconnectVersion != null ? mtconnectVersion : MTConnectVersions.Max; + Device obj = null; if (device.Type == TypeId) obj = new Device(); else if (device.Type == Agent.TypeId) obj = new Agent(); // Don't Ouput Agent Device if Version < 1.7 - if (device.Type == Agent.TypeId && mtconnectVersion < MTConnectVersions.Version17) return null; + if (device.Type == Agent.TypeId && version < MTConnectVersions.Version17) return null; if (obj != null) { @@ -1023,21 +1025,21 @@ public static Device Process(IDevice device, Version mtconnectVersion) { var description = new Description(); description.Manufacturer = device.Description.Manufacturer; - if (mtconnectVersion >= MTConnectVersions.Version12) description.Model = device.Description.Model; + if (version >= MTConnectVersions.Version12) description.Model = device.Description.Model; description.SerialNumber = device.Description.SerialNumber; description.Station = device.Description.Station; description.Value = device.Description.Value; obj.Description = description; } - if (mtconnectVersion < MTConnectVersions.Version12) obj.Iso841Class = device.Iso841Class; - if (mtconnectVersion < MTConnectVersions.Version12) obj.SampleRate = device.SampleRate; - if (mtconnectVersion >= MTConnectVersions.Version12) obj.SampleInterval = device.SampleInterval; - if (mtconnectVersion >= MTConnectVersions.Version13) obj.References = device.References; - if (mtconnectVersion >= MTConnectVersions.Version17) obj.Configuration = device.Configuration; - if (mtconnectVersion >= MTConnectVersions.Version18) obj.CoordinateSystemIdRef = device.CoordinateSystemIdRef; - if (mtconnectVersion >= MTConnectVersions.Version17) obj.MTConnectVersion = device.MTConnectVersion != null ? device.MTConnectVersion : mtconnectVersion; - if (mtconnectVersion >= MTConnectVersions.Version22) obj.Hash = device.Hash; + if (version < MTConnectVersions.Version12) obj.Iso841Class = device.Iso841Class; + if (version < MTConnectVersions.Version12) obj.SampleRate = device.SampleRate; + if (version >= MTConnectVersions.Version12) obj.SampleInterval = device.SampleInterval; + if (version >= MTConnectVersions.Version13) obj.References = device.References; + if (version >= MTConnectVersions.Version17) obj.Configuration = device.Configuration; + if (version >= MTConnectVersions.Version18) obj.CoordinateSystemIdRef = device.CoordinateSystemIdRef; + if (version >= MTConnectVersions.Version17) obj.MTConnectVersion = device.MTConnectVersion != null ? device.MTConnectVersion : version; + if (version >= MTConnectVersions.Version22) obj.Hash = device.Hash; // Add DataItems if (!device.DataItems.IsNullOrEmpty()) @@ -1046,7 +1048,7 @@ public static Device Process(IDevice device, Version mtconnectVersion) foreach (var dataItem in device.DataItems) { - var dataItemObj = DataItem.Process(dataItem, mtconnectVersion); + var dataItemObj = DataItem.Process(dataItem, version); if (dataItemObj != null) dataItems.Add(dataItemObj); } @@ -1060,7 +1062,7 @@ public static Device Process(IDevice device, Version mtconnectVersion) foreach (var composition in device.Compositions) { - var compositionObj = Composition.Process(composition, mtconnectVersion); + var compositionObj = Composition.Process(composition, version); if (compositionObj != null) compositions.Add(compositionObj); } @@ -1074,7 +1076,7 @@ public static Device Process(IDevice device, Version mtconnectVersion) foreach (var component in device.Components) { - var componentObj = Component.Process(component, mtconnectVersion); + var componentObj = Component.Process(component, version); if (componentObj != null) components.Add(componentObj); } diff --git a/libraries/MTConnect.NET-Common/Devices/IContainer.cs b/libraries/MTConnect.NET-Common/Devices/IContainer.cs index 42dc5bd0..02dcfff2 100644 --- a/libraries/MTConnect.NET-Common/Devices/IContainer.cs +++ b/libraries/MTConnect.NET-Common/Devices/IContainer.cs @@ -18,11 +18,15 @@ public partial interface IContainer : IMTConnectEntity /// IContainer Parent { get; set; } + /// + /// The Agent InstanceId that produced this Device + /// + ulong InstanceId { get; } - /// - /// Condensed message digest from a secure one-way hash function. FIPS PUB 180-4 - /// - string Hash { get; } + /// + /// Condensed message digest from a secure one-way hash function. FIPS PUB 180-4 + /// + string Hash { get; } /// /// diff --git a/libraries/MTConnect.NET-Common/Devices/IDataItem.cs b/libraries/MTConnect.NET-Common/Devices/IDataItem.cs index 1d068e87..3487df16 100644 --- a/libraries/MTConnect.NET-Common/Devices/IDataItem.cs +++ b/libraries/MTConnect.NET-Common/Devices/IDataItem.cs @@ -20,11 +20,16 @@ public partial interface IDataItem : IMTConnectEntity /// IContainer Container { get; } + /// + /// The Agent InstanceId that produced this Device + /// + ulong InstanceId { get; } - /// - /// Condensed message digest from a secure one-way hash function. FIPS PUB 180-4 - /// - string Hash { get; } + + /// + /// Condensed message digest from a secure one-way hash function. FIPS PUB 180-4 + /// + string Hash { get; } /// diff --git a/libraries/MTConnect.NET-Common/Devices/IDevice.cs b/libraries/MTConnect.NET-Common/Devices/IDevice.cs index 98ddf388..0a272e27 100644 --- a/libraries/MTConnect.NET-Common/Devices/IDevice.cs +++ b/libraries/MTConnect.NET-Common/Devices/IDevice.cs @@ -5,11 +5,6 @@ namespace MTConnect.Devices { public partial interface IDevice : IComponent, IContainer { - /// - /// The Agent InstanceId that produced this Device - /// - ulong InstanceId { get; } - /// /// DEPRECATED IN REL. 1.1 /// diff --git a/libraries/MTConnect.NET-Common/Observations/ConditionObservation.cs b/libraries/MTConnect.NET-Common/Observations/ConditionObservation.cs index 949b3096..d93b7cdd 100644 --- a/libraries/MTConnect.NET-Common/Observations/ConditionObservation.cs +++ b/libraries/MTConnect.NET-Common/Observations/ConditionObservation.cs @@ -140,35 +140,39 @@ public static ConditionObservation Create(string type, DataItemRepresentation re { if (!string.IsNullOrEmpty(type)) { - if (_types == null) _types = GetAllTypes(); - - if (!_types.IsNullOrEmpty()) + Type dataItemType = null; + lock (_typeLock) { - var key = string.Intern(type + ":" + (int)representation); + // Initialize Type List + if (_types == null) _types = GetAllTypes(); - // Lookup Type ID (Type as PascalCase) - _typeIds.TryGetValue(key, out var typeId); - if (typeId == null) + if (!_types.IsNullOrEmpty()) { - typeId = $"{type.ToPascalCase()}{representation.ToString().ToPascalCase()}"; - _typeIds.Add(key, typeId); + var key = string.Intern(type + ":" + (int)representation); + + // Lookup Type ID (Type as PascalCase) + _typeIds.TryGetValue(key, out string typeId); + if (typeId == null) + { + typeId = $"{type.ToPascalCase()}{representation.ToString().ToPascalCase()}"; + _typeIds.Add(key, typeId); + } + + _types.TryGetValue(key, out dataItemType); } + } - if (_types.TryGetValue(key, out Type t)) + if (dataItemType != null) + { + try { - var constructor = t.GetConstructor(System.Type.EmptyTypes); - if (constructor != null) + var constructor = dataItemType.GetConstructor(System.Type.EmptyTypes); + if (constructor != null && representation == DataItemRepresentation.VALUE) { - try - { - switch (representation) - { - case DataItemRepresentation.VALUE: return (ConditionObservation)Activator.CreateInstance(t); - } - } - catch { } + return (ConditionObservation)Activator.CreateInstance(dataItemType); } } + catch { } } } diff --git a/libraries/MTConnect.NET-Common/Observations/EventObservation.cs b/libraries/MTConnect.NET-Common/Observations/EventObservation.cs index 0495cb5f..c5be3525 100644 --- a/libraries/MTConnect.NET-Common/Observations/EventObservation.cs +++ b/libraries/MTConnect.NET-Common/Observations/EventObservation.cs @@ -79,37 +79,44 @@ public static EventObservation Create(string type, DataItemRepresentation repres { if (!string.IsNullOrEmpty(type)) { - if (_types == null) _types = GetAllTypes(); - - if (!_types.IsNullOrEmpty()) + Type dataItemType = null; + lock (_typeLock) { - var key = string.Intern(type + ":" + (int)representation); + // Initialize Type List + if (_types == null) _types = GetAllTypes(); - // Lookup Type ID (Type as PascalCase) - _typeIds.TryGetValue(key, out var typeId); - if (typeId == null) + if (!_types.IsNullOrEmpty()) { - typeId = $"{type.ToPascalCase()}{representation.ToString().ToPascalCase()}"; - _typeIds.Add(key, typeId); + var key = string.Intern(type + ":" + (int)representation); + + // Lookup Type ID (Type as PascalCase) + _typeIds.TryGetValue(key, out string typeId); + if (typeId == null) + { + typeId = $"{type.ToPascalCase()}{representation.ToString().ToPascalCase()}"; + _typeIds.Add(key, typeId); + } + + _types.TryGetValue(key, out dataItemType); } + } - if (_types.TryGetValue(key, out Type t)) + if (dataItemType != null) + { + try { - var constructor = t.GetConstructor(System.Type.EmptyTypes); + var constructor = dataItemType.GetConstructor(System.Type.EmptyTypes); if (constructor != null) { - try + switch (representation) { - switch (representation) - { - case DataItemRepresentation.VALUE: return (EventValueObservation)Activator.CreateInstance(t); - case DataItemRepresentation.DATA_SET: return (EventDataSetObservation)Activator.CreateInstance(t); - case DataItemRepresentation.TABLE: return (EventTableObservation)Activator.CreateInstance(t); - } + case DataItemRepresentation.VALUE: return (EventValueObservation)Activator.CreateInstance(dataItemType); + case DataItemRepresentation.DATA_SET: return (EventDataSetObservation)Activator.CreateInstance(dataItemType); + case DataItemRepresentation.TABLE: return (EventTableObservation)Activator.CreateInstance(dataItemType); } - catch { } } } + catch { } } } diff --git a/libraries/MTConnect.NET-Common/Observations/Observation.cs b/libraries/MTConnect.NET-Common/Observations/Observation.cs index cf3b6303..2566750d 100644 --- a/libraries/MTConnect.NET-Common/Observations/Observation.cs +++ b/libraries/MTConnect.NET-Common/Observations/Observation.cs @@ -24,11 +24,12 @@ public class Observation : IObservation private const string UppercaseValuePattern = "^[a-zA-Z_]*$"; private static readonly Regex _uppercaseValueRegex = new Regex(UppercaseValuePattern); - protected static readonly Dictionary _typeIds = new Dictionary(); + protected static readonly Dictionary _typeIds = new Dictionary(); protected static Dictionary _types; + protected static readonly object _typeLock = new object(); - private readonly object _lock = new object(); + protected readonly object _valueLock = new object(); protected readonly Dictionary _values = new Dictionary(); @@ -224,7 +225,7 @@ public string GetValue(string valueKey) try { ObservationValue value; - lock (_lock) _values.TryGetValue(valueKey, out value); + lock (_valueLock) _values.TryGetValue(valueKey, out value); return value.Value; } catch { } @@ -258,7 +259,7 @@ public void AddValue(ObservationValue observationValue) { try { - lock (_lock) + lock (_valueLock) { _values.Remove(observationValue.Key); _values.Add(observationValue.Key, observationValue); diff --git a/libraries/MTConnect.NET-Common/Observations/SampleObservation.cs b/libraries/MTConnect.NET-Common/Observations/SampleObservation.cs index 6551cb15..132cb1c7 100644 --- a/libraries/MTConnect.NET-Common/Observations/SampleObservation.cs +++ b/libraries/MTConnect.NET-Common/Observations/SampleObservation.cs @@ -127,8 +127,10 @@ public static SampleObservation Create(IObservation observation) public static SampleObservation Create(string type, DataItemRepresentation representation) { - if (!string.IsNullOrEmpty(type)) + Type dataItemType = null; + lock (_typeLock) { + // Initialize Type List if (_types == null) _types = GetAllTypes(); if (!_types.IsNullOrEmpty()) @@ -136,32 +138,34 @@ public static SampleObservation Create(string type, DataItemRepresentation repre var key = string.Intern(type + ":" + (int)representation); // Lookup Type ID (Type as PascalCase) - _typeIds.TryGetValue(key, out var typeId); + _typeIds.TryGetValue(key, out string typeId); if (typeId == null) { typeId = $"{type.ToPascalCase()}{representation.ToString().ToPascalCase()}"; _typeIds.Add(key, typeId); } - if (_types.TryGetValue(typeId, out Type t)) + _types.TryGetValue(key, out dataItemType); + } + } + + if (dataItemType != null) + { + try + { + var constructor = dataItemType.GetConstructor(System.Type.EmptyTypes); + if (constructor != null) { - var constructor = t.GetConstructor(System.Type.EmptyTypes); - if (constructor != null) + switch (representation) { - try - { - switch (representation) - { - case DataItemRepresentation.VALUE: return (SampleValueObservation)Activator.CreateInstance(t); - case DataItemRepresentation.DATA_SET: return (SampleDataSetObservation)Activator.CreateInstance(t); - case DataItemRepresentation.TABLE: return (SampleTableObservation)Activator.CreateInstance(t); - case DataItemRepresentation.TIME_SERIES: return (SampleTimeSeriesObservation)Activator.CreateInstance(t); - } - } - catch { } + case DataItemRepresentation.VALUE: return (SampleValueObservation)Activator.CreateInstance(dataItemType); + case DataItemRepresentation.DATA_SET: return (SampleDataSetObservation)Activator.CreateInstance(dataItemType); + case DataItemRepresentation.TABLE: return (SampleTableObservation)Activator.CreateInstance(dataItemType); + case DataItemRepresentation.TIME_SERIES: return (SampleTimeSeriesObservation)Activator.CreateInstance(dataItemType); } } } + catch { } } switch (representation) diff --git a/libraries/MTConnect.NET-Common/Streams/ComponentStream.cs b/libraries/MTConnect.NET-Common/Streams/ComponentStream.cs index 04d7754e..8884491c 100644 --- a/libraries/MTConnect.NET-Common/Streams/ComponentStream.cs +++ b/libraries/MTConnect.NET-Common/Streams/ComponentStream.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. using MTConnect.Devices; @@ -9,7 +9,7 @@ namespace MTConnect.Streams { /// - /// ComponentStream is a XML container that organizes the data associated with each Structural Element defined for that piece of equipment in the associated MTConnectDevices XML document + /// Organizes the data associated with each Component entity defined for a Device in the associated MTConnectDevices Response Document. /// public class ComponentStream : IComponentStream { diff --git a/libraries/MTConnect.NET-Common/Streams/DeviceStream.cs b/libraries/MTConnect.NET-Common/Streams/DeviceStream.cs index 1f089157..ab22af5e 100644 --- a/libraries/MTConnect.NET-Common/Streams/DeviceStream.cs +++ b/libraries/MTConnect.NET-Common/Streams/DeviceStream.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. using MTConnect.Observations; @@ -7,22 +7,22 @@ namespace MTConnect.Streams { /// - /// DeviceStream is a XML container that organizes data reported from a single piece of equipment.A DeviceStream element MUST be provided for each piece of equipment reporting data in an MTConnectStreams document. + /// Organizes data reported from a Device. /// public class DeviceStream : IDeviceStream { /// - /// The name of an element or a piece of equipment. The name associated with the piece of equipment reporting the data contained in this DeviceStream container. + /// Name of the Device. /// public string Name { get; set; } /// - /// The uuid associated with the piece of equipment reporting the data contained in this DeviceStream container. + /// Uuid of the Device. /// public string Uuid { get; set; } /// - /// An XML container type element that organizes data returned from an Agent in response to a current or sample HTTP request. + /// Organizes the data associated with each Component entity defined for a Device in the associated MTConnectDevices Response Document. /// public IEnumerable ComponentStreams { get; set; } diff --git a/libraries/MTConnect.NET-Common/Streams/IComponentStream.cs b/libraries/MTConnect.NET-Common/Streams/IComponentStream.cs index 832fd792..a1555336 100644 --- a/libraries/MTConnect.NET-Common/Streams/IComponentStream.cs +++ b/libraries/MTConnect.NET-Common/Streams/IComponentStream.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. using MTConnect.Devices; @@ -8,7 +8,7 @@ namespace MTConnect.Streams { /// - /// ComponentStream is a XML container that organizes the data associated with each Structural Element defined for that piece of equipment in the associated MTConnectDevices XML document + /// Organizes the data associated with each Component entity defined for a Device in the associated MTConnectDevices Response Document. /// public interface IComponentStream { diff --git a/libraries/MTConnect.NET-Common/Streams/IDeviceStream.cs b/libraries/MTConnect.NET-Common/Streams/IDeviceStream.cs index 6d74ff53..697e01e9 100644 --- a/libraries/MTConnect.NET-Common/Streams/IDeviceStream.cs +++ b/libraries/MTConnect.NET-Common/Streams/IDeviceStream.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. using MTConnect.Observations; @@ -7,22 +7,22 @@ namespace MTConnect.Streams { /// - /// DeviceStream is a XML container that organizes data reported from a single piece of equipment.A DeviceStream element MUST be provided for each piece of equipment reporting data in an MTConnectStreams document. + /// Organizes data reported from a Device. /// public interface IDeviceStream { /// - /// The name of an element or a piece of equipment. The name associated with the piece of equipment reporting the data contained in this DeviceStream container. + /// Name of the Device. /// string Name { get; } /// - /// The uuid associated with the piece of equipment reporting the data contained in this DeviceStream container. + /// Uuid of the Device. /// string Uuid { get; } /// - /// An XML container type element that organizes data returned from an Agent in response to a current or sample HTTP request. + /// Organizes the data associated with each Component entity defined for a Device in the associated MTConnectDevices Response Document. /// IEnumerable ComponentStreams { get; } diff --git a/libraries/MTConnect.NET-Common/Streams/IStreamsResponseDocument.cs b/libraries/MTConnect.NET-Common/Streams/IStreamsResponseDocument.cs index 6b5d1825..fea4b6a3 100644 --- a/libraries/MTConnect.NET-Common/Streams/IStreamsResponseDocument.cs +++ b/libraries/MTConnect.NET-Common/Streams/IStreamsResponseDocument.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. using MTConnect.Headers; @@ -9,17 +9,17 @@ namespace MTConnect.Streams { /// - /// The Streams Information Model provides a representation of the data reported by a piece of equipment used for a manufacturing process, or used for any other purpose. + /// Root entity of an MTConnectStreams Response Document that contains the Observation Information Model of one or more Device entities. /// public interface IStreamsResponseDocument { /// - /// Contains the Header information in an MTConnect Streams XML document + /// Provides information from an agent defining version information, storage capacity, and parameters associated with the data management within the agent. /// IMTConnectStreamsHeader Header { get; } /// - /// Streams is a container type XML element used to group the data reported from one or more pieces of equipment into a single XML document. + /// Streams groups one or more DeviceStream entities. /// IEnumerable Streams { get; } diff --git a/libraries/MTConnect.NET-Common/Streams/StreamsResponseDocument.cs b/libraries/MTConnect.NET-Common/Streams/StreamsResponseDocument.cs index 2c8df206..c4b5aad3 100644 --- a/libraries/MTConnect.NET-Common/Streams/StreamsResponseDocument.cs +++ b/libraries/MTConnect.NET-Common/Streams/StreamsResponseDocument.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. using MTConnect.Headers; @@ -9,17 +9,17 @@ namespace MTConnect.Streams { /// - /// The Streams Information Model provides a representation of the data reported by a piece of equipment used for a manufacturing process, or used for any other purpose. + /// Root entity of an MTConnectStreams Response Document that contains the Observation Information Model of one or more Device entities. /// public class StreamsResponseDocument : IStreamsResponseDocument { /// - /// Contains the Header information in an MTConnect Streams XML document + /// Provides information from an agent defining version information, storage capacity, and parameters associated with the data management within the agent. /// public IMTConnectStreamsHeader Header { get; set; } /// - /// Streams is a container type XML element used to group the data reported from one or more pieces of equipment into a single XML document. + /// Streams groups one or more DeviceStream entities. /// public IEnumerable Streams { get; set; } diff --git a/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpClient.cs b/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpClient.cs index 38852eec..bfc91881 100644 --- a/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpClient.cs +++ b/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpClient.cs @@ -5,6 +5,7 @@ using MTConnect.Devices; using MTConnect.Errors; using MTConnect.Formatters; +using MTConnect.Headers; using MTConnect.Http; using MTConnect.Observations; using MTConnect.Streams; @@ -669,26 +670,6 @@ private async Task Worker() } } - // Clear Cached DataItems and Components - lock (_lock) - { - _cachedComponents.Clear(); - _cachedDataItems.Clear(); - } - - // Add to cached list - if (!probe.Devices.IsNullOrEmpty()) - { - foreach (var device in probe.Devices) - { - lock (_lock) - { - _devices.Remove(device.Uuid); - _devices.Add(device.Uuid, device); - } - } - } - if (UseStreaming) { // Run Current Request @@ -843,14 +824,30 @@ private async Task Worker() private void ProcessProbeDocument(IDevicesResponseDocument document) { - // Raise ProbeReceived Event - ProbeReceived?.Invoke(this, document); - if (document != null && !document.Devices.IsNullOrEmpty()) { + // Clear Cached DataItems and Components + lock (_lock) + { + _cachedComponents.Clear(); + _cachedDataItems.Clear(); + } + + // Raise ProbeReceived Event + ProbeReceived?.Invoke(this, document); + foreach (var device in document.Devices) { - DeviceReceived?.Invoke(this, device); + var outputDevice = ProcessDevice(document.Header, device); + + // Add to cached list + lock (_lock) + { + _devices.Remove(outputDevice.Uuid); + _devices.Add(outputDevice.Uuid, outputDevice); + } + + DeviceReceived?.Invoke(this, outputDevice); } } } @@ -862,33 +859,31 @@ private void ProcessCurrentDocument(IStreamsResponseDocument document, Cancellat if (document != null) { - if (!document.Streams.IsNullOrEmpty()) + if (document.Header != null && !document.Streams.IsNullOrEmpty()) { - IDeviceStream deviceStream = null; - - // Get the DeviceStream for the Device or default to the first - if (!string.IsNullOrEmpty(Device)) deviceStream = document.Streams.FirstOrDefault(o => o.Uuid == Device || o.Name == Device); - else deviceStream = document.Streams.FirstOrDefault(); + // Recreate Response Document (to set DataItem property for Observations) + var response = new StreamsResponseDocument(); + response.Header = document.Header; - var observations = deviceStream.Observations; - if (deviceStream != null && !observations.IsNullOrEmpty()) + var deviceStreams = new List(); + foreach (var stream in document.Streams) { - // Recreate Response Document (to set DataItem property for Observations) - var response = new StreamsResponseDocument(); - response.Header = document.Header; + deviceStreams.Add(ProcessDeviceStream(response.Header, stream)); + } + response.Streams = deviceStreams; - var deviceStreams = new List(); - foreach (var stream in document.Streams) - { - deviceStreams.Add(ProcessDeviceStream(stream)); - } - response.Streams = deviceStreams; - CheckAssetChanged(deviceStream.Observations, cancel); + CurrentReceived?.Invoke(this, response); + - CurrentReceived?.Invoke(this, response); + // Process Device Streams + foreach (var deviceStream in response.Streams) + { + // Check to see if any Assets have changed + CheckAssetChanged(deviceStream.Observations, cancel); - observations = response.GetObservations(); + // Get Observations from Device Stream + var observations = response.GetObservations(); if (!observations.IsNullOrEmpty()) { foreach (var observation in observations) @@ -908,37 +903,36 @@ private void ProcessSampleDocument(IStreamsResponseDocument document, Cancellati if (document != null) { - // Set Agent Instance ID - if (document.Header != null) _lastInstanceId = document.Header.InstanceId; - - if (!document.Streams.IsNullOrEmpty()) + if (document.Header != null && !document.Streams.IsNullOrEmpty()) { - IDeviceStream deviceStream = null; + // Set Agent Instance ID + _lastInstanceId = document.Header.InstanceId; - // Get the DeviceStream for the Device or default to the first - if (!string.IsNullOrEmpty(Device)) deviceStream = document.Streams.FirstOrDefault(o => o.Uuid == Device || o.Name == Device); - else deviceStream = document.Streams.FirstOrDefault(); + // Recreate Response Document (to set DataItem property for Observations) + var response = new StreamsResponseDocument(); + response.Header = document.Header; - if (deviceStream != null && deviceStream.Observations != null && deviceStream.Observations.Count() > 0) + var deviceStreams = new List(); + foreach (var stream in document.Streams) { - // Recreate Response Document (to set DataItem property for Observations) - var response = new StreamsResponseDocument(); - response.Header = document.Header; + deviceStreams.Add(ProcessDeviceStream(response.Header, stream)); + } + response.Streams = deviceStreams; - var deviceStreams = new List(); - foreach (var stream in document.Streams) - { - deviceStreams.Add(ProcessDeviceStream(stream)); - } - response.Streams = deviceStreams; - CheckAssetChanged(deviceStream.Observations, cancel); + SampleReceived?.Invoke(this, response); + + // Process Device Streams + foreach (var deviceStream in response.Streams) + { // Save the most recent Sequence that was read _lastSequence = deviceStream.Observations.Max(o => o.Sequence); - SampleReceived?.Invoke(this, response); + // Check to see if any Assets have changed + CheckAssetChanged(deviceStream.Observations, cancel); + // Get Observations from Device Stream var observations = response.GetObservations(); if (!observations.IsNullOrEmpty()) { @@ -952,7 +946,116 @@ private void ProcessSampleDocument(IStreamsResponseDocument document, Cancellati } } - private IDeviceStream ProcessDeviceStream(IDeviceStream inputDeviceStream) + private static IDevice ProcessDevice(IMTConnectDevicesHeader header, IDevice inputDevice) + { + var outputDevice = (Device)inputDevice; + outputDevice.InstanceId = header.InstanceId; + + // Add DataItems + if (!inputDevice.DataItems.IsNullOrEmpty()) + { + var outputDataItems = new List(); + foreach (var inputDataItem in inputDevice.DataItems) + { + outputDataItems.Add(ProcessDataItem(header, inputDataItem)); + } + outputDevice.DataItems = outputDataItems; + } + + // Add Compositions + if (!inputDevice.Compositions.IsNullOrEmpty()) + { + var outputCompositions = new List(); + foreach (var inputComposition in inputDevice.Compositions) + { + outputCompositions.Add(ProcessComposition(header, inputComposition)); + } + outputDevice.Compositions = outputCompositions; + } + + // Add Components + if (!inputDevice.Components.IsNullOrEmpty()) + { + var outputSubComponents = new List(); + foreach (var inputSubComponent in inputDevice.Components) + { + outputSubComponents.Add(ProcessComponent(header, inputSubComponent)); + } + outputDevice.Components = outputSubComponents; + } + + return outputDevice; + } + + private static IComponent ProcessComponent(IMTConnectDevicesHeader header, IComponent inputComponent) + { + var outputComponent = (Component)inputComponent; + outputComponent.InstanceId = header.InstanceId; + + // Add DataItems + if (!inputComponent.DataItems.IsNullOrEmpty()) + { + var outputDataItems = new List(); + foreach (var inputDataItem in inputComponent.DataItems) + { + outputDataItems.Add(ProcessDataItem(header, inputDataItem)); + } + outputComponent.DataItems = outputDataItems; + } + + // Add Compositions + if (!inputComponent.Compositions.IsNullOrEmpty()) + { + var outputCompositions = new List(); + foreach (var inputComposition in inputComponent.Compositions) + { + outputCompositions.Add(ProcessComposition(header, inputComposition)); + } + outputComponent.Compositions = outputCompositions; + } + + // Add Components + if (!inputComponent.Components.IsNullOrEmpty()) + { + var outputSubComponents = new List(); + foreach (var inputSubComponent in inputComponent.Components) + { + outputSubComponents.Add(ProcessComponent(header, inputSubComponent)); + } + outputComponent.Components = outputSubComponents; + } + + return outputComponent; + } + + private static IComposition ProcessComposition(IMTConnectDevicesHeader header, IComposition inputComposition) + { + var outputComposition = (Composition)inputComposition; + outputComposition.InstanceId = header.InstanceId; + + // Add DataItems + if (!inputComposition.DataItems.IsNullOrEmpty()) + { + var outputDataItems = new List(); + foreach (var inputDataItem in inputComposition.DataItems) + { + outputDataItems.Add(ProcessDataItem(header, inputDataItem)); + } + outputComposition.DataItems = outputDataItems; + } + + return outputComposition; + } + + private static IDataItem ProcessDataItem(IMTConnectDevicesHeader header, IDataItem inputDataItem) + { + var outputDataItem = (DataItem)inputDataItem; + outputDataItem.InstanceId = header.InstanceId; + return outputDataItem; + } + + + private IDeviceStream ProcessDeviceStream(IMTConnectStreamsHeader header, IDeviceStream inputDeviceStream) { var outputDeviceStream = new DeviceStream(); outputDeviceStream.Name = inputDeviceStream.Name; @@ -963,7 +1066,7 @@ private IDeviceStream ProcessDeviceStream(IDeviceStream inputDeviceStream) { foreach (var componentStream in inputDeviceStream.ComponentStreams) { - componentStreams.Add(ProcessComponentStream(outputDeviceStream.Uuid, componentStream)); + componentStreams.Add(ProcessComponentStream(header, outputDeviceStream.Uuid, componentStream)); } } outputDeviceStream.ComponentStreams = componentStreams; @@ -971,13 +1074,23 @@ private IDeviceStream ProcessDeviceStream(IDeviceStream inputDeviceStream) return outputDeviceStream; } - private IComponentStream ProcessComponentStream(string deviceUuid, IComponentStream inputComponentStream) + private IComponentStream ProcessComponentStream(IMTConnectStreamsHeader header, string deviceUuid, IComponentStream inputComponentStream) { var outputComponentStream = new ComponentStream(); + outputComponentStream.ComponentId = inputComponentStream.ComponentId; + outputComponentStream.ComponentType = inputComponentStream.ComponentType; outputComponentStream.Name = inputComponentStream.Name; outputComponentStream.NativeName = inputComponentStream.NativeName; outputComponentStream.Uuid = inputComponentStream.Uuid; - outputComponentStream.Component = GetCachedComponent(deviceUuid, inputComponentStream.ComponentId); + + if (inputComponentStream.ComponentType == Agent.TypeId || inputComponentStream.ComponentType == Devices.Device.TypeId) + { + outputComponentStream.Component = GetCachedDevice(deviceUuid); + } + else + { + outputComponentStream.Component = GetCachedComponent(deviceUuid, inputComponentStream.ComponentId); + } var observations = new List(); if (!inputComponentStream.Observations.IsNullOrEmpty()) @@ -997,6 +1110,7 @@ private IComponentStream ProcessComponentStream(string deviceUuid, IComponentStr outputObservation.Type = inputObservation.Type; outputObservation.SubType = inputObservation.SubType; outputObservation.Name = inputObservation.Name; + outputObservation.InstanceId = header.InstanceId; outputObservation.Sequence = inputObservation.Sequence; outputObservation.Timestamp = inputObservation.Timestamp; outputObservation.AddValues(inputObservation.Values); diff --git a/libraries/MTConnect.NET-HTTP/Servers/MTConnectCurrentResponseHandler.cs b/libraries/MTConnect.NET-HTTP/Servers/MTConnectCurrentResponseHandler.cs index 50ac3495..3aff9ed5 100644 --- a/libraries/MTConnect.NET-HTTP/Servers/MTConnectCurrentResponseHandler.cs +++ b/libraries/MTConnect.NET-HTTP/Servers/MTConnectCurrentResponseHandler.cs @@ -41,8 +41,8 @@ protected async override Task OnRequestReceived(IHttpCont var path = httpRequest.QueryString["path"]; // Read "at" parameter from Query string - var at = httpRequest.QueryString["at"].ToULong(); - if (at < 1) at = 0; + ulong? at = null; + if (httpRequest.QueryString.ContainsKey("at")) at = httpRequest.QueryString["at"].ToULong(); // Read "interval" parameter from Query string var interval = httpRequest.QueryString["interval"].ToInt(); diff --git a/libraries/MTConnect.NET-HTTP/Servers/MTConnectHttpRequests.cs b/libraries/MTConnect.NET-HTTP/Servers/MTConnectHttpRequests.cs index 217ed3f5..e547ef6a 100644 --- a/libraries/MTConnect.NET-HTTP/Servers/MTConnectHttpRequests.cs +++ b/libraries/MTConnect.NET-HTTP/Servers/MTConnectHttpRequests.cs @@ -149,7 +149,7 @@ public static MTConnectHttpResponse GetCurrentRequest( IMTConnectAgentBroker mtconnectAgent, string deviceType = null, string path = null, - ulong at = 0, + ulong? at = null, int interval = 0, Version mtconnectVersion = null, string documentFormat = DocumentFormat.XML, @@ -192,8 +192,16 @@ public static MTConnectHttpResponse GetCurrentRequest( IStreamsResponseOutputDocument document; // Get MTConnectStreams document from the MTConnectAgent - if (dataItemIds != null) document = mtconnectAgent.GetDeviceStreamsResponseDocument(dataItemIds, at, mtconnectVersion: mtconnectVersion, deviceType: deviceType); - else document = mtconnectAgent.GetDeviceStreamsResponseDocument(at, mtconnectVersion: mtconnectVersion, deviceType: deviceType); + if (dataItemIds != null) + { + if (at.HasValue) document = mtconnectAgent.GetDeviceStreamsResponseDocument(dataItemIds, at.Value, mtconnectVersion: mtconnectVersion, deviceType: deviceType); + else document = mtconnectAgent.GetDeviceStreamsResponseDocument(dataItemIds, mtconnectVersion: mtconnectVersion, deviceType: deviceType); + } + else + { + if (at.HasValue) document = mtconnectAgent.GetDeviceStreamsResponseDocument(at.Value, mtconnectVersion: mtconnectVersion, deviceType: deviceType); + else document = mtconnectAgent.GetDeviceStreamsResponseDocument(mtconnectVersion: mtconnectVersion, deviceType: deviceType); + } stpw.Stop(); double duration = stpw.GetElapsedMilliseconds(); @@ -245,7 +253,7 @@ public static MTConnectHttpResponse GetDeviceCurrentRequest( IMTConnectAgentBroker mtconnectAgent, string deviceKey, string path = null, - ulong at = 0, + ulong? at = null, int interval = -1, Version mtconnectVersion = null, string documentFormat = DocumentFormat.XML, @@ -290,8 +298,16 @@ public static MTConnectHttpResponse GetDeviceCurrentRequest( IStreamsResponseOutputDocument document; // Get MTConnectStreams document from the MTConnectAgent - if (dataItemIds != null) document = mtconnectAgent.GetDeviceStreamsResponseDocument(deviceKey, dataItemIds, at, mtconnectVersion: mtconnectVersion); - else document = mtconnectAgent.GetDeviceStreamsResponseDocument(deviceKey, at, mtconnectVersion: mtconnectVersion); + if (dataItemIds != null) + { + if (at.HasValue) document = mtconnectAgent.GetDeviceStreamsResponseDocument(deviceKey, dataItemIds, at.Value, mtconnectVersion: mtconnectVersion); + else document = mtconnectAgent.GetDeviceStreamsResponseDocument(deviceKey, dataItemIds, mtconnectVersion: mtconnectVersion); + } + else + { + if (at.HasValue) document = mtconnectAgent.GetDeviceStreamsResponseDocument(deviceKey, at.Value, mtconnectVersion: mtconnectVersion); + else document = mtconnectAgent.GetDeviceStreamsResponseDocument(deviceKey, mtconnectVersion: mtconnectVersion); + } stpw.Stop(); double duration = stpw.GetElapsedMilliseconds(); diff --git a/libraries/MTConnect.NET-JSON-cppagent/Formatters/JsonHttpResponseDocumentFormatter.cs b/libraries/MTConnect.NET-JSON-cppagent/Formatters/JsonHttpResponseDocumentFormatter.cs index f6c621b3..ef389e0f 100644 --- a/libraries/MTConnect.NET-JSON-cppagent/Formatters/JsonHttpResponseDocumentFormatter.cs +++ b/libraries/MTConnect.NET-JSON-cppagent/Formatters/JsonHttpResponseDocumentFormatter.cs @@ -24,7 +24,7 @@ public class JsonHttpResponseDocumentFormatter : IResponseDocumentFormatter public virtual string ContentType => "application/json"; - public FormatWriteResult Format(IDevicesResponseDocument document, IEnumerable> options = null) + public virtual FormatWriteResult Format(IDevicesResponseDocument document, IEnumerable> options = null) { // Read Indent Option passed to Formatter var indentOutput = GetFormatterOption(options, "indentOutput"); @@ -40,7 +40,7 @@ public FormatWriteResult Format(IDevicesResponseDocument document, IEnumerable> options = null) + public virtual FormatWriteResult Format(ref IStreamsResponseOutputDocument document, IEnumerable> options = null) { // Read Indent Option passed to Formatter var indentOutput = GetFormatterOption(options, "indentOutput"); @@ -89,7 +89,7 @@ public FormatWriteResult Format(IErrorResponseDocument document, IEnumerable CreateDevicesResponseDocument(Stream content, IEnumerable> options = null) + public virtual FormatReadResult CreateDevicesResponseDocument(Stream content, IEnumerable> options = null) { // Read Document var document = JsonSerializer.Deserialize(content); @@ -98,7 +98,7 @@ public FormatReadResult CreateDevicesResponseDocument( return new FormatReadResult(document.ToDocument(), success); } - public FormatReadResult CreateStreamsResponseDocument(Stream content, IEnumerable> options = null) + public virtual FormatReadResult CreateStreamsResponseDocument(Stream content, IEnumerable> options = null) { // Read Document var document = JsonSerializer.Deserialize(content); diff --git a/libraries/MTConnect.NET-JSON-cppagent/Formatters/JsonMqttResponseDocumentFormatter.cs b/libraries/MTConnect.NET-JSON-cppagent/Formatters/JsonMqttResponseDocumentFormatter.cs index 914f0dc6..394bc60c 100644 --- a/libraries/MTConnect.NET-JSON-cppagent/Formatters/JsonMqttResponseDocumentFormatter.cs +++ b/libraries/MTConnect.NET-JSON-cppagent/Formatters/JsonMqttResponseDocumentFormatter.cs @@ -3,8 +3,12 @@ using MTConnect.Assets; using MTConnect.Assets.Json; +using MTConnect.Devices; +using MTConnect.Devices.Json; +using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text.Json; namespace MTConnect.Formatters @@ -16,6 +20,26 @@ public class JsonMqttResponseDocumentFormatter : JsonHttpResponseDocumentFormatt public override string ContentType => "application/json"; + public override FormatWriteResult Format(IDevicesResponseDocument document, IEnumerable> options = null) + { + // Read Indent Option passed to Formatter + var indentOutput = GetFormatterOption(options, "indentOutput"); + var jsonOptions = indentOutput ? JsonFunctions.IndentOptions : JsonFunctions.DefaultOptions; + + if (!document.Devices.IsNullOrEmpty()) + { + var device = document.Devices.FirstOrDefault(); + var outputStream = new MemoryStream(); + JsonSerializer.Serialize(outputStream, new JsonDeviceContainer(device), jsonOptions); + if (outputStream != null && outputStream.Length > 0) + { + return FormatWriteResult.Successful(outputStream, ContentType); + } + } + + return FormatWriteResult.Error(); + } + public override FormatWriteResult Format(IAssetsResponseDocument document, IEnumerable> options = null) { // Read Indent Option passed to Formatter @@ -32,6 +56,33 @@ public override FormatWriteResult Format(IAssetsResponseDocument document, IEnum return FormatWriteResult.Error(); } + + public override FormatReadResult CreateDevicesResponseDocument(Stream content, IEnumerable> options = null) + { + try + { + // Read Document + var devices = JsonSerializer.Deserialize(content); + var success = devices != null; + + var responseDocument = new DevicesResponseDocument(); + + var device = devices.ToDevice(); + if (device != null) + { + responseDocument.Devices = new IDevice[] { device }; + } + + return new FormatReadResult(responseDocument, success); + } + catch (Exception ex) + { + var messages = ex.Message != null ? new string[] { ex.Message } : null; + + return new FormatReadResult(null, false, errors: messages); + } + } + public override FormatReadResult CreateAssetsResponseDocument(Stream content, IEnumerable> options = null) { // Read Document diff --git a/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonDataSetEntries.cs b/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonDataSetEntries.cs index a5194d37..0410f976 100644 --- a/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonDataSetEntries.cs +++ b/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonDataSetEntries.cs @@ -54,7 +54,7 @@ public override JsonDataSetEntries Read(ref Utf8JsonReader reader, Type typeToCo } else { - reader.Skip(); // Unavailable + reader.TrySkip(); // Unavailable } return null; diff --git a/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonTableEntries.cs b/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonTableEntries.cs index febe09ab..632ee3dc 100644 --- a/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonTableEntries.cs +++ b/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonTableEntries.cs @@ -54,7 +54,7 @@ public override JsonTableEntries Read(ref Utf8JsonReader reader, Type typeToConv } else { - reader.Skip(); // Unavailable + reader.TrySkip(); // Unavailable } return null; diff --git a/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonTimeSeriesSamples.cs b/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonTimeSeriesSamples.cs index a71ea7a2..e99f87c0 100644 --- a/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonTimeSeriesSamples.cs +++ b/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonTimeSeriesSamples.cs @@ -55,7 +55,7 @@ public override JsonTimeSeriesSamples Read(ref Utf8JsonReader reader, Type typeT } else { - reader.Skip(); // Unavailable + reader.TrySkip(); // Unavailable } return null; diff --git a/libraries/MTConnect.NET-MQTT/Clients/MTConnectMqttClient.cs b/libraries/MTConnect.NET-MQTT/Clients/MTConnectMqttClient.cs index f12f04fc..01f958bd 100644 --- a/libraries/MTConnect.NET-MQTT/Clients/MTConnectMqttClient.cs +++ b/libraries/MTConnect.NET-MQTT/Clients/MTConnectMqttClient.cs @@ -8,6 +8,7 @@ using MTConnect.Devices; using MTConnect.Errors; using MTConnect.Formatters; +using MTConnect.Headers; using MTConnect.Observations; using MTConnect.Streams; using System; @@ -169,7 +170,7 @@ public class MTConnectMqttClient : IMTConnectClient, IMTConnectEntityClient, IDi /// Initializes a new instance of the MTConnectMqttClient class that is used to perform /// the full protocol from an MTConnect Agent using the MTConnect MQTT Api protocol /// - public MTConnectMqttClient(string server, int port = 1883, string deviceUuid = null, string topicPrefix = _defaultTopicPrefix, string documentFormat = _defaultDocumentFormat, string clientId = null, int qos = 1) + public MTConnectMqttClient(string server, int port = 1883, string deviceUuid = null, string topicPrefix = _defaultTopicPrefix, string documentFormat = _defaultDocumentFormat, string clientId = null, int qos = 0) { var configuration = new MTConnectMqttClientConfiguration(); configuration.Server = server; @@ -363,18 +364,26 @@ private async Task Worker() private async Task StartAllDevicesProtocol() { - await _mqttClient.SubscribeAsync("MTConnect/Probe/#"); - await _mqttClient.SubscribeAsync("MTConnect/Current/#"); - await _mqttClient.SubscribeAsync("MTConnect/Sample/#"); - await _mqttClient.SubscribeAsync("MTConnect/Asset/#"); + var topicPrefix = _configuration.TopicPrefix != null ? _configuration.TopicPrefix : ""; + topicPrefix = topicPrefix.Trim('/'); + + await _mqttClient.SubscribeAsync($"{topicPrefix}/Probe/+"); + await _mqttClient.SubscribeAsync($"{topicPrefix}/Probe/+/Availability"); + await _mqttClient.SubscribeAsync($"{topicPrefix}/Current/+"); + await _mqttClient.SubscribeAsync($"{topicPrefix}/Sample/+"); + await _mqttClient.SubscribeAsync($"{topicPrefix}/Asset/+"); } private async Task StartDeviceProtocol(string deviceUuid) { - await _mqttClient.SubscribeAsync($"MTConnect/Probe/{deviceUuid}"); - await _mqttClient.SubscribeAsync($"MTConnect/Current/{deviceUuid}"); - await _mqttClient.SubscribeAsync($"MTConnect/Sample/{deviceUuid}"); - await _mqttClient.SubscribeAsync($"MTConnect/Asset/{deviceUuid}/#"); + var topicPrefix = _configuration.TopicPrefix != null ? _configuration.TopicPrefix : ""; + topicPrefix = topicPrefix.Trim('/'); + + await _mqttClient.SubscribeAsync($"{topicPrefix}/Probe/{deviceUuid}"); + await _mqttClient.SubscribeAsync($"{topicPrefix}/Probe/{deviceUuid}/Availability"); + await _mqttClient.SubscribeAsync($"{topicPrefix}/Current/{deviceUuid}"); + await _mqttClient.SubscribeAsync($"{topicPrefix}/Sample/{deviceUuid}"); + await _mqttClient.SubscribeAsync($"{topicPrefix}/Asset/{deviceUuid}/+"); } @@ -455,20 +464,33 @@ private bool IsAssetTopic(string topic) private void ProcessProbeMessage(MqttApplicationMessage message) { - var result = EntityFormatter.CreateDevice(_documentFormat, new MemoryStream(message.Payload)); - if (result.Success) + using (var contentStream = new MemoryStream(message.Payload)) { - var device = result.Content; - if (device != null && device.Uuid != null) + var result = ResponseDocumentFormatter.CreateDevicesResponseDocument(_documentFormat, contentStream); + if (result.Success) { - // Add to cached list - lock (_lock) + var responseDocument = result.Content; + if (responseDocument != null && !responseDocument.Devices.IsNullOrEmpty()) { - _devices.Remove(device.Uuid); - _devices.Add(device.Uuid, device); - } + foreach (var device in responseDocument.Devices) + { + if (device != null && device.Uuid != null) + { + var outputDevice = ProcessDevice(responseDocument.Header, device); - DeviceReceived?.Invoke(this, device); + // Add to cached list + lock (_lock) + { + _devices.Remove(outputDevice.Uuid); + _devices.Add(outputDevice.Uuid, outputDevice); + } + + DeviceReceived?.Invoke(this, outputDevice); + } + } + + ProbeReceived?.Invoke(this, responseDocument); + } } } } @@ -477,10 +499,13 @@ private void ProcessCurrentMessage(MqttApplicationMessage message) { if (!message.Retain) { - var result = ResponseDocumentFormatter.CreateStreamsResponseDocument(_documentFormat, new MemoryStream(message.Payload)); - if (result.Success) + using (var contentStream = new MemoryStream(message.Payload)) { - ProcessCurrentDocument(result.Content); + var result = ResponseDocumentFormatter.CreateStreamsResponseDocument(_documentFormat, contentStream); + if (result.Success) + { + ProcessCurrentDocument(result.Content); + } } } } @@ -489,20 +514,26 @@ private void ProcessSampleMessage(MqttApplicationMessage message) { if (!message.Retain) { - var result = ResponseDocumentFormatter.CreateStreamsResponseDocument(_documentFormat, new MemoryStream(message.Payload)); - if (result.Success) + using (var contentStream = new MemoryStream(message.Payload)) { - ProcessSampleDocument(result.Content); + var result = ResponseDocumentFormatter.CreateStreamsResponseDocument(_documentFormat, contentStream); + if (result.Success) + { + ProcessSampleDocument(result.Content); + } } } } private void ProcessAssetMessage(MqttApplicationMessage message) { - var result = ResponseDocumentFormatter.CreateAssetsResponseDocument(_documentFormat, new MemoryStream(message.Payload)); - if (result.Success) + using (var contentStream = new MemoryStream(message.Payload)) { - ProcessAssetsDocument(result.Content); + var result = ResponseDocumentFormatter.CreateAssetsResponseDocument(_documentFormat, contentStream); + if (result.Success) + { + ProcessAssetsDocument(result.Content); + } } } @@ -516,14 +547,23 @@ private void ProcessCurrentDocument(IStreamsResponseDocument document) { if (!document.Streams.IsNullOrEmpty()) { - IDeviceStream deviceStream = null; + // Recreate Response Document (to set DataItem property for Observations) + var response = new StreamsResponseDocument(); + response.Header = document.Header; + + var deviceStreams = new List(); + foreach (var stream in document.Streams) + { + deviceStreams.Add(ProcessDeviceStream(response.Header, stream)); + } + response.Streams = deviceStreams; + + + CurrentReceived?.Invoke(this, response); - // Get the DeviceStream for the Device or default to the first - if (!string.IsNullOrEmpty(_configuration.DeviceUuid)) deviceStream = document.Streams.FirstOrDefault(o => o.Uuid == _configuration.DeviceUuid); - else deviceStream = document.Streams.FirstOrDefault(); - var observations = deviceStream.Observations; - if (deviceStream != null && deviceStream.Uuid != null && !observations.IsNullOrEmpty()) + // Process Device Streams + foreach (var deviceStream in response.Streams) { ulong lastSequence; ulong lastInstanceId; @@ -533,48 +573,34 @@ private void ProcessCurrentDocument(IStreamsResponseDocument document) _deviceInstanceId.TryGetValue(deviceStream.Uuid, out lastInstanceId); } - // Recreate Response Document (to set DataItem property for Observations) - var response = new StreamsResponseDocument(); - response.Header = document.Header; + // Check to see if any Assets have changed + //CheckAssetChanged(deviceStream.Observations, cancel); - if (lastInstanceId < 1 || response.Header.InstanceId != lastInstanceId) + // Get Observations from Device Stream + var observations = response.GetObservations(); + if (!observations.IsNullOrEmpty()) { - var deviceStreams = new List(); - foreach (var stream in document.Streams) - { - deviceStreams.Add(ProcessDeviceStream(stream)); - } - response.Streams = deviceStreams; - - //CheckAssetChanged(deviceStream.Observations, cancel); - - CurrentReceived?.Invoke(this, response); - - observations = response.GetObservations(); - if (!observations.IsNullOrEmpty()) + foreach (var observation in observations) { - foreach (var observation in observations) + if (observation.Sequence > lastSequence) { - if (observation.Sequence > lastSequence) - { - ObservationReceived?.Invoke(this, observation); - } + ObservationReceived?.Invoke(this, observation); } + } - var maxSequence = observations.Max(o => o.Sequence); + var maxSequence = observations.Max(o => o.Sequence); - // Save the most recent Sequence that was read - lock (_lock) - { - _deviceLastCurrentSequence.Remove(deviceStream.Uuid); - _deviceLastCurrentSequence.Add(deviceStream.Uuid, maxSequence); + // Save the most recent Sequence that was read + lock (_lock) + { + _deviceLastCurrentSequence.Remove(deviceStream.Uuid); + _deviceLastCurrentSequence.Add(deviceStream.Uuid, maxSequence); - _deviceLastSequence.Remove(deviceStream.Uuid); - _deviceLastSequence.Add(deviceStream.Uuid, maxSequence); + _deviceLastSequence.Remove(deviceStream.Uuid); + _deviceLastSequence.Add(deviceStream.Uuid, maxSequence); - _deviceInstanceId.Remove(deviceStream.Uuid); - _deviceInstanceId.Add(deviceStream.Uuid, response.Header.InstanceId); - } + _deviceInstanceId.Remove(deviceStream.Uuid); + _deviceInstanceId.Add(deviceStream.Uuid, response.Header.InstanceId); } } } @@ -589,64 +615,53 @@ private void ProcessSampleDocument(IStreamsResponseDocument document) if (document != null) { - // Set Agent Instance ID - //if (document.Header != null) _lastInstanceId = document.Header.InstanceId; + // Recreate Response Document (to set DataItem property for Observations) + var response = new StreamsResponseDocument(); + response.Header = document.Header; - if (!document.Streams.IsNullOrEmpty()) + var deviceStreams = new List(); + foreach (var stream in document.Streams) { - IDeviceStream deviceStream = null; - - // Get the DeviceStream for the Device or default to the first - if (!string.IsNullOrEmpty(_configuration.DeviceUuid)) deviceStream = document.Streams.FirstOrDefault(o => o.Uuid == _configuration.DeviceUuid); - else deviceStream = document.Streams.FirstOrDefault(); - - if (deviceStream != null && deviceStream.Observations != null && deviceStream.Observations.Count() > 0) - { - ulong lastCurrentSequence; - ulong lastSequence; - lock (_lock) - { - _deviceLastCurrentSequence.TryGetValue(deviceStream.Uuid, out lastCurrentSequence); - _deviceLastSequence.TryGetValue(deviceStream.Uuid, out lastSequence); - } + deviceStreams.Add(ProcessDeviceStream(response.Header, stream)); + } + response.Streams = deviceStreams; - if (lastCurrentSequence > 0) - { - // Recreate Response Document (to set DataItem property for Observations) - var response = new StreamsResponseDocument(); - response.Header = document.Header; - var deviceStreams = new List(); - foreach (var stream in document.Streams) - { - deviceStreams.Add(ProcessDeviceStream(stream)); - } - response.Streams = deviceStreams; + SampleReceived?.Invoke(this, response); - //CheckAssetChanged(deviceStream.Observations, cancel); - SampleReceived?.Invoke(this, response); + // Process Device Streams + foreach (var deviceStream in response.Streams) + { + ulong lastCurrentSequence; + ulong lastSequence; + lock (_lock) + { + _deviceLastCurrentSequence.TryGetValue(deviceStream.Uuid, out lastCurrentSequence); + _deviceLastSequence.TryGetValue(deviceStream.Uuid, out lastSequence); + } - var observations = response.GetObservations(); - if (!observations.IsNullOrEmpty()) + if (lastCurrentSequence > 0) + { + var observations = response.GetObservations(); + if (!observations.IsNullOrEmpty()) + { + foreach (var observation in observations) { - foreach (var observation in observations) + if (observation.Sequence > lastSequence && observation.Sequence > lastCurrentSequence) { - if (observation.Sequence > lastSequence && observation.Sequence > lastCurrentSequence) - { - ObservationReceived?.Invoke(this, observation); - } + ObservationReceived?.Invoke(this, observation); } + } - // Save the most recent Sequence that was read - var maxSequence = observations.Max(o => o.Sequence); + // Save the most recent Sequence that was read + var maxSequence = observations.Max(o => o.Sequence); - // Save the most recent Sequence that was read - lock (_lock) - { - _deviceLastSequence.Remove(deviceStream.Uuid); - _deviceLastSequence.Add(deviceStream.Uuid, maxSequence); - } + // Save the most recent Sequence that was read + lock (_lock) + { + _deviceLastSequence.Remove(deviceStream.Uuid); + _deviceLastSequence.Add(deviceStream.Uuid, maxSequence); } } } @@ -668,7 +683,116 @@ private void ProcessAssetsDocument(IAssetsResponseDocument document) } - private IDeviceStream ProcessDeviceStream(IDeviceStream inputDeviceStream) + private static IDevice ProcessDevice(IMTConnectDevicesHeader header, IDevice inputDevice) + { + var outputDevice = (Device)inputDevice; + outputDevice.InstanceId = header != null ? header.InstanceId : 0; + + // Add DataItems + if (!inputDevice.DataItems.IsNullOrEmpty()) + { + var outputDataItems = new List(); + foreach (var inputDataItem in inputDevice.DataItems) + { + outputDataItems.Add(ProcessDataItem(header, inputDataItem)); + } + outputDevice.DataItems = outputDataItems; + } + + // Add Compositions + if (!inputDevice.Compositions.IsNullOrEmpty()) + { + var outputCompositions = new List(); + foreach (var inputComposition in inputDevice.Compositions) + { + outputCompositions.Add(ProcessComposition(header, inputComposition)); + } + outputDevice.Compositions = outputCompositions; + } + + // Add Components + if (!inputDevice.Components.IsNullOrEmpty()) + { + var outputSubComponents = new List(); + foreach (var inputSubComponent in inputDevice.Components) + { + outputSubComponents.Add(ProcessComponent(header, inputSubComponent)); + } + outputDevice.Components = outputSubComponents; + } + + return outputDevice; + } + + private static IComponent ProcessComponent(IMTConnectDevicesHeader header, IComponent inputComponent) + { + var outputComponent = (Component)inputComponent; + outputComponent.InstanceId = header != null ? header.InstanceId : 0; + + // Add DataItems + if (!inputComponent.DataItems.IsNullOrEmpty()) + { + var outputDataItems = new List(); + foreach (var inputDataItem in inputComponent.DataItems) + { + outputDataItems.Add(ProcessDataItem(header, inputDataItem)); + } + outputComponent.DataItems = outputDataItems; + } + + // Add Compositions + if (!inputComponent.Compositions.IsNullOrEmpty()) + { + var outputCompositions = new List(); + foreach (var inputComposition in inputComponent.Compositions) + { + outputCompositions.Add(ProcessComposition(header, inputComposition)); + } + outputComponent.Compositions = outputCompositions; + } + + // Add Components + if (!inputComponent.Components.IsNullOrEmpty()) + { + var outputSubComponents = new List(); + foreach (var inputSubComponent in inputComponent.Components) + { + outputSubComponents.Add(ProcessComponent(header, inputSubComponent)); + } + outputComponent.Components = outputSubComponents; + } + + return outputComponent; + } + + private static IComposition ProcessComposition(IMTConnectDevicesHeader header, IComposition inputComposition) + { + var outputComposition = (Composition)inputComposition; + outputComposition.InstanceId = header != null ? header.InstanceId : 0; + + // Add DataItems + if (!inputComposition.DataItems.IsNullOrEmpty()) + { + var outputDataItems = new List(); + foreach (var inputDataItem in inputComposition.DataItems) + { + outputDataItems.Add(ProcessDataItem(header, inputDataItem)); + } + outputComposition.DataItems = outputDataItems; + } + + return outputComposition; + } + + private static IDataItem ProcessDataItem(IMTConnectDevicesHeader header, IDataItem inputDataItem) + { + var outputDataItem = (DataItem)inputDataItem; + outputDataItem.InstanceId = header != null ? header.InstanceId : 0; + return outputDataItem; + } + + + private IDeviceStream ProcessDeviceStream(IMTConnectStreamsHeader header, IDeviceStream inputDeviceStream) { var outputDeviceStream = new DeviceStream(); outputDeviceStream.Name = inputDeviceStream.Name; @@ -679,7 +803,7 @@ private IDeviceStream ProcessDeviceStream(IDeviceStream inputDeviceStream) { foreach (var componentStream in inputDeviceStream.ComponentStreams) { - componentStreams.Add(ProcessComponentStream(outputDeviceStream.Uuid, componentStream)); + componentStreams.Add(ProcessComponentStream(header, outputDeviceStream.Uuid, componentStream)); } } outputDeviceStream.ComponentStreams = componentStreams; @@ -687,13 +811,23 @@ private IDeviceStream ProcessDeviceStream(IDeviceStream inputDeviceStream) return outputDeviceStream; } - private IComponentStream ProcessComponentStream(string deviceUuid, IComponentStream inputComponentStream) + private IComponentStream ProcessComponentStream(IMTConnectStreamsHeader header, string deviceUuid, IComponentStream inputComponentStream) { var outputComponentStream = new ComponentStream(); + outputComponentStream.ComponentId = inputComponentStream.ComponentId; + outputComponentStream.ComponentType = inputComponentStream.ComponentType; outputComponentStream.Name = inputComponentStream.Name; outputComponentStream.NativeName = inputComponentStream.NativeName; outputComponentStream.Uuid = inputComponentStream.Uuid; - outputComponentStream.Component = GetCachedComponent(deviceUuid, inputComponentStream.ComponentId); + + if (inputComponentStream.ComponentType == Agent.TypeId || inputComponentStream.ComponentType == Devices.Device.TypeId) + { + outputComponentStream.Component = GetCachedDevice(deviceUuid); + } + else + { + outputComponentStream.Component = GetCachedComponent(deviceUuid, inputComponentStream.ComponentId); + } var observations = new List(); if (!inputComponentStream.Observations.IsNullOrEmpty()) @@ -713,6 +847,7 @@ private IComponentStream ProcessComponentStream(string deviceUuid, IComponentStr outputObservation.Type = inputObservation.Type; outputObservation.SubType = inputObservation.SubType; outputObservation.Name = inputObservation.Name; + outputObservation.InstanceId = header.InstanceId; outputObservation.Sequence = inputObservation.Sequence; outputObservation.Timestamp = inputObservation.Timestamp; outputObservation.AddValues(inputObservation.Values); diff --git a/libraries/MTConnect.NET-MQTT/Configurations/MTConnectMqttClientConfiguration.cs b/libraries/MTConnect.NET-MQTT/Configurations/MTConnectMqttClientConfiguration.cs index 285ea95b..850ea7bb 100644 --- a/libraries/MTConnect.NET-MQTT/Configurations/MTConnectMqttClientConfiguration.cs +++ b/libraries/MTConnect.NET-MQTT/Configurations/MTConnectMqttClientConfiguration.cs @@ -63,6 +63,7 @@ public MTConnectMqttClientConfiguration() Port = 1883; QoS = 1; RetryInterval = 5000; + TopicPrefix = "MTConnect"; } } } \ No newline at end of file diff --git a/libraries/MTConnect.NET-SHDR/Adapters/ShdrAdapter.cs b/libraries/MTConnect.NET-SHDR/Adapters/ShdrAdapter.cs index 1001b042..e6b27311 100644 --- a/libraries/MTConnect.NET-SHDR/Adapters/ShdrAdapter.cs +++ b/libraries/MTConnect.NET-SHDR/Adapters/ShdrAdapter.cs @@ -33,6 +33,9 @@ public class ShdrAdapter protected CancellationTokenSource StopToken => _stop; + protected IMTConnectAdapter Adapter => _adapter; + + /// /// Get a unique identifier for the Adapter /// diff --git a/libraries/MTConnect.NET-SHDR/Adapters/ShdrIntervalQueueAdapter.cs b/libraries/MTConnect.NET-SHDR/Adapters/ShdrIntervalQueueAdapter.cs index 624afddd..3e1606ca 100644 --- a/libraries/MTConnect.NET-SHDR/Adapters/ShdrIntervalQueueAdapter.cs +++ b/libraries/MTConnect.NET-SHDR/Adapters/ShdrIntervalQueueAdapter.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. using MTConnect.Configurations; @@ -20,5 +20,11 @@ public ShdrIntervalQueueAdapter(int port = 7878, int heartbeat = 10000, int inte public ShdrIntervalQueueAdapter(string deviceKey, int port = 7878, int heartbeat = 10000, int interval = _defaultInterval) : base(deviceKey, port, heartbeat, interval, true) { } public ShdrIntervalQueueAdapter(ShdrAdapterClientConfiguration configuration, int interval = _defaultInterval) : base(configuration, interval, true) { } + + + public bool SendBuffer() + { + return Adapter.SendBuffer(); + } } } \ No newline at end of file diff --git a/libraries/MTConnect.NET-SHDR/Adapters/ShdrQueueAdapter.cs b/libraries/MTConnect.NET-SHDR/Adapters/ShdrQueueAdapter.cs index cb5df0e4..f1c69053 100644 --- a/libraries/MTConnect.NET-SHDR/Adapters/ShdrQueueAdapter.cs +++ b/libraries/MTConnect.NET-SHDR/Adapters/ShdrQueueAdapter.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. using MTConnect.Configurations; @@ -17,5 +17,11 @@ public ShdrQueueAdapter(int port = 7878, int heartbeat = 10000) : base(port, hea public ShdrQueueAdapter(string deviceKey, int port = 7878, int heartbeat = 10000) : base(deviceKey, port, heartbeat, null, true) { } public ShdrQueueAdapter(ShdrAdapterClientConfiguration configuration) : base(configuration, null, true) { } + + + public bool SendBuffer() + { + return Adapter.SendBuffer(); + } } } \ No newline at end of file