Files
ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Commons/Entities/Templates/TemplateNativeAlarmSource.cs
T
Joseph Doherty dd4f1c2aa3 fix(alarms): Severity runs one direction, higher = more urgent; raw priority kept (#129)
AlarmConditionState.Severity mixed two conventions: OPC UA rows carried Part 9
Severity (higher = more severe) while MxGateway native alarms and computed
alarms carried a raw AVEVA-style priority (1 = most urgent). Every consumer
ranks higher as worse, so Worst Severity, the severity filter/sort and the
site event-log Error threshold picked the LEAST urgent MxGateway/computed
alarms.

- AlarmPriorityBands: the OtOpcUa GalaxyAlarmPriority table (lmxopcua#887,
  b61f3e05), value for value: 1-250 -> 1000, 251-500 -> 750, 501-750 -> 500,
  751-999 -> 250; <= 0 clamps to Critical, > 999 to Low.
- MxGatewayAlarmMapper bands the gateway severity (= AVEVA priority);
  AlarmConditionStateFactory.ForComputed bands PriorityLevel. OPC UA unchanged.
- AlarmConditionState gains trailing Priority (int?): the raw source number,
  exactly the pre-#129 Severity. AlarmStateChanged.Priority and the wire
  AlarmStateUpdate.priority keep that meaning (no proto change); central derives
  Severity by kind (SeverityFromPriority), so an older site decodes correctly.
- ScriptAlarm gains trailing Priority. The native MES 900-999 band and the MES
  API Severity/MinSeverity/MaxSeverity key off Priority; rig seed scripts moved
  from a.Severity to a.Priority, so MES output is unchanged.
- AlarmActor raise logs Error when the banded severity >= 700 (same threshold
  as NativeAlarmActor): priority 1-500 Error, 501+ Warning (was raw >= 700).
- NativeAlarmActor upgrades pre-#129 native_alarm_state rows on rehydrate.
- Debug snapshot decode restores Condition.Priority from the row's priority.
- Docs: Commons, DCL, SiteRuntime, Communication, CentralUI, InboundAPI,
  HighLevelReqs, MES alarm-status plan, CLAUDE.md.

Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi
2026-11-12 14:02:54 -05:00

45 lines
2.5 KiB
C#

namespace ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates;
/// <summary>
/// A template-defined binding to a native alarm source: a data connection plus
/// a source reference (OPC UA SourceNode/notifier nodeId, or MxAccess
/// object/area). At deploy time the instance subscribes and mirrors all
/// conditions discovered under the source. Inheritance/lock semantics mirror
/// <see cref="TemplateAlarm"/>.
/// </summary>
public class TemplateNativeAlarmSource
{
/// <summary>Database primary key.</summary>
public int Id { get; set; }
/// <summary>Foreign key to the owning <see cref="Template"/>.</summary>
public int TemplateId { get; set; }
/// <summary>Unique source binding name within the template.</summary>
public string Name { get; set; }
/// <summary>Optional human-readable description.</summary>
public string? Description { get; set; }
/// <summary>Name of the data connection that owns the alarm feed.</summary>
public string ConnectionName { get; set; } = string.Empty;
/// <summary>Source reference (OPC UA SourceNode/notifier nodeId, or MxAccess object/area).</summary>
public string SourceReference { get; set; } = string.Empty;
/// <summary>Optional condition filter; null = mirror all conditions under the source.</summary>
public string? ConditionFilter { get; set; }
/// <summary>
/// When true, every condition mirrored under this binding is MES-reportable
/// (<c>AlarmStateChanged.IsMesReportable</c> / <c>ScriptAlarm.IsMesReportable</c>). Additive to the
/// 900-999 priority-band convention (on <c>ScriptAlarm.Priority</c>, Gitea #129), which still flags a condition on its own. Default false.
/// Overridable per instance via <c>InstanceNativeAlarmSourceOverride.IsMesReportableOverride</c>.
/// </summary>
public bool IsMesReportable { get; set; }
/// <summary>When true, this binding cannot be overridden in derived templates.</summary>
public bool IsLocked { get; set; }
/// <summary>True when copied from a base template and not yet overridden on the derived template.</summary>
public bool IsInherited { get; set; }
/// <summary>Set on a base binding; when true derived templates may not override it.</summary>
public bool LockedInDerived { get; set; }
/// <summary>Initializes a new binding with the specified name.</summary>
/// <param name="name">The unique binding name within the template.</param>
public TemplateNativeAlarmSource(string name) =>
Name = name ?? throw new ArgumentNullException(nameof(name));
}