feat(dcl): populate obtainable NativeAlarmTransition fields from OPC UA and MxGateway (#27, M2.13)
OPC UA (RealOpcUaClient): - Append 5 new SelectClauses at indices 13–17 (never renumber 0–12): - 13: AlarmConditionType/ActiveState/TransitionTime → OriginalRaiseTime - 14–17: LimitAlarmType HighHighLimit/HighLimit/LowLimit/LowLowLimit → LimitValue - New OpcUaAlarmMapper.PickLimitValue helper: first non-null in HiHi→Hi→Lo→LoLo priority order, InvariantCulture-formatted; empty string for non-limit alarm types. - HandleAlarmEvent reads new indices with fields.Count > N guards; hard minimum (6) unchanged so base ConditionType events still process without the limit fields. - Document unavailable-by-protocol fields (Category, Description, OperatorUser, CurrentValue) inline in BuildAlarmEventFilter and HandleAlarmEvent. MxGateway (MxGatewayAlarmMapper): - MapTransition: CurrentValue and LimitValue now populated via MxValueToString (uses MxValueExtensions.ToClrValue + InvariantCulture) from OnAlarmTransitionEvent proto fields current_value/limit_value. - MapSnapshot: same — populated from ActiveAlarmSnapshot.current_value/limit_value. - MxValueToString helper (internal): null-safe MxValue → string conversion. Tests (17 new, 40 total pass): - OpcUaAlarmMapperTests: PickLimitValue priority, InvariantCulture, all-null case. - MxGatewayAlarmMapperTests: CurrentValue/LimitValue populate from double/string MxValue; absent fields yield empty strings. - RealOpcUaClientAlarmFilterTests: index alignment assertions (count=18, per-index TypeDefinitionId+BrowsePath), regression guard on existing indices 0–12.
This commit is contained in:
@@ -65,4 +65,40 @@ public static class OpcUaAlarmMapper
|
||||
null or "Unshelved" => AlarmShelveState.Unshelved,
|
||||
_ => AlarmShelveState.OneShotShelved
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Picks a representative display-only limit value from the four standard
|
||||
/// <c>LimitAlarmType</c> set-point fields (HighHighLimit, HighLimit, LowLimit,
|
||||
/// LowLowLimit) returned by the OPC UA event SelectClause.
|
||||
///
|
||||
/// <para>
|
||||
/// The fields are absent (null raw value) on non-limit alarm types (discrete,
|
||||
/// off-normal, etc.). When present, the first non-null value is returned in
|
||||
/// priority order: HighHigh → High → Low → LowLow. The caller may use
|
||||
/// <c>AlarmTypeName</c> or <c>ConditionName</c> to determine which specific
|
||||
/// limit is active; this method intentionally returns the coarsest useful value
|
||||
/// for the common single-limit case without requiring callers to understand the
|
||||
/// OPC UA limit hierarchy.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="highHighRaw">Raw HighHighLimit field value (null when absent).</param>
|
||||
/// <param name="highRaw">Raw HighLimit field value (null when absent).</param>
|
||||
/// <param name="lowRaw">Raw LowLimit field value (null when absent).</param>
|
||||
/// <param name="lowLowRaw">Raw LowLowLimit field value (null when absent).</param>
|
||||
/// <returns>
|
||||
/// A formatted string representation of the first non-null limit value, or an
|
||||
/// empty string when all four fields are absent (non-limit alarm type).
|
||||
/// </returns>
|
||||
public static string PickLimitValue(object? highHighRaw, object? highRaw, object? lowRaw, object? lowLowRaw)
|
||||
{
|
||||
// Standard OPC UA LimitAlarmType limit values are numeric (Double/Float/Int).
|
||||
// Convert with InvariantCulture so the decimal separator is always '.' regardless
|
||||
// of the server's locale.
|
||||
foreach (var raw in new[] { highHighRaw, highRaw, lowRaw, lowLowRaw })
|
||||
{
|
||||
if (raw is not null)
|
||||
return Convert.ToString(raw, System.Globalization.CultureInfo.InvariantCulture) ?? "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user