diff --git a/lmxproxy/src/ZB.MOM.WW.LmxProxy.Client/Domain/ScadaContracts.cs b/lmxproxy/src/ZB.MOM.WW.LmxProxy.Client/Domain/ScadaContracts.cs index c4b7ded..6adc419 100644 --- a/lmxproxy/src/ZB.MOM.WW.LmxProxy.Client/Domain/ScadaContracts.cs +++ b/lmxproxy/src/ZB.MOM.WW.LmxProxy.Client/Domain/ScadaContracts.cs @@ -120,6 +120,9 @@ public class ArrayValue [DataMember(Order = 6)] public StringArray? StringValues { get; set; } + + [DataMember(Order = 7)] + public DatetimeArray? DatetimeValues { get; set; } } [DataContract] @@ -164,6 +167,13 @@ public class StringArray public List Values { get; set; } = []; } +[DataContract] +public class DatetimeArray +{ + [DataMember(Order = 1)] + public List Values { get; set; } = []; +} + // ──────────────────────────────────────────────────────────────── // Quality Code (v2) // ──────────────────────────────────────────────────────────────── diff --git a/lmxproxy/src/ZB.MOM.WW.LmxProxy.Client/LmxProxyClient.cs b/lmxproxy/src/ZB.MOM.WW.LmxProxy.Client/LmxProxyClient.cs index fab607a..e970b95 100644 --- a/lmxproxy/src/ZB.MOM.WW.LmxProxy.Client/LmxProxyClient.cs +++ b/lmxproxy/src/ZB.MOM.WW.LmxProxy.Client/LmxProxyClient.cs @@ -271,12 +271,30 @@ public partial class LmxProxyClient : ILmxProxyClient TypedValueCase.StringValue => tv.StringValue, TypedValueCase.BytesValue => tv.BytesValue, TypedValueCase.DatetimeValue => new DateTime(tv.DatetimeValue, DateTimeKind.Utc), - TypedValueCase.ArrayValue => tv.ArrayValue, + TypedValueCase.ArrayValue => ExtractArrayValue(tv.ArrayValue), TypedValueCase.None => null, _ => null }; } + internal static object? ExtractArrayValue(ArrayValue? av) + { + if (av is null) return null; + if (av.BoolValues is not null) return av.BoolValues.Values.ToArray(); + if (av.Int32Values is not null) return av.Int32Values.Values.ToArray(); + if (av.Int64Values is not null) return av.Int64Values.Values.ToArray(); + if (av.FloatValues is not null) return av.FloatValues.Values.ToArray(); + if (av.DoubleValues is not null) return av.DoubleValues.Values.ToArray(); + if (av.StringValues is not null) return av.StringValues.Values.ToArray(); + if (av.DatetimeValues is not null) + { + return av.DatetimeValues.Values + .Select(ticks => new DateTime(ticks, DateTimeKind.Utc)) + .ToArray(); + } + return null; + } + private async Task ExecuteWithRetry(Func> operation, CancellationToken ct) { if (_resiliencePipeline is not null) diff --git a/lmxproxy/src/ZB.MOM.WW.LmxProxy.Host/Domain/TypedValueConverter.cs b/lmxproxy/src/ZB.MOM.WW.LmxProxy.Host/Domain/TypedValueConverter.cs index 30a4314..50883fd 100644 --- a/lmxproxy/src/ZB.MOM.WW.LmxProxy.Host/Domain/TypedValueConverter.cs +++ b/lmxproxy/src/ZB.MOM.WW.LmxProxy.Host/Domain/TypedValueConverter.cs @@ -109,9 +109,9 @@ namespace ZB.MOM.WW.LmxProxy.Host.Domain case DateTime[] dtArr: { - var arr = new Scada.Int64Array(); + var arr = new Scada.DatetimeArray(); arr.Values.AddRange(Array.ConvertAll(dtArr, dt => dt.ToUniversalTime().Ticks)); - return new Scada.TypedValue { ArrayValue = new Scada.ArrayValue { Int64Values = arr } }; + return new Scada.TypedValue { ArrayValue = new Scada.ArrayValue { DatetimeValues = arr } }; } default: @@ -202,6 +202,17 @@ namespace ZB.MOM.WW.LmxProxy.Host.Domain ? ToArray(arrayValue.StringValues.Values) : Array.Empty(); + case Scada.ArrayValue.ValuesOneofCase.DatetimeValues: + if (arrayValue.DatetimeValues?.Values?.Count > 0) + { + var ticks = ToArray(arrayValue.DatetimeValues.Values); + var result = new DateTime[ticks.Length]; + for (int i = 0; i < ticks.Length; i++) + result[i] = new DateTime(ticks[i], DateTimeKind.Utc); + return result; + } + return Array.Empty(); + default: return null; } diff --git a/lmxproxy/src/ZB.MOM.WW.LmxProxy.Host/Grpc/Protos/scada.proto b/lmxproxy/src/ZB.MOM.WW.LmxProxy.Host/Grpc/Protos/scada.proto index f9f435f..1da59c4 100644 --- a/lmxproxy/src/ZB.MOM.WW.LmxProxy.Host/Grpc/Protos/scada.proto +++ b/lmxproxy/src/ZB.MOM.WW.LmxProxy.Host/Grpc/Protos/scada.proto @@ -38,21 +38,23 @@ message TypedValue { message ArrayValue { oneof values { - BoolArray bool_values = 1; - Int32Array int32_values = 2; - Int64Array int64_values = 3; - FloatArray float_values = 4; - DoubleArray double_values = 5; - StringArray string_values = 6; + BoolArray bool_values = 1; + Int32Array int32_values = 2; + Int64Array int64_values = 3; + FloatArray float_values = 4; + DoubleArray double_values = 5; + StringArray string_values = 6; + DatetimeArray datetime_values = 7; // UTC DateTime.Ticks arrays } } -message BoolArray { repeated bool values = 1; } -message Int32Array { repeated int32 values = 1; } -message Int64Array { repeated int64 values = 1; } -message FloatArray { repeated float values = 1; } -message DoubleArray { repeated double values = 1; } -message StringArray { repeated string values = 1; } +message BoolArray { repeated bool values = 1; } +message Int32Array { repeated int32 values = 1; } +message Int64Array { repeated int64 values = 1; } +message FloatArray { repeated float values = 1; } +message DoubleArray { repeated double values = 1; } +message StringArray { repeated string values = 1; } +message DatetimeArray { repeated int64 values = 1; } // UTC DateTime.Ticks // ============================================================ // OPC UA-Style Quality Codes