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:
@@ -98,6 +98,44 @@ public class SiteStreamGrpcClientTests
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AlarmLevelEnum.AlarmLevelNone, AlarmLevel.None)]
|
||||
[InlineData(AlarmLevelEnum.AlarmLevelLow, AlarmLevel.Low)]
|
||||
[InlineData(AlarmLevelEnum.AlarmLevelLowLow, AlarmLevel.LowLow)]
|
||||
[InlineData(AlarmLevelEnum.AlarmLevelHigh, AlarmLevel.High)]
|
||||
[InlineData(AlarmLevelEnum.AlarmLevelHighHigh, AlarmLevel.HighHigh)]
|
||||
public void MapAlarmLevel_AllValues(AlarmLevelEnum input, AlarmLevel expected)
|
||||
{
|
||||
var result = SiteStreamGrpcClient.MapAlarmLevel(input);
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConvertToDomainEvent_AlarmChanged_PreservesLevel()
|
||||
{
|
||||
// Round-trip: a HiLo alarm emitted at HighHigh must come through with Level intact.
|
||||
var evt = new SiteStreamEvent
|
||||
{
|
||||
CorrelationId = "test",
|
||||
AlarmChanged = new AlarmStateUpdate
|
||||
{
|
||||
InstanceUniqueName = "Pump1",
|
||||
AlarmName = "TempAlarm",
|
||||
State = AlarmStateEnum.AlarmStateActive,
|
||||
Priority = 900,
|
||||
Timestamp = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow),
|
||||
Level = AlarmLevelEnum.AlarmLevelHighHigh
|
||||
}
|
||||
};
|
||||
|
||||
var domain = SiteStreamGrpcClient.ConvertToDomainEvent(evt) as AlarmStateChanged;
|
||||
|
||||
Assert.NotNull(domain);
|
||||
Assert.Equal(AlarmState.Active, domain.State);
|
||||
Assert.Equal(AlarmLevel.HighHigh, domain.Level);
|
||||
Assert.Equal(900, domain.Priority);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Unsubscribe_CancelsSubscription()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user