Endless error in designer

What is a way to run a script from a label in Vision without using runScript()?

I just had to quit developer (with about 45 mins of work in it) because I tried something similar [runScript in expression tag](Runscript in expression tag) - that’s where I got the idea. Result was an error that kept running and I found no way to stop it. I tried disabling label. I tried deleting script. Error dialog kept incrementing regardless of what I tried.

  1. Dialog that kept counting error rapidly (note bottom (Error 1 out of 951), gaining about 100 per second; found no way to stop this:
  2. Details tab of dialog:
  3. Tried binding this expression to Text field - I don’t know what the 12 is for but it demanded something :-/
  4. Labels to which I tried binding:
    designer_endless_error4
  5. Trying to backtrack, I deleted script from project scope & moved it to shared, to no effect.
    designer_endless_error5

I didn’t know if saving project would cause this to come back to bite me when I reopened, so I decided to quit knowing will lose a lot of work. Oh well.

Below is what I’m trying to accomplish.


What I want to do is run the following script for each label (#3 above).

# Running inside Script Console, if (1 == 1): fixes indenting so function runs
#def DifferenceLastSixHours (userTag):
userTag = "VP2/Chamber_Pressure"
if (1 == 1):
	endTime = system.date.now()
	startTime = system.date.addMinutes(endTime, -360)
	returnSize = 6
	args = {
		'paths':[userTag],
		'returnFormat':'Wide',
		'startDate':startTime,
		'aggregationMode':'LastValue',
		'endDate':endTime,
		'returnSize':returnSize
	}
	dataSet = system.tag.queryTagHistory(**args)
	out = "n/a"
	for row in range(dataSet.getRowCount()):
	    for col in range(dataSet.getColumnCount()):
    		if (row > 0 and col == 1):
	    		diff = dataSet.getValueAt(row-1, col) - dataSet.getValueAt(row, col)
    			out = "%s, %.02f" % (out,diff)
	print out
#DifferenceLastSixHours("VP2/Chamber_Pressure") - doesn't work; don't know how to keep it a function in Script Console & test it, in situ.

This print “n/a, 0.46, 0.38, 0.41, 0.30, 0.11” in Script Console, which is all I want on the darned label!

But how to do this???

It looks like your call has an error, and it’s being executed every 12 ms.

One thing you could try is passing the parameter to the runScript Expression Function as documented here

runScript(scriptFunction[, pollRate][, args…])

Option 1:

runScript("project.DifferenceLastSixHours('" + "VP2/Thermocoulpe_2" + "')", pollRate)

Option 2:

runScript("project.DifferenceLastSixHours", pollRate, "VP2/Thermocoulpe_2")

Don’t use queryTagHistory() in a runScript() expression. That requires a gateway round trip and will freeze your UI for that round-trip. Use a tag history binding and run the rest of your code in a propertyChange event (on the dataset property receiving the history).

1 Like

Add a custom property to your label. Make it of type Dataset. Place your tag history binding on that custom property. Add a propertyChange event script to your label. Within that script, check for the event.propertyName == “yourCustomPropertyName”, and in that if section, do the rest of your processing. At the end, assign to event.source.text.

Thank you - I’m too new to this for your first answer, but I think I understand the second one, except the “place your tag history binding on that custom property”.

I’m calling historian to get a range of values and then doing some computations on them - the results script outputs don’t exist in the historian, per se.

The tag history binding will place into the custom property the same dataset you’d get from a scripted call to query tag history, but will do it in the background without freezing the UI. When that dataset is delivered, the property will report that it changed, upon which your script can access that fresh dataset to do the rest of the calculations.

12 ms, that explains a lot. I will be more careful to look up all functions since I may loose all my changes in designer again. I was pasting random stuff out of forums trying to get it to work and didn’t think much of it. Thank you.

Ok, I did what you said and it works, but I have no idea why. Is the last line of script that’s doing all the magic?

if (event.propertyName == "text"):
     [do work]
event.source.text = out

I added custom property of type DataSet
custom_property

Ok, now that works too - I didn’t have it in quotes, before.

if (event.propertyName == "dataSet42"):
     [do work]
event.source.text = out

I’m going to have to document this really well as it’s counter-intuitive on all levels :upside_down_face:

Thank you.

No, you don’t want to watch for a change on the text property, you want to watch for the change on the custom property you added. You are going to write to the .text property at the end of the script–no need to watch for that.

One last question. I replicated the label to all the other channels and adjusted the custom property to have an unique name and modified all scripts to watch that property, but all labels are returning same output.

all_the_same

Be sure to indent that final assignment to .text so it only runs on the correct event.

I think I’m doing this, no?

if (event.propertyName == "dataSet1"):
	endTime = system.date.now()
	userTag = "VP2/Thermocouple_2"
	startTime = system.date.addMinutes(endTime, -360)
	returnSize = 6
	args = {
		'paths':[userTag],
		'returnFormat':'Wide',
		'startDate':startTime,
		'aggregationMode':'LastValue',
		'endDate':endTime,
		'returnSize':returnSize
	}
	dataSet = system.tag.queryTagHistory(**args)
	out = "n/a"
	for row in range(dataSet.getRowCount()):
	    for col in range(dataSet.getColumnCount()):
    		if (row > 0 and col == 1):
	    		diff = dataSet.getValueAt(row-1, col) - dataSet.getValueAt(row, col)
    			out = "%s, %.02f" % (out,diff)
	event.source.text = out

In this full clip, yes. In the example above, no.

You also still have a call to system.tag.queryTagHistory. That shouldn't be there. Use event.newValue or event.source.dataSet1.

Hmm. I don’t know where to find those. I must have skipped the this step you recommended “Place your tag history binding on that custom property” - how do I do that?

For now, I got it to work by changing labels’ scripts back to:
if (event.propertyName == “text”):

kinda_working

(for debugging changed out = “n/a” to out = “%s n/a” % userTag)

I think you need to spend some time with Inductive University:

https://www.inductiveuniversity.com/videos/tag-historian-binding/7.9

https://www.inductiveuniversity.com/courses/scripting/7.9#component-scripting

I appreciate the links. I viewed those before but they didn’t make sense to my predicament. This time… I still don’t see where that gets me - how can I avoid system.tag.queryTagHistory()?

Script uses special parameters to system.tag.queryTagHistory() to pull out only single values on the hour going back 6 hours. Then, it subtracts these from “previous” hour’s values to get “difference” (12AM,2.2,1AM,2.0,2AM,1.8) so difference would be 0.2 and 0.2 (to gain insight to rate of change, which is non-linear).

I don’t know how to make that happen WITHOUT using system.tag.queryTagHistory(). Or do you mean that I need to query the slice with system.tag.queryTagHistory(event.return.dataSet1)?

Also, for the slices of history I need (6 hours), I will be copying 2500 rows (of float) for each label ( times 14) - or is Ignition smarter than that? And I have to associate each historical tag with its slice (dataset), instead of just changing a variable in the script. Is that less of a hit than original script?

For now, I will restrict that dialog to just engineer role so operators can’t run it, which will limit it to my instance :slight_smile:

Honestly, I think that what you’re doing will be better suited as a gateway-level task. I generally try to avoid putting logic like this in the client since then those same requests cause duplicative effort at the gateway as you launch additional clients. Instead, consider using a gateway script to periodically compute and write these results to tags, and then simply bind to those tags in the client. It will perform and scale better, and keep the visualization side much simpler (and faster there too).

1 Like

You are calling it once. A history binding can do the same. Place those args on the tag history binding. It will (in the background) call the equivalent query and deliver the dataset to the bound property. The custom property's value will be that dataset. Just run your differencing loops using that property value as the input dataset.

Kevin, so I missed “[t]hat requires a gateway round trip and will freeze your UI for that round-trip” being the source of the penalty in Phil’s original response - thanks for pointing out that moving to gateway is an option to avoid this.

In fact, what brought me back to this forum is that I am now addicted to this (new to me) functionality* and moving these functions to gateway will let me compute data (safely) for others and for triggering higher-level (process-envelope excursion type) alarms.

I am learning about data structures, but will most likely flesh out the screens I need and ask our local integrator to quote implementation - they have been great about teaching me how to reuse & extend new code.

Thank you.

*I inherited several largish systems that are key to our plant, but that were not well understood by their OEMs (very primitive UI, no alarms above OL/OT, useless manuals, etc). I’m looking to make improvements and can’t lean on OEM (staff retired/left); only have data gathered by Ignition, which I get to write, with your invaluable help :slight_smile:

1 Like