I am trying to implement a oneshot command where I send a true signal to an OPC tag, maintain it for 2 seconds, then set the signal to false. I've tried many different approaches, including time.sleep(), which I've read is not recommended. How would I go about doing this?
The only reliable way to do this is to use a gateway timer event that repeated examines current conditions (state) to decide what that signal state should be, and write it if not already that state. Typically, you would use a datetime memory tag to hold the desired turn-off timestamp. The code that would normally set that boolean would instead set the timestamp to two seconds in the future. Then the timer script would see that it is supposed to be on, and write that, and then notice when it should turn off, and write that.
If you don't care as much about reliability, you can use timer.
def runAction(self, event):
from threading import Timer
def runLater():
system.tag.writeBlocking([self.view.params.tagPath], [self.view.params.buttonOffValue])
system.tag.writeBlocking([self.view.params.tagPath], [self.view.params.buttonOnValue])
t = Timer(self.view.params.holdTime, runLater)
t.start()
Thank you for the suggesion. This does work, but reliability is important. Any reason why this would not be reliable?
Yes, so currently I have a gateway timer event that sets the tag to 0 every 3 seconds. It works, but is not very elegant, because the duration of the pulse varies based on when you set it to 1 within the timer duration. If I set it to 1 near the end of the 3 second timer, the pulse lasts very short, whereas if I set it to 1 near the beginning, the pulse lasts longer. I kind of understand your explanation, but not quite. Ideally, the timer would be enabled when the pulse rises from 0 to 1
It all depends why you need the timing and what happens if the connection to the device gets interrupted before it resets the tag.
In the scenario I recommend, you'd run the timer event all the time, probably ~100ms interval. Just like a PLC would do with a periodic task.
(If you have many of these, use just one fast timer event for everything.)
If possible you should be resetting the tag in the PLC, 2 seconds after it's toggled on.
Ok I got it working. When I have the HMI send a boolean write signal to the PLC, I like to hold the signal for at least 2 seconds to overcome comms delays. And I do not want to maintain it because of unintended commands going through to the PLC. We could resolve those on the PLC, but I am used to ensuring that the HMI is the side that should correctly handle these signals. So, the HMI should send a true bit, hold it for a set amount of time to overcome comms delays, and then set the bit back to false to ensure that we are not sending signals to the PLC unintentionally.
I am using a gateway timer script like @pturmel recommended. I have it running at 500 ms. But the part of that scripts that sets the bit back to false executes conditionally. So the script runs all the time at 500 ms intervals, but the intended action only takes place under the stipulated condition.
The condition is the value of a timestamp tag. When the bit goes true, I have it also set the timestamp tag to system.date.now(). The gateway script reads the state of the timestamp tag every 500 ms, and if it sees that the value of the timestamp tag is not None, it compares the timestamp tag to system.date.now(). Because the timestamp tag was set to system.date.now() earlier, and is held at that point, comparing the timestamp tag to system.date.now() will result in an increasing timer. When that timer is greater than or equal to 2000 ms, the logic sets the bit to 0. An important step is to also set the timestamp tag to 0.
And that's it. Works great. Basically what @pturmel was saying. Thank you all for the help!
You'll get slight better performance if you set the timestamp tag to the desired turn-off time in the future, so the continual checking doesn't have to do any math--just comparison.
That doesn't necesarily guarantee anything. I'm sure in most cases 2 seconds is way more than enough, but some kind of feedback or handshake is best IMO.