This sounds like a 'first-out' indication. If so, there's a few ways to handle this... though, ideally, it's handled within the logic controller.
Edit: Decided to take a stab at a first-out setup...
In this example, I created 2 tags within their own folders, "Folder1/Tag1", and "Folder2/Tag2". Both are memory tags, boolean, configured to alarm when value == 1. I've manually entered a label on each of the alarms (though, one could certainly bind the label to a tag in the same folder via [.]ID
).
I've also created 3 additional tags, within the parent folder to the above alarm tags:
- Name="sFirst_Out_Enum", Memory Tag, Integer. "s" prefix indicates that tag is written to by a script (my standard), additional insight in Meta Data (Documentation & Tooltip) indicating origin script.
- Name="binEnc_Alarms", Expression Tag, Integer w/ Expression (event driven).
binEnc(
// Create a binary encoded integer, where each bit represents
// an alarm that is active and unacknowledged. Update to suit...
{[.]Folder1/Tag1/Alarms/Alarm.IsActive} && !{[.]Folder1/Tag1/Alarms/Alarm.IsAcked},
{[.]Folder2/Tag2/Alarms/Alarm.IsActive} && !{[.]Folder2/Tag2/Alarms/Alarm.IsAcked}
// Add others as necessary...
)
- This tag also with a script transform (search the forums for tag event scripts, then use your better judgement when deciding to add features. Bottom line: ensure entire script is very fast to execute). Tag Value Changed script which writes the "First-Out Enumeration" to aforementioned memory tag:
def valueChanged(tag, tagPath, previousValue, currentValue, initialChange, missedEvents):
fo_path = "[.]sFirst_Out_Enum" # "s" prefix indicates 'value is written by script'.
# If no alarms are active, output "All Clear" enumeration:
if currentValue.value == 0:
fo_enum = 0
system.tag.writeBlocking([fo_path], [fo_enum])
# If alarm transitions from 0 --> >0, capture and output first-out:
elif previousValue.value == 0 and currentValue.value > 0:
bin_alarm_string = format(currentValue.value, 'b') # Integer --> Binary e.g. 10 --> "1010"
fo_enum = bin_alarm_string[::-1].find("1") + 1 # Reverse string, then return character index of first "1".
system.tag.writeBlocking([fo_path], [fo_enum])
# Previous value was NOT "All Clear", do nothing:
else:
pass
- Name="First_Out_Text", Expression Tag, String. Expression:
case({[.]sFirst_Out_Enum},
0, "All Clear",
// Add alarm labels in same order as binEnc_Alarms tag:
1, {[.]Folder1/Tag1/Alarms/Alarm.Label},
2, {[.]Folder2/Tag2/Alarms/Alarm.Label},
// Add others as necessary...
"Error" // Default value
)
This method should output a first-out enumeration & lookup text for each alarm that is configured. The only tags that need updated when alarms are added are the "binEnc_Alarms" expression and "First_Out_Text" expressions.
Not the most "hands-off" approach, but all logic is contained in a single folder. Can be useful for consistently named tags.