feat(commons): native alarm source entities + ResolvedNativeAlarmSource
This commit is contained in:
@@ -22,6 +22,8 @@ public class Instance
|
||||
public ICollection<InstanceAlarmOverride> AlarmOverrides { get; set; } = new List<InstanceAlarmOverride>();
|
||||
/// <summary>Data-connection bindings that map template tags to site data sources.</summary>
|
||||
public ICollection<InstanceConnectionBinding> ConnectionBindings { get; set; } = new List<InstanceConnectionBinding>();
|
||||
/// <summary>Per-instance overrides of template-defined native alarm source bindings.</summary>
|
||||
public ICollection<InstanceNativeAlarmSourceOverride> NativeAlarmSourceOverrides { get; set; } = new List<InstanceNativeAlarmSourceOverride>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance with the required unique name.
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
namespace ZB.MOM.WW.ScadaBridge.Commons.Entities.Instances;
|
||||
|
||||
/// <summary>
|
||||
/// Per-instance override of a template-defined native alarm source. The source
|
||||
/// reference is the field that varies per physical instance (Tank01 vs Tank02),
|
||||
/// so per-instance override is the common case. Mirrors
|
||||
/// <c>InstanceAlarmOverride</c>; a null override field leaves the inherited
|
||||
/// value unchanged.
|
||||
/// </summary>
|
||||
public class InstanceNativeAlarmSourceOverride
|
||||
{
|
||||
/// <summary>Primary key.</summary>
|
||||
public int Id { get; set; }
|
||||
/// <summary>Foreign key to the owning instance.</summary>
|
||||
public int InstanceId { get; set; }
|
||||
/// <summary>
|
||||
/// Canonical name of the native alarm source being overridden — matches
|
||||
/// <c>ResolvedNativeAlarmSource.CanonicalName</c> after flattening.
|
||||
/// </summary>
|
||||
public string SourceCanonicalName { get; set; }
|
||||
/// <summary>Overrides the connection name when set; null = keep inherited.</summary>
|
||||
public string? ConnectionNameOverride { get; set; }
|
||||
/// <summary>Overrides the source reference when set; null = keep inherited.</summary>
|
||||
public string? SourceReferenceOverride { get; set; }
|
||||
/// <summary>Overrides the condition filter when set; null = keep inherited.</summary>
|
||||
public string? ConditionFilterOverride { get; set; }
|
||||
|
||||
/// <summary>Initializes a new override for the specified source binding.</summary>
|
||||
/// <param name="sourceCanonicalName">Canonical name of the source to override.</param>
|
||||
public InstanceNativeAlarmSourceOverride(string sourceCanonicalName) =>
|
||||
SourceCanonicalName = sourceCanonicalName ?? throw new ArgumentNullException(nameof(sourceCanonicalName));
|
||||
}
|
||||
@@ -38,6 +38,11 @@ public class Template
|
||||
/// Collection of compositions defined in this template.
|
||||
/// </summary>
|
||||
public ICollection<TemplateComposition> Compositions { get; set; } = new List<TemplateComposition>();
|
||||
/// <summary>
|
||||
/// Collection of native alarm source bindings defined in this template
|
||||
/// (read-only mirrors of OPC UA A&C / MxAccess Gateway alarm feeds).
|
||||
/// </summary>
|
||||
public ICollection<TemplateNativeAlarmSource> NativeAlarmSources { get; set; } = new List<TemplateNativeAlarmSource>();
|
||||
|
||||
/// <summary>
|
||||
/// True when this template was auto-derived to back a TemplateComposition
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
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, 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));
|
||||
}
|
||||
@@ -23,6 +23,8 @@ public sealed record FlattenedConfiguration
|
||||
public IReadOnlyList<ResolvedAlarm> Alarms { get; init; } = [];
|
||||
/// <summary>Gets the resolved scripts.</summary>
|
||||
public IReadOnlyList<ResolvedScript> Scripts { get; init; } = [];
|
||||
/// <summary>Gets the resolved native alarm source bindings.</summary>
|
||||
public IReadOnlyList<ResolvedNativeAlarmSource> NativeAlarmSources { get; init; } = [];
|
||||
/// <summary>Gets the UTC timestamp when this configuration was generated.</summary>
|
||||
public DateTimeOffset GeneratedAtUtc { get; init; } = DateTimeOffset.UtcNow;
|
||||
|
||||
@@ -125,6 +127,25 @@ public sealed record ResolvedAlarm
|
||||
public string Source { get; init; } = "Template";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A fully resolved native alarm source binding (data connection + source
|
||||
/// reference). Conditions under the source are discovered at runtime; this
|
||||
/// record only carries the binding, not individual alarms.
|
||||
/// </summary>
|
||||
public sealed record ResolvedNativeAlarmSource
|
||||
{
|
||||
/// <summary>Gets the path-qualified canonical name.</summary>
|
||||
public string CanonicalName { get; init; } = string.Empty;
|
||||
/// <summary>Gets the data connection name that owns the alarm feed.</summary>
|
||||
public string ConnectionName { get; init; } = string.Empty;
|
||||
/// <summary>Gets the source reference (OPC UA SourceNode/notifier nodeId, or MxAccess object/area).</summary>
|
||||
public string SourceReference { get; init; } = string.Empty;
|
||||
/// <summary>Gets the optional condition filter; null = mirror all conditions under the source.</summary>
|
||||
public string? ConditionFilter { get; init; }
|
||||
/// <summary>Gets the source of this binding: "Template", "Inherited", "Composed", or "Override".</summary>
|
||||
public string Source { get; init; } = "Template";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A fully resolved script with code, trigger config, parameters, and return definition.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Flattening;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.Commons.Tests.Entities;
|
||||
|
||||
public class NativeAlarmSourceEntityTests
|
||||
{
|
||||
[Fact]
|
||||
public void TemplateNativeAlarmSource_RequiresName()
|
||||
{
|
||||
var s = new TemplateNativeAlarmSource("PressureMon") { ConnectionName = "Plant", SourceReference = "ns=2;s=P1" };
|
||||
Assert.Equal("PressureMon", s.Name);
|
||||
Assert.False(s.IsLocked);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FlattenedConfiguration_HasNativeAlarmSourcesDefaultEmpty()
|
||||
{
|
||||
var f = new FlattenedConfiguration();
|
||||
Assert.Empty(f.NativeAlarmSources);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolvedNativeAlarmSource_DefaultsSourceTemplate()
|
||||
{
|
||||
var r = new ResolvedNativeAlarmSource { CanonicalName = "PressureMon", ConnectionName = "Plant", SourceReference = "ns=2;s=P1" };
|
||||
Assert.Equal("Template", r.Source);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user