Show filtered retain in the AlarmCondition sample (#845) - #893
Merged
Merged
Conversation
Part 9 B.1.4 lets a condition report one final event as it leaves the scope of a client's where clause, so that client sees Retain go false even though the server still retains the condition. Nothing in the samples demonstrated it. The alarm sample is where it belongs, and it already had the shape for it: an operator's list which asks only for the alarms that need attention. Server - Every alarm opts in with ConditionState.SupportsFilteredRetain. The flag is not part of the instance child hierarchy - Part 9 provides SupportsFilteredRetain on the ConditionType only - so it is set on the node rather than created from the type model, and a branch gets a copy. - FilteredRetainCapability advertises the Property on the ConditionType node, which is where a client asks whether the server supports the concept. The standard address space ships it false, so a server which does support it has to say so. - SourceState.ConditionRefresh no longer overwrites the handle of the snapshot it replays with the source. A monitored item resolves the condition behind an event through that handle, so nothing a refresh replayed could take part in filtered retain; it only started working once an alarm reported a live event of its own. IsOwnCondition is the marker against replaying one source twice instead. Client - The where clause now leaves out an alarm which is suppressed, shelved or out of service, which is what the sample README always described. That makes it a clause a condition falls out of while the condition itself carries on - the case filtered retain exists for. - The clause is asked only of the alarms. SuppressedOrShelved is declared by AlarmConditionType, and an operand which resolves to nothing makes Equals answer null and the element false, so a bare SuppressedOrShelved == False silently drops every condition which is not an alarm, the OnlineState dialogs of the sample included. - A condition which reports Retain = false leaves the list, as ConditionChange.Removed, and the window drops the row. That covers both an alarm the plant and the operator are done with and the trailing event of one which left this client's filter; the two are deliberately indistinguishable. Suppressing an alarm now takes it out of the list at once instead of leaving a row which stands until the next Refresh. Tests - Node manager: the ConditionType advertises the flag; a suppressed alarm is delivered one last time carrying SuppressedOrShelved = true, which no plain where clause evaluation could have let through, together with Retain = false - and is not delivered again until it comes back into scope. EventCapture gained an overload which takes a where clause next to the standard select clauses. - Client model: suppressing an alarm takes it out of the list without a condition refresh, and unsuppressing puts it back. - SeverityFilterKeepsTheLowerConditionsOut allows a removal to carry a severity the filter rejects: dropping below the threshold is one of the ways out of the where clause. Also fixes an unrelated build break on this branch: the 2.0.312 node manager generator emits a parameterless constructor which chains with a literal null, which was ambiguous with the RuntimeNodeSets sample's own three argument constructor and left SampleNodeManagers.Tests unbuildable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proposed changes
Adds a demonstration of filtered retain (OPC 10000-9, §B.1.4) to the Alarms & Conditions
quickstart. A fitting sample already existed, so this extends
Workshop/AlarmConditionrather than adding a new one.
Filtered retain lets a condition report one final event as it leaves the scope of a client's
where clause, so that client sees
Retaingo false even though the server itself stillretains the condition. Nothing in the samples showed it, and the alarm sample already had the
right shape for it: an operator's list which asks only for the alarms that need attention.
Server
ConditionState.SupportsFilteredRetain. The flag is deliberatelynot part of the instance child hierarchy — Part 9 provides
SupportsFilteredRetainon theConditionTypeonly — so it is set on the node rather than created from the type model,and a branch gets its own copy.
FilteredRetainCapabilitystartup task advertises the Property on theConditionTypenode, which is where a client asks whether the server supports the concept at all. The
standard address space ships it
false, so a server which does support it has to say so.SourceState.ConditionRefreshno longer overwrites the handle of the snapshot it replayswith the source. This was a real defect for this feature: a monitored item resolves the
condition behind an event through that handle, so nothing a refresh replayed could take
part in filtered retain — it only began to work once an alarm reported a live event of its
own.
IsOwnConditionis the marker against replaying one source twice instead.Client
which is what the sample README always described. That is what makes it a clause a
condition falls out of while the condition itself carries on.
SuppressedOrShelvedis declared byAlarmConditionType, and an operand which resolves to nothing makesEqualsanswer nulland the whole element false — so a bare
SuppressedOrShelved == Falsesilently drops everycondition which is not an alarm, the
OnlineStatedialogs of this sample included.Retain = falseleaves the list, asConditionChange.Removed,and the window drops the row. That covers both an alarm the plant and the operator are done
with and the trailing event of one which left this client's filter; the two are
deliberately indistinguishable to the client. Suppressing an alarm now takes it out of the
list at once, instead of leaving a row which stands until the next Refresh.
Tests
ConditionTypeadvertises the flag; a suppressed alarm is deliveredone last time carrying
SuppressedOrShelved = true(which no plain where clause evaluationcould have let through) together with
Retain = false, and is not delivered again until itcomes back into scope.
EventCapturegained an overload which takes a where clause next tothe standard select clauses.
refresh, and unsuppressing puts it back.
SeverityFilterKeepsTheLowerConditionsOutnow allows a removal to carry a severity thefilter rejects: dropping below the threshold is one of the ways out of the where clause.
Documentation: the sample README gained a Filtered retain section, its Things worth
trying items 3 and 4 no longer tell the reader to press Refresh, and
docs/TESTING.mdandthe root README were updated.
Related Issues
Types of changes
Checklist
Further comments
One change is unrelated to #845 and worth a separate look.
masterdid not build againstthe 2.0.312 packages this branch pins: the node manager generator emits a parameterless
constructor which chains with a literal
null, and that was ambiguous with theRuntimeNodeSets sample's own three argument constructor (
CS0121), which leftSampleNodeManagers.Testsunbuildable.Workshop/RuntimeNodeSets/Server/SiteNodeManager.csgains a fourth optional parameter to break the tie. Happy to split it out or drop it if it is
already being fixed elsewhere.
Behaviour change worth flagging: the condition list no longer keeps
Retain = falserowsgreyed out — they leave the list, which is what Part 9 §5.5.2 asks of a client and what makes
filtered retain visible at all. Branches are still shown next to the current state and toned
down.
Local test results, all tiers:
Full-solution build is clean across all target frameworks.
🤖 Generated with Claude Code