Async callbacks in value change event script can't use information from the value change event?

I want to have a UDT with a boolean called Update that has a value change event script which reads and writes from various datasets for use with some power tables.

As it's on the gateway, I want to use asynchronous reads to ensure I don't lock the gateway up.

The issue is that the callback function necessitated by system.tag.readAsync / writeAsync doesn't seem to be able to be given any information when used inside the value change event scope.

This is as opposed to in the script console, on table scripts, etc, anything in the client scope.

def valueChanged(tag, tagPath, previousValue, currentValue, initialChange, missedEvents):
	if currentValue.value:
		udtPath = tagPath[:tagPath.rindex("/")] 
		tagNameArray = [udtPath + '/Tag1',udtPath + '/Tag2']
		system.tag.readAsync(tagNameArray, superTable_InitialCallback)

def superTable_InitialCallback(values):
	#Call a script with some arguments pertaining to the tag itself
	SuperTable_Gateway.superTable_MainCallback(None, values, udtPath)

In the example above, I get an error: global name 'udtPath' is not defined.
OK, so I use tagPath to regenerate udtPath. Still no good; within that callback, even tagPath is unknown.

I tried using a partial function but it's no good; the partial function seems to have nowhere to define it that allows me to slip the arguments in that I'd like to use.

What do I need to do here?

PS The documentation for Ignition is great, especially compared to the competition, but what you can and can't do with callbacks when implemented in various scopes (e.g. in a component script / in a tag change event script / etc) seems to be a bit of a gap.

You can use closure to capture the extra things you need. Build your callback inside the valueChanged function, and you will have access to the variables you need:

def valueChanged(tag, tagPath, previousValue, currentValue, initialChange, missedEvents):
	if currentValue.value:
		udtPath = tagPath[:tagPath.rindex("/")] 
		tagNameArray = [udtPath + '/Tag1',udtPath + '/Tag2']

        def callback(values):
	        #Call a script with some arguments pertaining to the tag itself
            doYourThing(None, values, udtPath)

        system.tag.readAsync(tagNameArray, callback)

3 Likes

Talk about 'closure'. My function got closure and so did I. :laughing: Thank you so much.

1 Like

Also re: the docs, I can see why this is taken for granted as it's implicit in python aye? Although possibly with lots of bumpkin PLC programmers like myself learning this stuff it might make for a good paragraph in the IU training.

Yes. Poorly understood by many python programmers, too.

Not a bad idea.