Best way to trigger a script after a time delay without pausing a script

I want to call a script to run based on a boolean tag changing state. When the bit goes low I want to wait 30 seconds and then do some simple math by reading in a value and then writing to a tag. Right now I have a tag event value change script that works great except it does not have the delay in it. What would be the best way to add a delay without essentially pausing the script? Would it be when the bit goes low trigger a secondary tag. That tag would have a script on it to run a timer and after 30 seconds trigger another tag that would actually do the math? Although this kind of seems like the same thing. Suggestions?

import threading

def delayed_function():
    print("This function runs after a 5-second delay.")

# Set the timer
timer = threading.Timer(5.0, delayed_function)
timer.start()
1 Like

I made a UDT that behaves similar to Rockwell's TON/TOF functions. You may find it useful. Or maybe not. :wink:

TimerUDT.json (1.4 KB)

2 Likes

I attempted to do that within a gateway tag change script and the delay portion is not working. It does not seem to be executing the function I have inside the script. Can I not have a function within the overall script? Am I not allowed to have a function within a gateway script like this?

Nice! I have tried the threading.Timer function and it does not execute the delay. It writes the value right away. I think I will use your UDT. When I am ready to start timer turn on the monitor bit. Then I can apply a script on the TON_Flag to set the value to 1!

I tried this and for whatever reason it did not work, although it seems it should! Thanks for pointing this out though!

Using a delay in a script is fraught with peril in Ignition. Jordan's UDT works because it uses the same technique a PLC would: it repeated executes expressions to "see" what it should do/report.

If you cannot use an expression tag that regularly executes, the safe scripting alternative is a repeating (gateway) timer event that reads relevant tags, evaluates the timing logic, and runs the next step when appropriate. No pause/sleep/delay used in the script.

If you absolutely have to schedule something in the future, use the gateway context's scheduler. (But beware: not supported by IA.)

Thanks Phil. Yes I remember I did that a few years ago when I first was programming with Ignition and it freezed the gateway so lesson learned. Not sure why threading.Timer did not work but the timer UDT worked perfect. Thanks for the advice

Because it is a sleep under the hood.

Anyways, using jython stdlib stuff is prone to problems, unless it is very generic. Importing threading is almost always a mistake in Ignition.

There is another solution you may try:

import asyncio

async def delayed_function():
    await asyncio.sleep(5)  # Delays for 5 seconds
    print("This function runs after a 5-second delay.")

async def main():
    # Schedule delayed_function to run after a delay
    await delayed_function()

# Run the async main function
asyncio.run(main())

Really, stop with the ChatGPT ideas. Jython doesn't have async and await keywords.

9 Likes

Hi. I have been avoiding using any pause/sleep/delay by creating delayed alarms and then dealing with the desired reactions in the Tag Event Scripts.

On my systems, I capture almost all tag transitions as an alarm with the priority "Diagnostic". When I want a delayed reaction, I delay the alarm associated with that change (or create a new one) and then write the action in the Alarm Active script.

2 Likes