invokeAsynchronous on gateway vs tag browser

I am trying to figure out why my invokeAsynchronous works on the tag browser but not on the gateway even thou they are similar logic.

On tag browser:

def valueChanged(tag, tagPath, previousValue, currentValue, initialChange, missedEvents):
	if not initialChange and currentValue.value:
		def foo():
			import time
			for i in range(300):
				if not system.tag.readBlocking("[default]S/C/S")[0].value:
					return
				time.sleep(1)
			system.tag.writeBlocking("[default]S/C/D", True)
		system.util.invokeAsynchronous(lambda:foo())


This works and sets D true after 5 minutes.

On gateway tag change script:

if not initialChange:
	if event.currentValue.value:
		def foo():
			import time
			for i in range(300):
				if not system.tag.readBlocking("[default]S/C/S")[0].value:
					return
				time.sleep(1)
			system.tag.writeBlocking("[default]S/C/D", True)
		system.util.invokeAsynchronous(lambda:foo())

I do enter into the code, however foo never gets called. So D never gets set.

What makes these 2 places different that caused one to work and the other not?

The value changed script’s currentValue is not equivalent to the gateway tag change scripts event.currentValue

Try newValue.value

That being said, I’m not sure what you’re trying to do, but generally speaking any time you’re calling sleep() in ignition your doing something in a less optimal way than it can (read should) be done.

  1. Gateway event scripts (until 8.3) use a 'legacy' scoping rule from an ancient version of Python that doesn't work the way you'd expect when defining inline functions, so your callback is likely not being called. The fix for that particular issue is to make your gateway event scripts immediately call a project library function, where scoping rules make sense.
  2. This syntax: system.util.invokeAsynchronous(lambda:foo()) is pointless. Just: system.util.invokeAsynchronous(foo). Python functions are first class objects and can be passed around directly.
  3. As @lrose mentioned, the actual fix for this would be a gateway timer script. Give it a one second rate. Read the trigger tag(s) for your gateway tag change script first, and only if they meet your condition enter your second set of checks to read the inner tag you're currently reading in a loop.
3 Likes
  1. Don’t ever use sleep()or system.tag.writeBlocking() or any system.opc.* calls in the events scripts directly attached to tags or UDT members. You are extremely likely to lock up tag event processing due to tying up a thread in that event type’s thread pool.
2 Likes

What I am trying to achieve is the first time the tag goes true, wait 5 minutes before setting another tag true. This executes only once only when the tag goes true. If the tag goes false during the 5 minute wait, stop executing and do not set the other tag true.

Add a tag event/tag change script watching the trigger tag.

  • If the tag goes true, write now() + 5 minutes to a separate tag (via an async write).
  • If the tag goes false, clear that timestamp.
  • In a gateway timer script, every 1 second, check whether now() >= theTimestampTag.
2 Likes