feat(alarms): HiLo trigger type with per-band level, hysteresis, messages, overrides
Adds a new HiLo alarm trigger type with four configurable setpoints
(LoLo / Lo / Hi / HiHi). Each setpoint carries an optional priority,
deadband (for hysteresis), and operator message. The site runtime emits
AlarmStateChanged with an AlarmLevel field so consumers can differentiate
warning vs critical bands.
Plumbing:
- new AlarmLevel enum + AlarmStateChanged.Level/Message init properties
- AlarmTriggerEditor (Blazor) gets a HiLo render with severity tinting
- AlarmTriggerConfigCodec extracted from the editor for testability
- sitestream.proto carries level + message over gRPC
- SemanticValidator enforces numeric attribute, setpoint ordering,
non-negative deadband
- on-trigger scripts get an Alarm global (Name/Level/Priority/Message)
so notification routing can branch by severity
- per-instance InstanceAlarmOverride entity + EF migration + flattening
step + CLI commands; HiLo overrides merge setpoint-by-setpoint, binary
types whole-replace
- DebugView shows a Level badge + per-band message tooltip
- App.razor auto-reloads on permanent Blazor circuit failure
- docker/regen-proto.sh automates the proto regen workflow (the linux/arm64
protoc segfault means generated files are checked in for now)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// <auto-generated>
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: sitestream.proto
|
||||
// source: Protos/sitestream.proto
|
||||
// </auto-generated>
|
||||
#pragma warning disable 1591, 0612, 3021, 8981
|
||||
#region Designer generated code
|
||||
@@ -11,11 +11,11 @@ using pbr = global::Google.Protobuf.Reflection;
|
||||
using scg = global::System.Collections.Generic;
|
||||
namespace ScadaLink.Communication.Grpc {
|
||||
|
||||
/// <summary>Holder for reflection information generated from sitestream.proto</summary>
|
||||
/// <summary>Holder for reflection information generated from Protos/sitestream.proto</summary>
|
||||
public static partial class SitestreamReflection {
|
||||
|
||||
#region Descriptor
|
||||
/// <summary>File descriptor for sitestream.proto</summary>
|
||||
/// <summary>File descriptor for Protos/sitestream.proto</summary>
|
||||
public static pbr::FileDescriptor Descriptor {
|
||||
get { return descriptor; }
|
||||
}
|
||||
@@ -24,36 +24,41 @@ namespace ScadaLink.Communication.Grpc {
|
||||
static SitestreamReflection() {
|
||||
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||
string.Concat(
|
||||
"ChBzaXRlc3RyZWFtLnByb3RvEgpzaXRlc3RyZWFtGh9nb29nbGUvcHJvdG9i",
|
||||
"dWYvdGltZXN0YW1wLnByb3RvIk0KFUluc3RhbmNlU3RyZWFtUmVxdWVzdBIW",
|
||||
"Cg5jb3JyZWxhdGlvbl9pZBgBIAEoCRIcChRpbnN0YW5jZV91bmlxdWVfbmFt",
|
||||
"ZRgCIAEoCSKoAQoPU2l0ZVN0cmVhbUV2ZW50EhYKDmNvcnJlbGF0aW9uX2lk",
|
||||
"GAEgASgJEj0KEWF0dHJpYnV0ZV9jaGFuZ2VkGAIgASgLMiAuc2l0ZXN0cmVh",
|
||||
"bS5BdHRyaWJ1dGVWYWx1ZVVwZGF0ZUgAEjUKDWFsYXJtX2NoYW5nZWQYAyAB",
|
||||
"KAsyHC5zaXRlc3RyZWFtLkFsYXJtU3RhdGVVcGRhdGVIAEIHCgVldmVudCLI",
|
||||
"AQoUQXR0cmlidXRlVmFsdWVVcGRhdGUSHAoUaW5zdGFuY2VfdW5pcXVlX25h",
|
||||
"bWUYASABKAkSFgoOYXR0cmlidXRlX3BhdGgYAiABKAkSFgoOYXR0cmlidXRl",
|
||||
"X25hbWUYAyABKAkSDQoFdmFsdWUYBCABKAkSJAoHcXVhbGl0eRgFIAEoDjIT",
|
||||
"LnNpdGVzdHJlYW0uUXVhbGl0eRItCgl0aW1lc3RhbXAYBiABKAsyGi5nb29n",
|
||||
"bGUucHJvdG9idWYuVGltZXN0YW1wIrABChBBbGFybVN0YXRlVXBkYXRlEhwK",
|
||||
"FGluc3RhbmNlX3VuaXF1ZV9uYW1lGAEgASgJEhIKCmFsYXJtX25hbWUYAiAB",
|
||||
"KAkSKQoFc3RhdGUYAyABKA4yGi5zaXRlc3RyZWFtLkFsYXJtU3RhdGVFbnVt",
|
||||
"EhAKCHByaW9yaXR5GAQgASgFEi0KCXRpbWVzdGFtcBgFIAEoCzIaLmdvb2ds",
|
||||
"ZS5wcm90b2J1Zi5UaW1lc3RhbXAqXAoHUXVhbGl0eRIXChNRVUFMSVRZX1VO",
|
||||
"U1BFQ0lGSUVEEAASEAoMUVVBTElUWV9HT09EEAESFQoRUVVBTElUWV9VTkNF",
|
||||
"UlRBSU4QAhIPCgtRVUFMSVRZX0JBRBADKl0KDkFsYXJtU3RhdGVFbnVtEhsK",
|
||||
"F0FMQVJNX1NUQVRFX1VOU1BFQ0lGSUVEEAASFgoSQUxBUk1fU1RBVEVfTk9S",
|
||||
"TUFMEAESFgoSQUxBUk1fU1RBVEVfQUNUSVZFEAIyagoRU2l0ZVN0cmVhbVNl",
|
||||
"cnZpY2USVQoRU3Vic2NyaWJlSW5zdGFuY2USIS5zaXRlc3RyZWFtLkluc3Rh",
|
||||
"bmNlU3RyZWFtUmVxdWVzdBobLnNpdGVzdHJlYW0uU2l0ZVN0cmVhbUV2ZW50",
|
||||
"MAFCH6oCHFNjYWRhTGluay5Db21tdW5pY2F0aW9uLkdycGNiBnByb3RvMw=="));
|
||||
"ChdQcm90b3Mvc2l0ZXN0cmVhbS5wcm90bxIKc2l0ZXN0cmVhbRofZ29vZ2xl",
|
||||
"L3Byb3RvYnVmL3RpbWVzdGFtcC5wcm90byJNChVJbnN0YW5jZVN0cmVhbVJl",
|
||||
"cXVlc3QSFgoOY29ycmVsYXRpb25faWQYASABKAkSHAoUaW5zdGFuY2VfdW5p",
|
||||
"cXVlX25hbWUYAiABKAkiqAEKD1NpdGVTdHJlYW1FdmVudBIWCg5jb3JyZWxh",
|
||||
"dGlvbl9pZBgBIAEoCRI9ChFhdHRyaWJ1dGVfY2hhbmdlZBgCIAEoCzIgLnNp",
|
||||
"dGVzdHJlYW0uQXR0cmlidXRlVmFsdWVVcGRhdGVIABI1Cg1hbGFybV9jaGFu",
|
||||
"Z2VkGAMgASgLMhwuc2l0ZXN0cmVhbS5BbGFybVN0YXRlVXBkYXRlSABCBwoF",
|
||||
"ZXZlbnQiyAEKFEF0dHJpYnV0ZVZhbHVlVXBkYXRlEhwKFGluc3RhbmNlX3Vu",
|
||||
"aXF1ZV9uYW1lGAEgASgJEhYKDmF0dHJpYnV0ZV9wYXRoGAIgASgJEhYKDmF0",
|
||||
"dHJpYnV0ZV9uYW1lGAMgASgJEg0KBXZhbHVlGAQgASgJEiQKB3F1YWxpdHkY",
|
||||
"BSABKA4yEy5zaXRlc3RyZWFtLlF1YWxpdHkSLQoJdGltZXN0YW1wGAYgASgL",
|
||||
"MhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcCLsAQoQQWxhcm1TdGF0ZVVw",
|
||||
"ZGF0ZRIcChRpbnN0YW5jZV91bmlxdWVfbmFtZRgBIAEoCRISCgphbGFybV9u",
|
||||
"YW1lGAIgASgJEikKBXN0YXRlGAMgASgOMhouc2l0ZXN0cmVhbS5BbGFybVN0",
|
||||
"YXRlRW51bRIQCghwcmlvcml0eRgEIAEoBRItCgl0aW1lc3RhbXAYBSABKAsy",
|
||||
"Gi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEikKBWxldmVsGAYgASgOMhou",
|
||||
"c2l0ZXN0cmVhbS5BbGFybUxldmVsRW51bRIPCgdtZXNzYWdlGAcgASgJKlwK",
|
||||
"B1F1YWxpdHkSFwoTUVVBTElUWV9VTlNQRUNJRklFRBAAEhAKDFFVQUxJVFlf",
|
||||
"R09PRBABEhUKEVFVQUxJVFlfVU5DRVJUQUlOEAISDwoLUVVBTElUWV9CQUQQ",
|
||||
"AypdCg5BbGFybVN0YXRlRW51bRIbChdBTEFSTV9TVEFURV9VTlNQRUNJRklF",
|
||||
"RBAAEhYKEkFMQVJNX1NUQVRFX05PUk1BTBABEhYKEkFMQVJNX1NUQVRFX0FD",
|
||||
"VElWRRACKoUBCg5BbGFybUxldmVsRW51bRIUChBBTEFSTV9MRVZFTF9OT05F",
|
||||
"EAASEwoPQUxBUk1fTEVWRUxfTE9XEAESFwoTQUxBUk1fTEVWRUxfTE9XX0xP",
|
||||
"VxACEhQKEEFMQVJNX0xFVkVMX0hJR0gQAxIZChVBTEFSTV9MRVZFTF9ISUdI",
|
||||
"X0hJR0gQBDJqChFTaXRlU3RyZWFtU2VydmljZRJVChFTdWJzY3JpYmVJbnN0",
|
||||
"YW5jZRIhLnNpdGVzdHJlYW0uSW5zdGFuY2VTdHJlYW1SZXF1ZXN0Ghsuc2l0",
|
||||
"ZXN0cmVhbS5TaXRlU3RyZWFtRXZlbnQwAUIfqgIcU2NhZGFMaW5rLkNvbW11",
|
||||
"bmljYXRpb24uR3JwY2IGcHJvdG8z"));
|
||||
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||
new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, },
|
||||
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::ScadaLink.Communication.Grpc.Quality), typeof(global::ScadaLink.Communication.Grpc.AlarmStateEnum), }, null, new pbr::GeneratedClrTypeInfo[] {
|
||||
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::ScadaLink.Communication.Grpc.Quality), typeof(global::ScadaLink.Communication.Grpc.AlarmStateEnum), typeof(global::ScadaLink.Communication.Grpc.AlarmLevelEnum), }, null, new pbr::GeneratedClrTypeInfo[] {
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.InstanceStreamRequest), global::ScadaLink.Communication.Grpc.InstanceStreamRequest.Parser, new[]{ "CorrelationId", "InstanceUniqueName" }, null, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.SiteStreamEvent), global::ScadaLink.Communication.Grpc.SiteStreamEvent.Parser, new[]{ "CorrelationId", "AttributeChanged", "AlarmChanged" }, new[]{ "Event" }, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.AttributeValueUpdate), global::ScadaLink.Communication.Grpc.AttributeValueUpdate.Parser, new[]{ "InstanceUniqueName", "AttributePath", "AttributeName", "Value", "Quality", "Timestamp" }, null, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.AlarmStateUpdate), global::ScadaLink.Communication.Grpc.AlarmStateUpdate.Parser, new[]{ "InstanceUniqueName", "AlarmName", "State", "Priority", "Timestamp" }, null, null, null, null)
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::ScadaLink.Communication.Grpc.AlarmStateUpdate), global::ScadaLink.Communication.Grpc.AlarmStateUpdate.Parser, new[]{ "InstanceUniqueName", "AlarmName", "State", "Priority", "Timestamp", "Level", "Message" }, null, null, null, null)
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
@@ -73,6 +78,19 @@ namespace ScadaLink.Communication.Grpc {
|
||||
[pbr::OriginalName("ALARM_STATE_ACTIVE")] AlarmStateActive = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Severity level for an active alarm. Binary trigger types (ValueMatch,
|
||||
/// RangeViolation, RateOfChange) always emit ALARM_LEVEL_NONE. The HiLo
|
||||
/// trigger type emits one of the directional values.
|
||||
/// </summary>
|
||||
public enum AlarmLevelEnum {
|
||||
[pbr::OriginalName("ALARM_LEVEL_NONE")] AlarmLevelNone = 0,
|
||||
[pbr::OriginalName("ALARM_LEVEL_LOW")] AlarmLevelLow = 1,
|
||||
[pbr::OriginalName("ALARM_LEVEL_LOW_LOW")] AlarmLevelLowLow = 2,
|
||||
[pbr::OriginalName("ALARM_LEVEL_HIGH")] AlarmLevelHigh = 3,
|
||||
[pbr::OriginalName("ALARM_LEVEL_HIGH_HIGH")] AlarmLevelHighHigh = 4,
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Messages
|
||||
@@ -1074,6 +1092,8 @@ namespace ScadaLink.Communication.Grpc {
|
||||
state_ = other.state_;
|
||||
priority_ = other.priority_;
|
||||
timestamp_ = other.timestamp_ != null ? other.timestamp_.Clone() : null;
|
||||
level_ = other.level_;
|
||||
message_ = other.message_;
|
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
|
||||
}
|
||||
|
||||
@@ -1143,6 +1163,36 @@ namespace ScadaLink.Communication.Grpc {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "level" field.</summary>
|
||||
public const int LevelFieldNumber = 6;
|
||||
private global::ScadaLink.Communication.Grpc.AlarmLevelEnum level_ = global::ScadaLink.Communication.Grpc.AlarmLevelEnum.AlarmLevelNone;
|
||||
/// <summary>
|
||||
/// ALARM_LEVEL_NONE for binary trigger types; set by HiLo.
|
||||
/// </summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public global::ScadaLink.Communication.Grpc.AlarmLevelEnum Level {
|
||||
get { return level_; }
|
||||
set {
|
||||
level_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "message" field.</summary>
|
||||
public const int MessageFieldNumber = 7;
|
||||
private string message_ = "";
|
||||
/// <summary>
|
||||
/// Optional per-band operator message; empty when unset.
|
||||
/// </summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public string Message {
|
||||
get { return message_; }
|
||||
set {
|
||||
message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override bool Equals(object other) {
|
||||
@@ -1163,6 +1213,8 @@ namespace ScadaLink.Communication.Grpc {
|
||||
if (State != other.State) return false;
|
||||
if (Priority != other.Priority) return false;
|
||||
if (!object.Equals(Timestamp, other.Timestamp)) return false;
|
||||
if (Level != other.Level) return false;
|
||||
if (Message != other.Message) return false;
|
||||
return Equals(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
@@ -1175,6 +1227,8 @@ namespace ScadaLink.Communication.Grpc {
|
||||
if (State != global::ScadaLink.Communication.Grpc.AlarmStateEnum.AlarmStateUnspecified) hash ^= State.GetHashCode();
|
||||
if (Priority != 0) hash ^= Priority.GetHashCode();
|
||||
if (timestamp_ != null) hash ^= Timestamp.GetHashCode();
|
||||
if (Level != global::ScadaLink.Communication.Grpc.AlarmLevelEnum.AlarmLevelNone) hash ^= Level.GetHashCode();
|
||||
if (Message.Length != 0) hash ^= Message.GetHashCode();
|
||||
if (_unknownFields != null) {
|
||||
hash ^= _unknownFields.GetHashCode();
|
||||
}
|
||||
@@ -1213,6 +1267,14 @@ namespace ScadaLink.Communication.Grpc {
|
||||
output.WriteRawTag(42);
|
||||
output.WriteMessage(Timestamp);
|
||||
}
|
||||
if (Level != global::ScadaLink.Communication.Grpc.AlarmLevelEnum.AlarmLevelNone) {
|
||||
output.WriteRawTag(48);
|
||||
output.WriteEnum((int) Level);
|
||||
}
|
||||
if (Message.Length != 0) {
|
||||
output.WriteRawTag(58);
|
||||
output.WriteString(Message);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(output);
|
||||
}
|
||||
@@ -1243,6 +1305,14 @@ namespace ScadaLink.Communication.Grpc {
|
||||
output.WriteRawTag(42);
|
||||
output.WriteMessage(Timestamp);
|
||||
}
|
||||
if (Level != global::ScadaLink.Communication.Grpc.AlarmLevelEnum.AlarmLevelNone) {
|
||||
output.WriteRawTag(48);
|
||||
output.WriteEnum((int) Level);
|
||||
}
|
||||
if (Message.Length != 0) {
|
||||
output.WriteRawTag(58);
|
||||
output.WriteString(Message);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(ref output);
|
||||
}
|
||||
@@ -1268,6 +1338,12 @@ namespace ScadaLink.Communication.Grpc {
|
||||
if (timestamp_ != null) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Timestamp);
|
||||
}
|
||||
if (Level != global::ScadaLink.Communication.Grpc.AlarmLevelEnum.AlarmLevelNone) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Level);
|
||||
}
|
||||
if (Message.Length != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(Message);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
size += _unknownFields.CalculateSize();
|
||||
}
|
||||
@@ -1298,6 +1374,12 @@ namespace ScadaLink.Communication.Grpc {
|
||||
}
|
||||
Timestamp.MergeFrom(other.Timestamp);
|
||||
}
|
||||
if (other.Level != global::ScadaLink.Communication.Grpc.AlarmLevelEnum.AlarmLevelNone) {
|
||||
Level = other.Level;
|
||||
}
|
||||
if (other.Message.Length != 0) {
|
||||
Message = other.Message;
|
||||
}
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
@@ -1340,6 +1422,14 @@ namespace ScadaLink.Communication.Grpc {
|
||||
input.ReadMessage(Timestamp);
|
||||
break;
|
||||
}
|
||||
case 48: {
|
||||
Level = (global::ScadaLink.Communication.Grpc.AlarmLevelEnum) input.ReadEnum();
|
||||
break;
|
||||
}
|
||||
case 58: {
|
||||
Message = input.ReadString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1382,6 +1472,14 @@ namespace ScadaLink.Communication.Grpc {
|
||||
input.ReadMessage(Timestamp);
|
||||
break;
|
||||
}
|
||||
case 48: {
|
||||
Level = (global::ScadaLink.Communication.Grpc.AlarmLevelEnum) input.ReadEnum();
|
||||
break;
|
||||
}
|
||||
case 58: {
|
||||
Message = input.ReadString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user