fix(dcl): format ArrayValue objects as comma-separated strings for display

ArrayValue from LmxProxy client was showing as type name in debug views.
Added ValueFormatter utility and NormalizeValue in LmxProxyDataConnection
to convert arrays at the adapter boundary. DateTime arrays remain as
"System.DateTime[]" due to server-side v1 string serialization.
This commit is contained in:
Joseph Doherty
2026-03-22 14:46:15 -04:00
parent ea9c2857a7
commit dcdf79afdc
6 changed files with 767 additions and 5 deletions

View File

@@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging;
using ScadaLink.Commons.Interfaces.Protocol;
using ScadaLink.Commons.Types.Enums;
using ZB.MOM.WW.LmxProxy.Client.Domain;
using ScadaLink.Commons.Types;
using QualityCode = ScadaLink.Commons.Interfaces.Protocol.QualityCode;
using WriteResult = ScadaLink.Commons.Interfaces.Protocol.WriteResult;
@@ -76,7 +77,7 @@ public class LmxProxyDataConnection : IDataConnection
{
var vtq = await _client!.ReadAsync(tagPath, cancellationToken);
var quality = MapQuality(vtq.Quality);
var tagValue = new TagValue(vtq.Value, quality, new DateTimeOffset(vtq.Timestamp, TimeSpan.Zero));
var tagValue = new TagValue(NormalizeValue(vtq.Value), quality, new DateTimeOffset(vtq.Timestamp, TimeSpan.Zero));
return vtq.Quality.IsBad()
? new ReadResult(false, tagValue, "LmxProxy read returned bad quality")
@@ -100,7 +101,7 @@ public class LmxProxyDataConnection : IDataConnection
foreach (var (tag, vtq) in vtqs)
{
var quality = MapQuality(vtq.Quality);
var tagValue = new TagValue(vtq.Value, quality, new DateTimeOffset(vtq.Timestamp, TimeSpan.Zero));
var tagValue = new TagValue(NormalizeValue(vtq.Value), quality, new DateTimeOffset(vtq.Timestamp, TimeSpan.Zero));
results[tag] = vtq.Quality.IsBad()
? new ReadResult(false, tagValue, "LmxProxy read returned bad quality")
: new ReadResult(true, tagValue, null);
@@ -177,7 +178,7 @@ public class LmxProxyDataConnection : IDataConnection
(path, vtq) =>
{
var quality = MapQuality(vtq.Quality);
callback(path, new TagValue(vtq.Value, quality, new DateTimeOffset(vtq.Timestamp, TimeSpan.Zero)));
callback(path, new TagValue(NormalizeValue(vtq.Value), quality, new DateTimeOffset(vtq.Timestamp, TimeSpan.Zero)));
},
onStreamError: ex =>
{
@@ -231,6 +232,18 @@ public class LmxProxyDataConnection : IDataConnection
Disconnected?.Invoke();
}
/// <summary>
/// Normalizes a Vtq value for consumption by the rest of the system.
/// Converts LmxProxy ArrayValue objects to comma-separated strings
/// so downstream code doesn't need to know about LmxProxy domain types.
/// </summary>
private static object? NormalizeValue(object? value) => value switch
{
null or string => value,
IFormattable => value,
_ => ValueFormatter.FormatDisplayValue(value)
};
private static QualityCode MapQuality(Quality quality)
{
if (quality.IsGood()) return QualityCode.Good;