Using system.tag.editTag to pass tag change event scripts

I’m running Ignition 7.9.14 and trying to write tag change event scripts to tags with script.

https://docs.inductiveautomation.com/display/DOC79/system.tag.editTag

Documentation tells me that I can write attributes, great. It says these attributes are defined here:
https://docs.inductiveautomation.com/display/DOC79/Tag+Properties

If I wanted to do literally any other attribute, there’s good documentation here for that, but there are three lines under Tag Events that let me know it’s possible without providing any information on how to format that when I pass through system.tag.editTag.

I used system.tag.browseConfiguration to parse out the script that I want to pass and try to get some idea of the formatting of the dictionary I need to pass into system.tag.editTag’s attributes… it also converts this java hash object to a list, and then the list object from a SQL type to a string, before printing the original text and parsed script so I don’t have to deal with escaping all the script characters myself.

sourceTag = "***tag***"
tagConfig = system.tag.browseConfiguration(sourceTag,False)
propertyList = []

for tag in tagConfig:
	propList = tag.getProperties()
	print propList
	for prop in propList:
		#if prop == 'eventScripts':
		#print "Property '%s' has a value of '%s'" % (prop, tag.get(prop))
		#print propList[4]
		propertyList.append(tag.get(prop))
#for property in propertyList:
#	print property
#print propertyList.index("TagEventScripts[]")
#print propertyList[4]

tagChangeScript1 = str(propertyList[4])
print "------------------------------------------------"
print tagChangeScript1
print "------------------------------------------------"
tagChangeScript2 = tagChangeScript1.replace("TagEventScripts[scripts={valueChanged=(","")
#print type(tagChangeScript)
#print type(propertyList[4])
tagChangeScript = tagChangeScript2.replace(", enabled=true)}]","")
print "------------------------------------------------"
print tagChangeScript
print "------------------------------------------------"

That gives me some clues…

[HistoricalDeadband, HistoricalScanclass, InterpolationMode, tagType, eventScripts, path, HistoryTimestampSource, name, HistoryEnabled, PrimaryHistoryProvider, value, HistoryMaxAgeMode]
------------------------------------------------
TagEventScripts[scripts={valueChanged=(	***SCRIPT*** , enabled=true)}]

and this is where I’m stuck - I can’t seem to format the PyDictionary attributes correctly to feed in my script. Does anyone have a reference example using system.tag.editTag to pass eventScripts / TagEventScripts for valueChanged?

I suspect that it is expecting an object, even though the native toString function prints this with the look and feel of a list and dictionary it is most likely an object of type BasicTagEventScripts, which inherits from the interface TagEventScripts.

Something like this should work (note this is not tested):

sourceTag = '***tagPath***'
tagConfig = system.tag.browseConfiguration(sourceTag,False)

for tag in tagConfig:
     propList = tag.getProperties()

     for prop in propList:
           if prop.toString() == 'eventScripts':
                editProp = tag.get(prop)
                editScript = editProp.get('valueChanged')
                #Do whatever editing to the script you need to here

                #set valueChanged eventScript value to new script
                editProp.set('valueChanged',editScript,True)
                #commit changes
                system.tag.editTag(tagPath = tag.getFullPath,attributes={'eventScripts':editProp})
1 Like

I tried something like that before, but not quite in this way so I tried it and got the same error message.

The object type returned from system.tag.browseConfiguration is <type ‘java.util.HashMap$KeySet’>, the system.tag.editTag documentation says to pass a PyDictionary object. So what I’m having trouble with is not parsing out the data, but structuring the PyDictionary object in the way that system.tag.editTag expects for its eventScripts attribute.

Throws this error:

Java Traceback:


	at org.python.core.Py.JavaError(Py.java:495)

	at org.python.core.Py.JavaError(Py.java:488)

	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:188)

	at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction.__call__(ScriptManager.java:431)

	at org.python.core.PyObject.__call__(PyObject.java:320)

	at org.python.pycode._pyx104.f$0(<buffer>:9)

	at org.python.pycode._pyx104.call_function(<buffer>)

	at org.python.core.PyTableCode.call(PyTableCode.java:165)

	at org.python.core.PyCode.call(PyCode.java:18)

	at org.python.core.Py.runCode(Py.java:1275)

	at org.python.core.Py.exec(Py.java:1319)

	at org.python.util.PythonInterpreter.exec(PythonInterpreter.java:215)

	at org.python.util.InteractiveInterpreter.runcode(InteractiveInterpreter.java:89)

	at org.python.util.InteractiveInterpreter.runsource(InteractiveInterpreter.java:70)

	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$InterpreterWorker.doInBackground(JythonConsole.java:476)

	at com.inductiveautomation.ignition.designer.gui.tools.jythonconsole.JythonConsole$InterpreterWorker.doInBackground(JythonConsole.java:464)

	at javax.swing.SwingWorker$1.call(Unknown Source)

	at java.util.concurrent.FutureTask.run(Unknown Source)

	at javax.swing.SwingWorker.run(Unknown Source)

	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

	at java.lang.Thread.run(Unknown Source)

Caused by: com.inductiveautomation.ignition.client.gateway_interface.GatewayException: Attribute 'eventScripts' is invalid or value is an incorrect data type

	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.newGatewayException(GatewayInterface.java:341)

	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.sendMessage(GatewayInterface.java:315)

	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.sendMessage(GatewayInterface.java:268)

	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.invoke(GatewayInterface.java:894)

	at com.inductiveautomation.factorypmi.application.script.builtin.ialabs.IALabsTagFunctions.editTagImpl(IALabsTagFunctions.java:59)

	at com.inductiveautomation.ignition.common.script.builtin.ialabs.AbstractIALabsTagFunctions.editTag(AbstractIALabsTagFunctions.java:58)

	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

	at java.lang.reflect.Method.invoke(Unknown Source)

	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:186)

	... 19 more

Caused by: java.lang.Exception: Attribute 'eventScripts' is invalid or value is an incorrect data type

	at com.inductiveautomation.ignition.gateway.script.ialabs.IALabsTagFunctions.__editTags(IALabsTagFunctions.java:833)

	at com.inductiveautomation.ignition.gateway.script.ialabs.IALabsTagFunctions.editTagImpl(IALabsTagFunctions.java:729)

	at com.inductiveautomation.ignition.common.script.builtin.ialabs.AbstractIALabsTagFunctions.editTag(AbstractIALabsTagFunctions.java:58)

	at com.inductiveautomation.ignition.gateway.servlets.gateway.functions.IALabs.editTag(IALabs.java:189)

	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at sun.reflect.NativeMethodAccessorImpl.invoke(null)

	at sun.reflect.DelegatingMethodAccessorImpl.invoke(null)

	at java.lang.reflect.Method.invoke(null)

	at com.inductiveautomation.ignition.gateway.servlets.gateway.AbstractGatewayFunction.invoke(AbstractGatewayFunction.java:208)

	at com.inductiveautomation.ignition.gateway.servlets.Gateway.doPost(Gateway.java:405)

	at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)

	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)

	at com.inductiveautomation.ignition.gateway.bootstrap.MapServlet.service(MapServlet.java:85)

	at org.eclipse.jetty.servlet.ServletHolder$NotAsyncServlet.service(ServletHolder.java:1400)

	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:760)

	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1617)

	at org.eclipse.jetty.servlets.CrossOriginFilter.handle(CrossOriginFilter.java:310)

	at org.eclipse.jetty.servlets.CrossOriginFilter.doFilter(CrossOriginFilter.java:264)

	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1596)

	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:545)

	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)

	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:590)

	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)

	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)

	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1607)

	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)

	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1297)

	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)

	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:485)

	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1577)

	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)

	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1212)

	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)

	at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:59)

	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)

	at org.eclipse.jetty.server.Server.handle(Server.java:500)

	at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383)

	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:547)

	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375)

	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:270)

	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)

	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)

	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117)

	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336)

	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313)

	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171)

	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129)

	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:388)

	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806)

	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938)

	at java.lang.Thread.run(null)

Traceback (most recent call last):
  File "<buffer>", line 25, in <module>
	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.newGatewayException(GatewayInterface.java:341)

	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.sendMessage(GatewayInterface.java:315)

	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.sendMessage(GatewayInterface.java:268)

	at com.inductiveautomation.ignition.client.gateway_interface.GatewayInterface.invoke(GatewayInterface.java:894)

	at com.inductiveautomation.factorypmi.application.script.builtin.ialabs.IALabsTagFunctions.editTagImpl(IALabsTagFunctions.java:59)

	at com.inductiveautomation.ignition.common.script.builtin.ialabs.AbstractIALabsTagFunctions.editTag(AbstractIALabsTagFunctions.java:58)

	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

	at java.lang.reflect.Method.invoke(Unknown Source)


com.inductiveautomation.ignition.client.gateway_interface.GatewayException: com.inductiveautomation.ignition.client.gateway_interface.GatewayException: Attribute 'eventScripts' is invalid or value is an incorrect data type


Here is more what I’m trying to get correct, and the results.

Script:

sourceTag = "***TagPath***"
destinationTag = "***TagPath***"

tagConfig = system.tag.browseConfiguration(sourceTag,False)
propertyList = []

for tag in tagConfig:
	propList = tag.getProperties()
	print "-------------------------------------------"
	print "Property type and value"
	print type(propList)
	print propList
	print "-------------------------------------------"
	for prop in propList:
		#if prop == 'eventScripts':
		#print "Property '%s' has a value of '%s'" % (prop, tag.get(prop))
		#print propList[4]
		propertyList.append(tag.get(prop))
		if prop.toString() == 'eventScripts':
			editProp = tag.get(prop)
			editScript = editProp.get('valueChanged')
			print "editProp:"
			print editProp
			print "--------------------------------------"
			print "editScript:"
			print editScript
			print "--------------------------------------"
			editProp.set('valueChanged',editScript,True)
			dic = dict(editProp.toString())
			print "dictionary"
			print dic
			system.tag.editTag(tagPath=destinationTag,attributes={'eventScripts':dic})

Results:

Jython 2.5.3 (, Dec 6 2018, 12:34:00) 
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_241

>>> 
-------------------------------------------
Property type and value
<type 'java.util.HashMap$KeySet'>
[HistoricalDeadband, HistoricalScanclass, InterpolationMode, tagType, eventScripts, path, HistoryTimestampSource, name, HistoryEnabled, PrimaryHistoryProvider, value, HistoryMaxAgeMode]
-------------------------------------------
editProp:
TagEventScripts[scripts={valueChanged=(	***SCRIPT***  , enabled=true)}]
--------------------------------------
editScript:
	***SCRIPT*** 
--------------------------------------
Traceback (most recent call last):
  File "<buffer>", line 31, in <module>
ValueError: dictionary update sequence element #0 has length 1; 2 is required

From Ignition support, a working solution that uses the SDK.

This is important because it’s the only way to update event scripts on MQTT Engine tags when not inheriting those properties from Ignition Edge Nodes.

from com.inductiveautomation.ignition.common.sqltags.model import TagProp

sourceTag = "***TAGPATH***"
destinationTag = "***TAGPATH***"

tagConfig = system.tag.browseConfiguration(sourceTag,False)
propertyList = []

for tag in tagConfig:
	propList = tag.getProperties()
	print "-------------------------------------------"
	print "Property type and value"
	print type(propList)
	print propList
	print "-------------------------------------------"
	for prop in propList:
		#if prop == 'eventScripts':
		#print "Property '%s' has a value of '%s'" % (prop, tag.get(prop))
		#print propList[4]
		propertyList.append(tag.get(prop))
		if prop.toString() == 'eventScripts':
			editProp = tag.get(prop)
			editScript = editProp.get('valueChanged')
			print "editProp:"
			print editProp
			print "--------------------------------------"
			print "editScript:"
			print editScript
			print "--------------------------------------"
			editProp.set('valueChanged',editScript,True)
			type(editProp)
			system.tag.editTag(tagPath=destinationTag,attributes={TagProp.EventScripts:editProp})
1 Like