From 25cedfe0b72c5d89292f6a03fae9b6df13af722c Mon Sep 17 00:00:00 2001 From: thomassorensen Date: Fri, 21 Feb 2025 22:23:12 +0100 Subject: [PATCH 1/2] Fixed missing metric timestamp for SparkplubBV3 payloads. --- .../SparkplugMessageGeneratorTestVersion30.cs | 12 ++++- .../SparkplugPayloadConverterTestVersionB.cs | 4 +- .../Messages/SparkplugMessageGenerator.cs | 49 +++++++++++++++++-- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/SparkplugNet.Tests/Messages/SparkplugMessageGeneratorTestVersion30.cs b/src/SparkplugNet.Tests/Messages/SparkplugMessageGeneratorTestVersion30.cs index 15ac569..b0fe976 100644 --- a/src/SparkplugNet.Tests/Messages/SparkplugMessageGeneratorTestVersion30.cs +++ b/src/SparkplugNet.Tests/Messages/SparkplugMessageGeneratorTestVersion30.cs @@ -96,12 +96,13 @@ public void TestDeviceBirthMessageNamespaceB() public void TestNodeBirthMessageNamespaceB() { var dateTime = DateTimeOffset.UtcNow; + var timestamp = (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); var message = this.messageGenerator.GetSparkplugNodeBirthMessage(SparkplugNamespace.VersionB, "group1", "edge1", this.metricsB, 0, 1, dateTime); var payloadVersionB = PayloadHelper.Deserialize(message.Payload); Assert.AreEqual("spBv1.0/group1/NBIRTH/edge1", message.Topic); Assert.IsNotNull(payloadVersionB); - Assert.AreEqual((ulong)dateTime.ToUnixTimeMilliseconds(), payloadVersionB.Timestamp); + Assert.AreEqual(timestamp, payloadVersionB.Timestamp); Assert.AreEqual(2, payloadVersionB.Metrics.Count); Assert.AreEqual(this.metricsB.First().Name, payloadVersionB.Metrics.ElementAt(0).Name); @@ -111,6 +112,13 @@ public void TestNodeBirthMessageNamespaceB() Assert.AreEqual(this.seqMetricB.Name, payloadVersionB.Metrics.ElementAt(1).Name); Assert.AreEqual(Convert.ToUInt64(this.seqMetricB.Value), payloadVersionB.Metrics.ElementAt(1).LongValue); Assert.AreEqual((uint?)this.seqMetricB.DataType, payloadVersionB.Metrics.ElementAt(1).DataType); + + foreach (var metric in payloadVersionB.Metrics) + { + // [tck-id-payloads-name-birth-data-requirement] + // The timestamp MUST be included with every metric in all NBIRTH, DBIRTH, NDATA, and DDATA messages.*# + Assert.AreEqual(metric.Timestamp, timestamp); + } } /// @@ -246,4 +254,4 @@ public void TestNodeCommandMessageNamespaceB() Assert.AreEqual(Convert.ToUInt64(this.seqMetricB.Value), payloadVersionB.Metrics.ElementAt(1).LongValue); Assert.AreEqual((uint?)this.seqMetricB.DataType, payloadVersionB.Metrics.ElementAt(1).DataType); } -} +} \ No newline at end of file diff --git a/src/SparkplugNet.Tests/Payloads/SparkplugPayloadConverterTestVersionB.cs b/src/SparkplugNet.Tests/Payloads/SparkplugPayloadConverterTestVersionB.cs index 0bb3fef..f90af2b 100644 --- a/src/SparkplugNet.Tests/Payloads/SparkplugPayloadConverterTestVersionB.cs +++ b/src/SparkplugNet.Tests/Payloads/SparkplugPayloadConverterTestVersionB.cs @@ -1353,7 +1353,7 @@ public void TestConvertVersionBPayloadToProto() IsTransient = true, IsNull = false, DataType = (uint?)VersionBProtoBuf.DataType.UInt32, - LongValue = 7 + IntValue = 7 }, new() { @@ -2123,4 +2123,4 @@ public void TestConvertVersionBPayloadToProtoWithNegativeValues() EqualityHelper.MetricEquals(convertedMetrics[count++], metric); } } -} +} \ No newline at end of file diff --git a/src/SparkplugNet/Core/Messages/SparkplugMessageGenerator.cs b/src/SparkplugNet/Core/Messages/SparkplugMessageGenerator.cs index d96c248..f9422a7 100644 --- a/src/SparkplugNet/Core/Messages/SparkplugMessageGenerator.cs +++ b/src/SparkplugNet/Core/Messages/SparkplugMessageGenerator.cs @@ -665,6 +665,13 @@ private MqttApplicationMessage GetSparkplugNodeBirthB( int sequenceNumber, DateTimeOffset dateTime) { + if (this.specificationVersion == SparkplugSpecificationVersion.Version30) + { + foreach (var metric in metrics) + { + metric.Timestamp ??= (ulong)dateTime.ToUnixTimeMilliseconds(); + } + } var payload = new Payload { Metrics = metrics.ToList(), @@ -749,6 +756,13 @@ private MqttApplicationMessage GetSparkplugDeviceBirthB( int sequenceNumber, DateTimeOffset dateTime) { + if (this.specificationVersion == SparkplugSpecificationVersion.Version30) + { + foreach (var metric in metrics) + { + metric.Timestamp ??= (ulong)dateTime.ToUnixTimeMilliseconds(); + } + } var payload = new Payload { Metrics = metrics.ToList(), @@ -984,6 +998,13 @@ private MqttApplicationMessage GetSparkplugNodeDataB( int sequenceNumber, DateTimeOffset dateTime) { + if (this.specificationVersion == SparkplugSpecificationVersion.Version30) + { + foreach (var metric in metrics) + { + metric.Timestamp ??= (ulong)dateTime.ToUnixTimeMilliseconds(); + } + } var payload = new Payload { Metrics = metrics.ToList(), @@ -1068,6 +1089,13 @@ private MqttApplicationMessage GetSparkplugDeviceDataB( int sequenceNumber, DateTimeOffset dateTime) { + if (this.specificationVersion == SparkplugSpecificationVersion.Version30) + { + foreach (var metric in metrics) + { + metric.Timestamp ??= (ulong)dateTime.ToUnixTimeMilliseconds(); + } + } var payload = new Payload { Metrics = metrics.ToList(), @@ -1101,6 +1129,7 @@ private MqttApplicationMessage GetSparkplugDeviceDataB( /// The metrics. /// The date time. /// A new NCMD . + private static MqttApplicationMessage GetSparkplugNodeCommandA( SparkplugNamespace nameSpace, string groupIdentifier, @@ -1139,7 +1168,7 @@ private static MqttApplicationMessage GetSparkplugNodeCommandA( /// The sequence number. /// The date time. /// A new NCMD . - private static MqttApplicationMessage GetSparkplugNodeCommandB( + private MqttApplicationMessage GetSparkplugNodeCommandB( SparkplugNamespace nameSpace, string groupIdentifier, string edgeNodeIdentifier, @@ -1147,6 +1176,13 @@ private static MqttApplicationMessage GetSparkplugNodeCommandB( int sequenceNumber, DateTimeOffset dateTime) { + if (this.specificationVersion == SparkplugSpecificationVersion.Version30) + { + foreach (var metric in metrics) + { + metric.Timestamp ??= (ulong)dateTime.ToUnixTimeMilliseconds(); + } + } var payload = new Payload { Metrics = metrics.ToList(), @@ -1220,7 +1256,7 @@ private static MqttApplicationMessage GetSparkplugDeviceCommandA( /// The sequence number. /// The date time. /// A new DCMD . - private static MqttApplicationMessage GetSparkplugDeviceCommandB( + private MqttApplicationMessage GetSparkplugDeviceCommandB( SparkplugNamespace nameSpace, string groupIdentifier, string edgeNodeIdentifier, @@ -1229,6 +1265,13 @@ private static MqttApplicationMessage GetSparkplugDeviceCommandB( int sequenceNumber, DateTimeOffset dateTime) { + if (this.specificationVersion == SparkplugSpecificationVersion.Version30) + { + foreach (var metric in metrics) + { + metric.Timestamp ??= (ulong)dateTime.ToUnixTimeMilliseconds(); + } + } var payload = new Payload { Metrics = metrics.ToList(), @@ -1251,4 +1294,4 @@ private static MqttApplicationMessage GetSparkplugDeviceCommandB( .WithRetainFlag(false) .Build(); } -} +} \ No newline at end of file From ce435e62f7772d1367dae82fceaf69c805c0ee00 Mon Sep 17 00:00:00 2001 From: thomassorensen Date: Sat, 22 Feb 2025 07:47:26 +0100 Subject: [PATCH 2/2] Cleaned up code --- .../Messages/SparkplugMessageGenerator.cs | 68 +++++++------------ 1 file changed, 24 insertions(+), 44 deletions(-) diff --git a/src/SparkplugNet/Core/Messages/SparkplugMessageGenerator.cs b/src/SparkplugNet/Core/Messages/SparkplugMessageGenerator.cs index f9422a7..ae77731 100644 --- a/src/SparkplugNet/Core/Messages/SparkplugMessageGenerator.cs +++ b/src/SparkplugNet/Core/Messages/SparkplugMessageGenerator.cs @@ -665,19 +665,13 @@ private MqttApplicationMessage GetSparkplugNodeBirthB( int sequenceNumber, DateTimeOffset dateTime) { - if (this.specificationVersion == SparkplugSpecificationVersion.Version30) - { - foreach (var metric in metrics) - { - metric.Timestamp ??= (ulong)dateTime.ToUnixTimeMilliseconds(); - } - } var payload = new Payload { Metrics = metrics.ToList(), Seq = (ulong)sequenceNumber, Timestamp = (ulong)dateTime.ToUnixTimeMilliseconds() }; + EnsureSparkplugBMetricTimestamps(ref payload); var convertedPayload = VersionB.PayloadConverter.ConvertVersionBPayload(payload); var serialized = PayloadHelper.Serialize(convertedPayload); @@ -756,19 +750,13 @@ private MqttApplicationMessage GetSparkplugDeviceBirthB( int sequenceNumber, DateTimeOffset dateTime) { - if (this.specificationVersion == SparkplugSpecificationVersion.Version30) - { - foreach (var metric in metrics) - { - metric.Timestamp ??= (ulong)dateTime.ToUnixTimeMilliseconds(); - } - } var payload = new Payload { Metrics = metrics.ToList(), Seq = (ulong)sequenceNumber, Timestamp = (ulong)dateTime.ToUnixTimeMilliseconds() }; + EnsureSparkplugBMetricTimestamps(ref payload); var convertedPayload = VersionB.PayloadConverter.ConvertVersionBPayload(payload); var serialized = PayloadHelper.Serialize(convertedPayload); @@ -998,19 +986,13 @@ private MqttApplicationMessage GetSparkplugNodeDataB( int sequenceNumber, DateTimeOffset dateTime) { - if (this.specificationVersion == SparkplugSpecificationVersion.Version30) - { - foreach (var metric in metrics) - { - metric.Timestamp ??= (ulong)dateTime.ToUnixTimeMilliseconds(); - } - } var payload = new Payload { Metrics = metrics.ToList(), Seq = (ulong)sequenceNumber, Timestamp = (ulong)dateTime.ToUnixTimeMilliseconds() }; + EnsureSparkplugBMetricTimestamps(ref payload); var convertedPayload = VersionB.PayloadConverter.ConvertVersionBPayload(payload); var serialized = PayloadHelper.Serialize(convertedPayload); @@ -1089,19 +1071,13 @@ private MqttApplicationMessage GetSparkplugDeviceDataB( int sequenceNumber, DateTimeOffset dateTime) { - if (this.specificationVersion == SparkplugSpecificationVersion.Version30) - { - foreach (var metric in metrics) - { - metric.Timestamp ??= (ulong)dateTime.ToUnixTimeMilliseconds(); - } - } var payload = new Payload { Metrics = metrics.ToList(), Seq = (ulong)sequenceNumber, Timestamp = (ulong)dateTime.ToUnixTimeMilliseconds() }; + EnsureSparkplugBMetricTimestamps(ref payload); var convertedPayload = VersionB.PayloadConverter.ConvertVersionBPayload(payload); var serialized = PayloadHelper.Serialize(convertedPayload); @@ -1129,7 +1105,6 @@ private MqttApplicationMessage GetSparkplugDeviceDataB( /// The metrics. /// The date time. /// A new NCMD . - private static MqttApplicationMessage GetSparkplugNodeCommandA( SparkplugNamespace nameSpace, string groupIdentifier, @@ -1176,20 +1151,14 @@ private MqttApplicationMessage GetSparkplugNodeCommandB( int sequenceNumber, DateTimeOffset dateTime) { - if (this.specificationVersion == SparkplugSpecificationVersion.Version30) - { - foreach (var metric in metrics) - { - metric.Timestamp ??= (ulong)dateTime.ToUnixTimeMilliseconds(); - } - } var payload = new Payload { Metrics = metrics.ToList(), Seq = (ulong)sequenceNumber, Timestamp = (ulong)dateTime.ToUnixTimeMilliseconds() }; - + EnsureSparkplugBMetricTimestamps(ref payload); + var convertedPayload = VersionB.PayloadConverter.ConvertVersionBPayload(payload); var serialized = PayloadHelper.Serialize(convertedPayload); @@ -1265,19 +1234,13 @@ private MqttApplicationMessage GetSparkplugDeviceCommandB( int sequenceNumber, DateTimeOffset dateTime) { - if (this.specificationVersion == SparkplugSpecificationVersion.Version30) - { - foreach (var metric in metrics) - { - metric.Timestamp ??= (ulong)dateTime.ToUnixTimeMilliseconds(); - } - } var payload = new Payload { Metrics = metrics.ToList(), Seq = (ulong)sequenceNumber, Timestamp = (ulong)dateTime.ToUnixTimeMilliseconds() }; + EnsureSparkplugBMetricTimestamps(ref payload); var convertedPayload = VersionB.PayloadConverter.ConvertVersionBPayload(payload); var serialized = PayloadHelper.Serialize(convertedPayload); @@ -1294,4 +1257,21 @@ private MqttApplicationMessage GetSparkplugDeviceCommandB( .WithRetainFlag(false) .Build(); } + + /// + /// Ensures that all metrics will contain a Timestamp if Sparkplug protol version is Version 3.0 + /// Message timestamp will be added to all metrics that does not already contain timestamps + /// [tck-id-payloads-name-birth-data-requirement] + /// + /// The payload to update + private void EnsureSparkplugBMetricTimestamps(ref Payload payload) + { + if (this.specificationVersion == SparkplugSpecificationVersion.Version30) + { + foreach (var metric in payload.Metrics) + { + metric.Timestamp ??= payload.Timestamp; + } + } + } } \ No newline at end of file