diff --git a/docs/AlarmClientDiscovery.md b/docs/AlarmClientDiscovery.md index 24045cd..74b87e5 100644 --- a/docs/AlarmClientDiscovery.md +++ b/docs/AlarmClientDiscovery.md @@ -236,6 +236,39 @@ omits `InitializeConsumer` entirely — that's a bug fix to apply even before A.2 lands, since without it the provider chain never becomes visible. +## Subscribe-parameter sweep — fifth probe run, 2026-05-01 + +Even with `InitializeConsumer` + provider visible at status 100, +no alarm transitions arrived during a 60s window with the user's +script flipping the test bool every 10s. Tried: + +- `qtSummary` and `qtHistory` (the only `eQueryType` values). +- Priority 1..999 and 0..32767. +- `eAlarmFilterState.asNone` and `asAlarmActiveNow` for both + `FilterMask` and `FilterSpecification`. + +`eAlarmFilterState` is single-state-valued (asNone=0, +asAlarmActiveNow=1, asAlarmAcked=2, asShelved=3), not flag bits. +None of these knobs surfaced any alarm activity. + +User confirmation 2026-05-01: the test bool does have a +`BoolAlarm` extension on it; in `aaObjectViewer` the +`$Alarm.InAlarm` sub-attribute flips true/false in lockstep with +the script's writes. So the alarm extension is **evaluating** +its condition, just not visibly producing transitions on the +`aaAlarmManagedClient` consumer stream. + +This isolates the unknown to the producer-side path — whether +the BoolAlarm extension's "publish to alarm manager" knob is on, +whether the platform is in an alarm area that matches the +consumer's subscription scope, or whether AVEVA has a separate +"events" path the BoolAlarm uses by default that this consumer +doesn't subscribe to. Resolving requires checking the BoolAlarm +extension's config in System Platform IDE (alarm priority, +category, "Active"/"Enabled" flags, alarm-vs-event mode) and +checking whether `aaObjectViewer`'s Active Alarms panel sees the +alarm fire. + ### Implications for A.2 implementation The A.2 PR's value is unmeasurable until at least one alarm diff --git a/src/MxGateway.Worker.Tests/AlarmClientWmProbeTests.cs b/src/MxGateway.Worker.Tests/AlarmClientWmProbeTests.cs index 39f1b04..d139583 100644 --- a/src/MxGateway.Worker.Tests/AlarmClientWmProbeTests.cs +++ b/src/MxGateway.Worker.Tests/AlarmClientWmProbeTests.cs @@ -257,14 +257,38 @@ public sealed class AlarmClientWmProbeTests : IDisposable LogProviders(client, "after Register"); + // Dump the eQueryType enum so we can see what alternatives exist + // beyond qtSummary, in case Summary aggregates and we need a + // List/Snapshot mode instead. + try + { + Type qt = typeof(eQueryType); + Log($"eQueryType enum values: " + + string.Join(", ", Enum.GetNames(qt).Select(n => + $"{n}=0x{Convert.ToInt32(Enum.Parse(qt, n)):X}"))); + Type af = typeof(eAlarmFilterState); + Log($"eAlarmFilterState enum values: " + + string.Join(", ", Enum.GetNames(af).Select(n => + $"{n}=0x{Convert.ToInt32(Enum.Parse(af, n)):X}"))); + } + catch (Exception ex) + { + Log($"Enum dump threw: {ex.Message}"); + } + + // qtHistory + state=ActiveNow: stream historical alarm transitions + // including active alarms. asNone for FilterMask/Spec might + // literally mean "match alarms in state 'none'" (i.e., nothing), + // since the eAlarmFilterState enum is 0/1/2/3 single-states not + // flag bits. Try ActiveNow explicitly. int subscribe = client.Subscribe( szSubscription: SubscriptionExpression, - wFromPri: 1, wToPri: 999, - QueryType: eQueryType.qtSummary, + wFromPri: 0, wToPri: short.MaxValue, + QueryType: eQueryType.qtHistory, SortFlags: eSortFlags.sfReturnNewestFirst, - FilterMask: eAlarmFilterState.asNone, - FilterSpecification: eAlarmFilterState.asNone); - Log($"Subscribe('{SubscriptionExpression}') -> {subscribe}"); + FilterMask: eAlarmFilterState.asAlarmActiveNow, + FilterSpecification: eAlarmFilterState.asAlarmActiveNow); + Log($"Subscribe('{SubscriptionExpression}', qtHistory, state=ActiveNow, pri=[0..32767]) -> {subscribe}"); LogProviders(client, "after Subscribe");