Is there a better way to do this? I feel like I made this more difficult than it needed to be. I needed to be able to write the reset trigger back to False after the counter returned to 0.
I have 3 tags:
Reject - PLC tag
Reject_Counter - Int written to by event meter
Counter_Reset - Trigger to reset the event meter
The following is a script onActionPerformed of a "reset" button in one of my views.
def runAction(self, event):
import time
while True:
system.perspective.print("reading tags")
counter_value = system.tag.readBlocking("[default]Reject_Counter")[0].value
reset_value = system.tag.readBlocking("[default]Counter_Reset")[0].value
system.perspective.print("done reading tags")
# Condition 1: Exit the script if counter is 0 and reset is False
if counter_value == 0 and reset_value == False:
system.perspective.print("Counter is 0 and reset is False. Exiting script.")
return
# Condition 2: If counter is not 0 and reset is not True, write True
if counter_value != 0 and reset_value != True:
system.perspective.print("Counter is not 0 and reset is not True. Writing True to reset_value.")
system.tag.writeBlocking(["[default]Counter_Reset"], [True])
# Condition 3: If counter is 0 and reset is True, write False
if counter_value == 0 and reset_value == True:
system.perspective.print("Counter is 0 and reset is True. Writing False to reset_value.")
system.tag.writeBlocking(["[default]Counter_Reset"], [False])
time.sleep(0.5) # Add a short delay to prevent crash
Don't do this in a button script. Also, don't use while loops in Ignition unless you absolutely have to.
If multiple users hit the reset button then you have this loop (and writes to the tags) fighting. Last one in the queue would win (probably).
Instead:
Only enable the reset button if the counter value is not 0 and the reset tag value is not True. When the user presses the button, only write True to the reset tag.
Have a tag change event script, either on the counter tag or a Gateway Tag Change event script write false to the reset tag on counter tag value change to 0.
Ryan, that is what I was doing, but I was worried about being able to scale it up. I am going to do the same thing for uptime/downtime event meters that run every second. If I ran a value changed script on the time values, and I have a 100 pieces of equipment, I would have 100 scripts running every second.
That is what I was trying to avoid by doing this. I agree the while loop is irresponsible, but it was the only other solution I could come up with.
Gateway Tag Change event would be the way to go with this at that scale. When configured correctly you'd be able to define a single script and have it run against all 100 machines.
Another option (if you don't want to increase gateway load) would be to have the PLC reset the tag after it clears the counter, but that leads to race conditions. You can help mitigate this if you have the PLC wait for a few poll periods before changing the tag value (general rule of thumb is 3x the ignition poll rate)
I'll let others speak on the performance implications of 200 tags with Gateway Tag Change event scripts, but I imagine a simple value check would execute pretty quickly.
Consider not using counter resets. Use non-resetting odometer-style counters instead, and just let them roll over. Record the counters (all of them) at regular intervals (at the top of every minute, perhaps) and you can then get a delta for any time period.
If necessary, add a separate "snapshot" integer tag that you can write the current counter to, and then live subtract from the current count in your UI (not in the PLC) to display the count since the snapshot.
Way more efficient, and cannot lose a count due to communication races.
I like this solution, but I am curious about the gateway performance.
For arguments sake, lets say I must have all 100 runtimes displayed on the view. I would have to read and calculate, either through a binding on the labels, or through dedicated derived tags, each time delta.
If that was the case, would this really relieve any load on the gateway?
(Even if it doesn't, it is still much cleaner than my while loop script on the button.)
The gateway CPU load to run 100 simple expression tags is near trivial. Making a snapshot is simply reading the counters with a single line of code, and the writing the snapshot memory tags with one more line of code.
(The while loop isn't just unclean--it is actively harmful, as it burns CPU.)
Computing deltas from the database is done when you need reports. Just use the snapshots for live displays.