Automation Professionals' Integration Toolkit Module

That's very helpful.
Thanks a lot Phil!

Automation Professionals is pleased to announce a beta release of this Integration Toolkit:

For Ignition v8.1+, as usual: v2.0.16.241352008

This beta introduces a number of new scripting features:

  • Inspired by @Mathias_Melling above, the souped-up dictionary functionality of the BindableVarMap data type has been factored out, as system.util.VarMap. Serializable to the extent its contents are serializable, just like dictionaries, and safe for use with persistence. :grin:

  • The PythonAsJavaException wrapper from my later.py script has been re-implemented in java as PyAsJavaException, exposed via the helper function system.reflect.asThrowable(). This implementation extracts the package to include with the function or class+method on each line of the resulting traceback. And it is serializable, suitable for inclusion in gateway network or designer/client messaging.

  • As a side-effect of the work on PyAsJavaException, system.reflect.getModulePath() is available for use within project library scripts. Particularly useful when naming logger instances.

And finally, something that has been percolating for a while now:

  • A solution to testing gateway code in the designer script console, in the form of a decorator for project library functions: @system.util.runInGateway. Place this decorator in front of your gateway-scope-only library function and calls from Designer or Vision Client scopes will be automatically turned into an RPC call to the gateway instance of the code, and that instance's return value passed back to the calling scope.

The above can be approximated with message handlers on a per-project basis, but that approximation suffers from significant extra opportunities for errors, and lack of parallelism at scale.

Try something like this code snippet, perhaps in toolkit:

logger = system.util.getLogger(system.util.getProjectName() + '.' + system.reflect.getModulePath())

@system.util.runInGateway
def gwLoggerTest(someMessage):
	logger.info(someMessage)
	return "Logged: " + someMessage

(Remember to save your project.) Then try this in the designer script console:

print toolkit.gwLoggerTest("Hold my beer!")

Then go look at your gateway logs. :grin:

{ It is a beta because travel and client crises have limited testing time... }

14 Likes

I'm running into an error trying to merge a dataset of tag paths and a comma separated list of tag paths into a single dataset in Vision. Ignition version 8.1.25.

If I attempt to use any string expression functions(such as trim or toStr) while iterating though the result of split, I'll get an error saying: com.inductiveautomation.ignition.common.expressions.ExpressionException: Unsupported type in rowSource: class java.lang.String . If I remove the string expression functions, the binding will compile and run without issue.

Union All error
java.lang.Exception: Error executing expression binding on
MagicPlot.MagicPlot.plotTagPaths
	at com.inductiveautomation.factorypmi.application.binding.ExpressionPropertyAdapter.runExpression(ExpressionPropertyAdapter.java:92)
	at com.inductiveautomation.factorypmi.application.binding.ExpressionPropertyAdapter.startup(ExpressionPropertyAdapter.java:113)
	at com.inductiveautomation.factorypmi.application.binding.DefaultInteractionController.setPropertyAdapter(DefaultInteractionController.java:219)
	at com.inductiveautomation.factorypmi.designer.property.configurators.ExpressionConfigurator.bind(ExpressionConfigurator.java:246)
	at com.inductiveautomation.factorypmi.designer.property.configurators.ExpressionConfigurator.tryCommit(ExpressionConfigurator.java:192)
	at com.inductiveautomation.factorypmi.designer.property.configurators.ConfiguratorMultiplexor$EditorParent.tryCommit(ConfiguratorMultiplexor.java:398)
	at com.inductiveautomation.factorypmi.designer.property.configurators.ConfiguratorMultiplexor.tryCommit(ConfiguratorMultiplexor.java:546)
	at com.inductiveautomation.factorypmi.designer.property.configurators.DynamicOptsDialog.doOK(DynamicOptsDialog.java:95)
	at com.inductiveautomation.factorypmi.designer.property.configurators.DynamicOptsDialog$1.actionPerformed(DynamicOptsDialog.java:64)
	at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at com.inductiveautomation.snap.swing.RibsEventQueue.dispatchEvent(RibsEventQueue.java:99)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.WaitDispatchSupport$2.run(Unknown Source)
	at java.desktop/java.awt.WaitDispatchSupport$4.run(Unknown Source)
	at java.desktop/java.awt.WaitDispatchSupport$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.desktop/java.awt.WaitDispatchSupport.enter(Unknown Source)
	at java.desktop/java.awt.Dialog.show(Unknown Source)
	at java.desktop/java.awt.Component.show(Unknown Source)
	at java.desktop/java.awt.Component.setVisible(Unknown Source)
	at java.desktop/java.awt.Window.setVisible(Unknown Source)
	at java.desktop/java.awt.Dialog.setVisible(Unknown Source)
	at com.inductiveautomation.factorypmi.designer.property.configurators.DynamicOptsDialog.showDialog(DynamicOptsDialog.java:163)
	at com.inductiveautomation.factorypmi.designer.model.VisionDesignerImpl.openBindingDialog(VisionDesignerImpl.java:1223)
	at com.inductiveautomation.factorypmi.designer.property.editors.bb.DynamicOptionsButton.actionPerformed(DynamicOptionsButton.java:37)
	at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at com.jidesoft.plaf.basic.BasicJideButtonListener.mouseReleased(Unknown Source)
	at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
	at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/javax.swing.plaf.basic.BasicTableUI$Handler.repostEvent(Unknown Source)
	at java.desktop/javax.swing.plaf.basic.BasicTableUI$Handler.mouseReleased(Unknown Source)
	at com.jidesoft.swing.DelegateMouseInputListener.mouseReleased(Unknown Source)
	at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
	at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
	at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at com.inductiveautomation.snap.swing.RibsEventQueue.dispatchEvent(RibsEventQueue.java:99)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Caused by: com.inductiveautomation.ignition.common.expressions.ExpressionException: Unable to handle rowSource #2
	at com.automation_pros.simaids.expressions.UnionAll.execute(UnionAll.java:119)
	at com.inductiveautomation.ignition.client.expressions.ClientDynamicDispatchFunction.execute(ClientDynamicDispatchFunction.java:43)
	at com.inductiveautomation.ignition.common.expressions.FunctionExpression.execute(FunctionExpression.java:69)
	at com.inductiveautomation.factorypmi.application.binding.ExpressionPropertyAdapter.runExpression(ExpressionPropertyAdapter.java:83)
	... 104 common frames omitted
Caused by: com.inductiveautomation.ignition.common.expressions.ExpressionException: Unsupported type in rowSource: class java.lang.String
	at com.automation_pros.simaids.expressions.UnionAll.buildWith(UnionAll.java:203)
	at com.automation_pros.simaids.expressions.UnionAll.execute(UnionAll.java:117)
	... 107 common frames omitted

Working Binding
unionAll(
	asMap("tagPath", "str"),
	{MagicPlot.tagPaths},
	where(	
		if(
			{MagicPlot.tagPathList} != "",
			forEach(
				split({MagicPlot.tagPathList}, ","), it()
			), asList(None)
		), !isNull(it())
	)
)
Erroring binding
unionAll(
	asMap("tagPath", "str"),
	{MagicPlot.tagPaths},
	where(	
		if(
			{MagicPlot.tagPathList} != "",
			forEach(
				split({MagicPlot.tagPathList}, ","), trim(it())
			), asList(None)
		), !isNull(it())
	)
)

tagpathList: [default]OEE/Cell A/TestValueA, [default]OEE/Cell A/TestValueB
tagPaths Dataset:

"#NAMES"
"tagPath"
"#TYPES"
"str"
"#ROWS","1"
"[default]OEE/Cell A/TestValuec"

split() returns a multi-row dataset.

Iterating through a dataset supplies a single row to it() at a time. You cannot use trim() on the one-row dataset--it needs a string, and returns a string.

1 Like

I guess I got confused on what my iteration loop was returning and what union all was expecting. Changing the iteration through the results of split() to

forEach(
	split({MagicPlot.tagPathList}, ","), asList(trim(it()[0]))
)

corrected the issue.

I was thinking that the error was coming from me doing string operations on a row value but it was actually coming from the union all expecting a list of lists, and was not happy it was finding a list of strings instead for the row values, along with me attempting to perform string operations on a dataset row instead of a value.

I keep forgetting that split returns a dataset and not a list. I think I'm assuming it behaves like python's split

1 Like

I've run into this error, and I just can't make since of it, so I thought I would ask for some assistance.

Error
java.lang.Exception: Error executing expression binding on
Stop Occurances.Root Container.Table.data
	at com.inductiveautomation.factorypmi.application.binding.ExpressionPropertyAdapter.runExpression(ExpressionPropertyAdapter.java:92)
	at com.inductiveautomation.factorypmi.application.binding.ExpressionPropertyAdapter.startup(ExpressionPropertyAdapter.java:113)
	at com.inductiveautomation.factorypmi.application.binding.DefaultInteractionController.setPropertyAdapter(DefaultInteractionController.java:248)
	at com.inductiveautomation.factorypmi.designer.property.configurators.ExpressionConfigurator.bind(ExpressionConfigurator.java:246)
	at com.inductiveautomation.factorypmi.designer.property.configurators.ExpressionConfigurator.tryCommit(ExpressionConfigurator.java:192)
	at com.inductiveautomation.factorypmi.designer.property.configurators.ConfiguratorMultiplexor$EditorParent.tryCommit(ConfiguratorMultiplexor.java:398)
	at com.inductiveautomation.factorypmi.designer.property.configurators.ConfiguratorMultiplexor.tryCommit(ConfiguratorMultiplexor.java:546)
	at com.inductiveautomation.factorypmi.designer.property.configurators.DynamicOptsDialog.doOK(DynamicOptsDialog.java:95)
	at com.inductiveautomation.factorypmi.designer.property.configurators.DynamicOptsDialog$1.actionPerformed(DynamicOptsDialog.java:64)
	at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.WaitDispatchSupport$2.run(Unknown Source)
	at java.desktop/java.awt.WaitDispatchSupport$4.run(Unknown Source)
	at java.desktop/java.awt.WaitDispatchSupport$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
	at java.desktop/java.awt.WaitDispatchSupport.enter(Unknown Source)
	at java.desktop/java.awt.Dialog.show(Unknown Source)
	at java.desktop/java.awt.Component.show(Unknown Source)
	at java.desktop/java.awt.Component.setVisible(Unknown Source)
	at java.desktop/java.awt.Window.setVisible(Unknown Source)
	at java.desktop/java.awt.Dialog.setVisible(Unknown Source)
	at com.inductiveautomation.factorypmi.designer.property.configurators.DynamicOptsDialog.showDialog(DynamicOptsDialog.java:163)
	at com.inductiveautomation.factorypmi.designer.model.VisionDesignerImpl.openBindingDialog(VisionDesignerImpl.java:1236)
	at com.inductiveautomation.factorypmi.designer.property.editors.bb.DynamicOptionsButton.actionPerformed(DynamicOptionsButton.java:37)
	at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at java.desktop/javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at com.jidesoft.plaf.basic.BasicJideButtonListener.mouseReleased(Unknown Source)
	at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
	at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Caused by: com.inductiveautomation.ignition.common.expressions.ExpressionException: Error performing subscript operation
	at com.inductiveautomation.ignition.common.expressions.SubscriptExpression.execute(SubscriptExpression.java:126)
	at com.inductiveautomation.ignition.common.expressions.functions.BaseFunction.executeAll(BaseFunction.java:64)
	at com.automation_pros.simaids.expressions.SimpleIterator.execute(SimpleIterator.java:177)
	at com.inductiveautomation.ignition.client.expressions.ClientDynamicDispatchFunction.execute(ClientDynamicDispatchFunction.java:43)
	at com.inductiveautomation.ignition.common.expressions.FunctionExpression.execute(FunctionExpression.java:69)
	at com.inductiveautomation.factorypmi.application.binding.ExpressionPropertyAdapter.runExpression(ExpressionPropertyAdapter.java:83)
	... 90 more
Caused by: java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Unknown Source)
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Unknown Source)
	at java.base/jdk.internal.util.Preconditions.checkIndex(Unknown Source)
	at java.base/java.util.Objects.checkIndex(Unknown Source)
	at java.base/java.util.ArrayList.get(Unknown Source)
	at com.automation_pros.simaids.expressions.SimpleIterator.getValue(SimpleIterator.java:56)
	at com.automation_pros.simaids.expressions.IteratorValue.execute(IteratorValue.java:40)
	at com.inductiveautomation.ignition.client.expressions.ClientDynamicDispatchFunction.execute(ClientDynamicDispatchFunction.java:43)
	at com.inductiveautomation.ignition.common.expressions.FunctionExpression.execute(FunctionExpression.java:69)
	at com.inductiveautomation.ignition.common.expressions.SubscriptExpression.execute(SubscriptExpression.java:50)
	at com.inductiveautomation.ignition.common.expressions.SubscriptExpression.execute(SubscriptExpression.java:59)
	... 95 more

Ignition v8.1.35 (b2023120517)
Java: Azul Systems, Inc. 17.0.8

I'm using the following expression to add a column to a dataset.

Expression
selectStar(
	{Root Container.Processing Group.processingStopsTable.pivotedData},
	asMap(
		forEach(
			groupBy(
				{Root Container.Processing Group.processingStopsTable.last8HistoricalData},
				split(it()['path'],'_')[0]
			),
			asList(
				case(
					it()[0],
					'productlevel', 'No Product',
					'cap', 'No Caps',
					'empty', 'No Bottles',
					'Packaging'
				),
				sum(it()[1],'value')
			)
		)
	)[it()['Occurrence']],
	'Last 8',
	'I'
)

The internal expression works as expected and returns the following Map:

{No Product=7.0,No Caps=29.0, Packaging=27.0, No Bottles=3.0}

The pivotedData dataset does have an "Occurrence" column.

pivotedData Dataset
"#NAMES"
"Occurrence","_7A","_8A","_9A","_10A","_11A","_12P","_1P","_2P","_3P","_4P","_5P","_6P","_7P","_8P","_9P","_10P","_11P","_12A","_1A","_2A","_3A","_4A","_5A","_6A"
"#TYPES"
"str","I","I","I","I","I","I","I","I","I","I","I","I","I","I","I","I","I","I","I","I","I","I","I","I"
"#ROWS","4"
"No Product","0","0","1","0","0","1","0","0","0","0","2","0","2","0","0","1","0","1","0","0","1","1","4","1"
"No Caps","2","8","0","0","0","1","1","1","0","0","0","0","1","1","1","0","1","16","8","7","4","5","3","0"
"Packaging","6","2","6","1","0","0","2","4","1","11","0","0","6","0","4","4","2","5","1","1","2","4","6","4"
"No Bottles","0","2","5","0","0","1","1","1","0","2","1","0","1","0","1","1","1","7","0","0","0","0","0","0"

Any guidance is appreciated.

The arguments to selectStar() changed along the way. Column info is now the 2nd argument, and following arguments are the column value expressions.

https://www.automation-pros.com/toolkit/doc/datasets.html#selectstar

Consider also extracting that groupBy() and the asMap() around it into a subexpression via transform() and value() so it is only executed once, instead of for every row. Your row expression would then be just

value()[it()['Occurrence']]
1 Like

Sheesh, that was embarrassingly simple. I read the documentation like 10 times and missed the order completely.

As always, thanks for the quick response.

Automation Professionals is pleased to announce the latest production release of the Integration Toolkit module:

For Ignition v8.1+: v2.0.17.241921515

It fixes one bug found in the last beta, a race condition that broke initialization of the python VarMap monkey-patching. Without that, property access to dictionary keys did not work. This flaw showed up on high-end hardware that was running a very stripped-down Ignition instance. (Testing my spreadsheet-based tag tool. Almost ready, fwiw.)

Also, system.reflect.getModulePath() is the correct name, not system.util.getModulePath(). (I had to move it and didn't fix the example.)

5 Likes

Apologies if this is not the right place, but I have to ask :

Your tags function seems like a necessity in the core Ignition functions, as myself and our different development teams are in dire need of such functionalities in our projects. Clients are more and more demanding and resorting to building a dynamic list of tag paths is becoming very common, or at least it would really speed up our development cycle...

And from what I've gathered, the alternatives to the tags function are clearly far from ideal (hidden table with embedded view or creating tons of bindings in advance...)

I know @pturmel isn't related to IA staff by any means, but it would be awesome if someone from IA could chime in and tell us whether this tags function behavior will be implemented one day, say in 8.3.0 ?

I think your work is amazing @pturmel but unfortunately our clients are generally reluctant to incorporating modules from 3rd parties, despite our best efforts to convince them to go the "3rd party" road.

1 Like

Maybe.

Almost certainly not.

1 Like

Sorry.

This module exists, and is NOT open source, precisely to break down this reluctance. I have no sympathy for it at all.

Once any organization accepts any of my modules in their systems, they tend to not be reluctant to use my other modules, where applicable. In other words, this module is what a general retailer would call a "loss leader"--a product provided at a loss whose purpose is to enable other sales. And my unpaid hours sunk into this module definitely counts as a loss.

If I get hit by a bus, my heirs have instructions to sell my IP to an entity that can and will carry it forward.

16 Likes

That's always good to hear as I know I've heard that argument in terms of using an integrator with a team vs a sole contracted one-man-shop integrator.

4 Likes

Understood, this is an amazing argument we can now put forward when dealing with reluctant clients whose main argument is "but what happens afterwards when there's no one left to maintain this module?"

Again, I'm convinced your modules are top notch, thanks for your work.

5 Likes

@pturmel I'm trying to use forEach() to do cell color in a perspective table. I can get it to work for row background color, but I can't get it to work for individual cell background color.

forEach({this.custom.data},
	forEach(it(),
		asMap(
			it()[0],
			asMap(
				"value", it()[1],
				"style", None
			)
		)
	)
)

image

Try setting style to be asMap() instead of None. That will make it behave as an object in the perspective component data. You can then also provide some default object members as well, such as classes.

Edit: Wait, are you trying to merge 2 maps?

Yes, I was already doing that. I omitted that part to be a cleaner post. I think the problem is the extra 0 layer in the JSON.

As is renders like so

original data:

[
  {
    "serial": 4363915,
    "cover": "03-01D",
    "backs": "07-01A",
    "seats": "07-01A",
    "frame": "0M91-51",
    "style": "M9231351",
    "in_queue": 1722880635000,
    "scheduled": 1723003200000
  }
]

expected output

[
  {
    "serial": {"value":4363915, "style":{"backgroundColor":"someColor"} },
    "cover": {"value":"03-01D", "style":{"backgroundColor":"someColor"} },
    ...
  }
]

Try wrapping your entire expression with flatten() to remove the double [[]]

1 Like

That is closer, but still not right. cover, in_queue should both be under 0, 1, 2, ...

image

oh, i see what you're trying to do. I haven't found a good way to do that yet and have so far resorted to creating my maps by hand instead of iterating through the columns :frowning: