Script weird behavior with system.perspective.openPopup

Hello everyone. I'm facing a weird issue with a script that gives me error only the first time I try to execute it, then it doesn't work also but doesn't show the error again!
The error is:

([edge]Test/MoveToPanelHome/Trigger, valueChanged) Error executing tag event script: Traceback (most recent call last): File "<tagevent:valueChanged>", line 11, in valueChanged File "<module:OPCMethods>", line 63, in callMethod File "<module:OPCMethods>", line 63, in callMethod at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.lambda$operateOnPage$0(AbstractScriptingFunctions.java:64) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnSession(AbstractScriptingFunctions.java:120) at com.inductiveautomation.perspective.gateway.script.AbstractScriptingFunctions.operateOnPage(AbstractScriptingFunctions.java:47) at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.popupAction(PerspectiveScriptingFunctions.java:758) at com.inductiveautomation.perspective.gateway.script.PerspectiveScriptingFunctions.openPopup(PerspectiveScriptingFunctions.java:240) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: No perspective page attached to this thread.

I'm calling a script from project library on a tag value changed, and change the trigger tag using a button in perspective. The scripts are the following sequentially:
First script on the button

def runAction(self, event):
	system.tag.configure("[edge]Test/GetCentroid", [{"name" : "Trigger", "sessionId" : str(self.session.props.id)}], "m")
	system.tag.writeBlocking(["[edge]AB_Test/EP_Job_GetCentroid/Trigger"], [True])

Second script on the tag value changed

def valueChanged(tag, tagPath, previousValue, currentValue, initialChange, missedEvents):
	if (not initialChange) and (currentValue.value == True) and (currentValue.value != previousValue.value) and (currentValue.quality.good) and (previousValue.quality.good):
		# Parsing Method path in AB and EP
		pathEP = '/'.join(tagPath.split("/")[:-1])
		pathAB = tag['parameters']['ABPath']
		
		# Parsing sessionId
		sessionId = tag['sessionId']
		
		# Call the Method
		OPCMethods.callMethod(pathEP, pathAB, sessionId)

Third script in project library

def callMethod(pathEP, pathAB, thisSession):
	logger = system.util.getLogger("DiagMethod")
	logger.info(thisSession)
	# Reading OPC method params (OPC Connection Name, OPC Server Namespace, ObjectID, MethodID)
	opc = system.tag.readBlocking(["[edge]EastmanPro/OPCConnection", "[edge]EastmanPro/Namespace", pathEP + "/ObjectId", pathEP + "/MethodId"])
	conn, ns = opc[0].value, opc[1].value
	objectId, methodId = ns + opc[2].value, ns + opc[3].value
	
	# Init args and outputs
	args = []
	outs = []
	
	# Browse AB UDT to get args and outs
	try:
		udtAB = system.tag.browse(pathAB)
	except Exception as e1:
		logger.warning("Error1" + str(e1))
		try:
			system.perspective.openPopup("pathABError1", "Popups/ErrorBox", params = {"message" : "Error 1: Invalid AB Path.\n 'ABPath' parameter that refers to method UDT in AB PLC is invalid."}, title = "Error", sessionId = thisSession)
		except Exception as e1hf:	
			logger.error("Error1HF" + str(e1hf))

		return
		
	# Read args values and outs names/number
	for tag in udtAB:
		if "Arg" in tag["name"]:
			args.append(system.tag.readBlocking(pathAB + "/" + tag["name"])[0].value)
		if "Return" in tag["name"]:                            #tag["name"] == "Return1" or tag["name"] == "Return2":
			outs.append(str(tag["fullPath"]))
	
	# Sort args and outs
	args = sorted(args)
	outs = sorted(outs)

	# Call the method		
	try:
		method = system.opcua.callMethod(conn, objectId, methodId, args)
	except Exception as e2:
		logger.info(" ".join(list((str(conn), str(objectId), str(methodId), str(args)))))
		logger.error("Error2: " + str(e2))
		try:
			system.perspective.openPopup("methodCallError2", "Popups/ErrorBox", params = {"message" : "Error 2: Method call failed.\nOne of the following parameters is invalid:\n  - Ignition OPC client connection name.\n  - EastmanPro OPC server Namespace.\n  - ObjectId (NodeId of the Object Node the Method is a member of).\n  - MethodId.\n  - List of Inputs (check data types and order)."}, title = "Error", sessionId = thisSession)
		except Exception as e2hf:
			logger.error("Error2HF: " + str(e2hf))

			
	# Write StatusCodes return for Call and inputs
	statPaths = [pathEP + "/StatusCode_Call", pathEP + "/StatusCode_Inputs"]
	statCall = [str(method[0][0]), method[0][1], method[0][2]]
	statInputs = system.dataset.toDataSet(["Code", "Name", "Description"], [list(i) for i in method[1]])
	
	system.tag.writeBlocking(statPaths, [statCall, statInputs])

	# Write back to the Return (Assuming method return status as a 1st value eg. [Return, Return1. Return2])
	try:
		system.tag.writeBlocking(outs, method[2])
	except Exception as e3:
		logger.error("Error3: " + str(e3) + " Paths: " + str(outs) + " Returns: " + str(method[2]))

	# Prompt the success message and Trigger tag reset option
	try:
		system.perspective.openPopup("methodCallSuccess", "Popups/DoneBox", params = {"message" : "Method has been called successfully!\nDo you need to reset AB Trigger tag?", "pathAB" : pathAB} if method[0][0] == 0 else {"message" : "Method call failed!\nDo you need to reset AB Trigger tag?", "pathAB" : pathAB}, title = "Done", sessionId = thisSession)
	except Exception as df:
		logger.error("DoneFail" + str(df))

	

Now I have three questions:

  • Why do I still get this error (No perspective page attached to this thread.No perspective page attached to this thread.), although I'm passing the sessionId correctly?
  • Why does the error appear in the logs only the first execution, then never appear until I restart Ignition service?
  • Why don't (try, except) handle the error (first execution or even after that)?

Thanks and sorry for the long question :smiley:


A session, by itself, cannot open a popup. You need a page.

Ignition deliberately suppresses repeat errors/warnings.

Jython's Exception is not related to java's Exception hierarchy, and cannot catch java errors or exceptions. Typically, you'd use two except clauses. One catching java.lang.Throwable, the second catching jython's Exception.

2 Likes

Thank you very much @pturmel. It's clear now. Regarding the third question, I totally understand your explanation, but I don't know to implement it. If you can give me an example I would be grateful.

Use something like this:

1 Like

Great! Thank you for the support