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..ae77731 100644 --- a/src/SparkplugNet/Core/Messages/SparkplugMessageGenerator.cs +++ b/src/SparkplugNet/Core/Messages/SparkplugMessageGenerator.cs @@ -671,6 +671,7 @@ private MqttApplicationMessage GetSparkplugNodeBirthB( Seq = (ulong)sequenceNumber, Timestamp = (ulong)dateTime.ToUnixTimeMilliseconds() }; + EnsureSparkplugBMetricTimestamps(ref payload); var convertedPayload = VersionB.PayloadConverter.ConvertVersionBPayload(payload); var serialized = PayloadHelper.Serialize(convertedPayload); @@ -755,6 +756,7 @@ private MqttApplicationMessage GetSparkplugDeviceBirthB( Seq = (ulong)sequenceNumber, Timestamp = (ulong)dateTime.ToUnixTimeMilliseconds() }; + EnsureSparkplugBMetricTimestamps(ref payload); var convertedPayload = VersionB.PayloadConverter.ConvertVersionBPayload(payload); var serialized = PayloadHelper.Serialize(convertedPayload); @@ -990,6 +992,7 @@ private MqttApplicationMessage GetSparkplugNodeDataB( Seq = (ulong)sequenceNumber, Timestamp = (ulong)dateTime.ToUnixTimeMilliseconds() }; + EnsureSparkplugBMetricTimestamps(ref payload); var convertedPayload = VersionB.PayloadConverter.ConvertVersionBPayload(payload); var serialized = PayloadHelper.Serialize(convertedPayload); @@ -1074,6 +1077,7 @@ private MqttApplicationMessage GetSparkplugDeviceDataB( Seq = (ulong)sequenceNumber, Timestamp = (ulong)dateTime.ToUnixTimeMilliseconds() }; + EnsureSparkplugBMetricTimestamps(ref payload); var convertedPayload = VersionB.PayloadConverter.ConvertVersionBPayload(payload); var serialized = PayloadHelper.Serialize(convertedPayload); @@ -1139,7 +1143,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, @@ -1153,7 +1157,8 @@ private static MqttApplicationMessage GetSparkplugNodeCommandB( Seq = (ulong)sequenceNumber, Timestamp = (ulong)dateTime.ToUnixTimeMilliseconds() }; - + EnsureSparkplugBMetricTimestamps(ref payload); + var convertedPayload = VersionB.PayloadConverter.ConvertVersionBPayload(payload); var serialized = PayloadHelper.Serialize(convertedPayload); @@ -1220,7 +1225,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, @@ -1235,6 +1240,7 @@ private static MqttApplicationMessage GetSparkplugDeviceCommandB( Seq = (ulong)sequenceNumber, Timestamp = (ulong)dateTime.ToUnixTimeMilliseconds() }; + EnsureSparkplugBMetricTimestamps(ref payload); var convertedPayload = VersionB.PayloadConverter.ConvertVersionBPayload(payload); var serialized = PayloadHelper.Serialize(convertedPayload); @@ -1251,4 +1257,21 @@ private static 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