Run Script Periodically While Component or Window is Active

I have a script that executes when a specific tab is selected on a popup window that will populate a dataset based on values from two different arrays and then I have a table object linked to this dataset.

This script works just fine, but I want the tables data to be updated when the user is sitting on this page and looking at the table data. Is there a way to update the data in the table every second or two while the table is being displayed? I don't need this script to execute all the time, just when they are viewing the table.

The reason I want to execute this periodically is that this is a list of motor interlocks and its possible that the status of these interlocks will change (which will change array data) in the PLC while they are looking at the table and I want them to be aware of that data change.

The script I am running on the tabstrip property change is as follows: (Note this is in vision)

counter = 0

headers = ["Status", "Description"]
data = []

while counter < 64:
	if event.source.selectedTab != "Interlocks":
		break
	if event.source.parent.Valve.InterlockDatasets.DatasetDescription[counter] != "":
		data.append([event.source.parent.Valve.InterlockDatasets.DatasetStatus[counter], event.source.parent.Valve.InterlockDatasets.DatasetDescription[counter]])
	counter += 1
	
if counter >= 1:
	event.source.parent.getComponent('Interlocks Group').getComponent('InterlocksTable').data = system.dataset.toDataSet(headers, data)

Hi Kyle, welcome to the forums!

First a warning: propertyChange scripts will fire when any bindable property changes. So, be sure to add a filter in your script so that you only run on the property changes you want. :wink:

For a two-second trigger, I would add a custom property to the tab strip (I'll use 'trigger' for an example).
image

Bind the trigger property to an expression. For two secconds, something like this should work. It takes the modulus of the current second, and sees if it's divisible by 2:

(getSecond(now()) % 2) = 0

Then in the script, add your filter to run and the conditions you want. Note that I modified your code a bit to make it more 'pythonic', but that gets more into picking at nits. The comment lines should help (I hope) explain it. The filter line at the top remains the same either way.

# Check that we're on the correct tab, that the trigger property fired, and that it's true.
# Otherwise it would fire once for true, then another time for false. 
if event.source.selectedTab == "Interlocks" and event.propertyName == 'trigger' and event.newValue:
	
	# If you use a path more than twice, you should probably make an object out the path.
	# It will make your code more readable later on.
	InterlockDS = event.source.parent.Valve.InterlockDatasets
	
	headers = ["Status", "Description"]
	data = []

	# The pythonic way for a loop. ;)
	for counter in range(64):
		if InterlockDS.DatasetDescription[counter] != "":
			data.append([InterlockDS.DatasetStatus[counter], InterlockDS.DatasetDescription[counter]])
	
	event.source.parent.getComponent('Interlocks Group').getComponent('InterlocksTable').data = system.dataset.toDataSet(headers, data)

You can read more about the event properties here:

3 Likes

Are you sure this actually works? What's the data type of the custom property?
If it's a dataset, you're only supplying a row index, so I would expect your code to either fail outright (because you can only retrieve an entire row of a PyDataset) or at best, to never actually be working (because a dataset row will never be an empty string).

Thanks Jordan! I really appreciate the help. It makes a lot of sense the way you have explained it.

First time ignition user so I have a lot of learning to do and I've never used python code before (more of a PLC programmer to be honest), been trying to search through existing forum posts as much as I can but couldn't seem to find a similar post in this case.

It does work. The "DatasetDescription" tag is a string array type, so it only has the one dimension (poor choice of name I know). Essentially what I was trying to accomplish with the script is take one array of bools and another array of strings and then form a dataset using those two arrays. I was hoping that I could just use a derived dataset tag and then link its source property to the two arrays directly, but I couldn't figure out how to do that....

1 Like

You'd probably be better off using bindings. The way I do my interlocks is I have a template for my interlocks that show the status, first out, etc, but I pass in an index number and a tag path to the template so it indirectly references/binds to those tags based on the index number so they update live rather than using any scripting to refresh a dataset.

Edit: Guess I should say that I use a template repeater to repeat that template easily using a dataset of the parameters.

1 Like