Automation Professionals' Integration Toolkit Module

Awesome, we’ll try binding things then, I have to admit we didn’t really try as there wasn’t the binding icon.

I would love to but unfortunately a flight from France to Sacramento might be too much to ask for to my employer ahah !

Thanks!

There's a livestream option for ICC, too.

2 Likes

My presentation is done. The source code I mentioned is available here:

https://www.automation-pros.com/toolkit/actors.zip

7 Likes

Automation Professionals is pleased to announce the production release of this module for Ignition v8.3: v2.1.1.252721938

As usual, refer to the Module Sales page linked in the OP to keep up with the latest production releases.

11 Likes

Hey @pturmel , with the Bulk Action, can we use relative tagpaths in the called script that are relative to the tagpath that triggered it?

e.g. if I’m calling this function:

def doThisLongThing(values):
   # read udt param
   deviceName = system.tag.readBlocking('[.]../Parameters.DeviceName')[0].value

No, but each item delivered includes the .source as a TagPath object, which can efficiently compute relative paths with the parentPath property and the .getChildPath(...) method.

Keep in mind that the function gets a list of items, that do not have to have the same source at all. Only if a function was set up to take just one item at a time could you apply relative paths automatically. And then, you just have the standard valueChange event. :man_shrugging:

Also be aware that each function called, while not blocking the tag subsystem, relies on the gateway context's Execution Manager to run each delivery asynchronously. If you expect to run many long processes, consider handing off to a custom thread pool execution manager with the desired level of parallelism. If each potential item has its own long process, you may want to parallelize them individually.

1 Like

Ah, derr, that makes sense. Monday brain still kicking in… Good note about the TagPath object though, that is handy to know.

Hey Phil,

I'm trying to use @system.util.runInGateway and am encountering an error.

toolkitTest

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

@system.util.runInGateway
def gwLogInfof(*args):
    logger.infof(*args)

Script Console

toolkitTest.gwLogInfof('Test Message')

Result

Java Traceback:
Traceback (most recent call last):
  File "<input>", line 1, in <module>
java.util.NoSuchElementException: No value present

	at java.util.Optional.orElseThrow(:0)

	at com.automation_pros.simaids.gateway.ToolkitRPCImpl.runInGateway(ToolkitRPCImpl.java:77)

	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(:0)

	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(:0)

	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(:0)

	at java.lang.reflect.Method.invoke(:0)

	at com.inductiveautomation.ignition.gateway.rpc.RpcDelegate$DelegateRpcHandler.handle(RpcDelegate.java:275)

	at com.inductiveautomation.ignition.gateway.rpc.RpcRoutes.lambda$handle$1(RpcRoutes.java:209)

	at com.inductiveautomation.ignition.gateway.rpc.RpcRoutes.safelyHandle(RpcRoutes.java:225)

	at com.inductiveautomation.ignition.gateway.rpc.RpcRoutes.handle(RpcRoutes.java:209)

	at com.inductiveautomation.ignition.gateway.dataroutes.Route.service(Route.java:355)

	at com.inductiveautomation.ignition.gateway.dataroutes.RouteGroupImpl.service(RouteGroupImpl.java:117)

	at com.inductiveautomation.ignition.gateway.dataroutes.RouteGroupCollectionServlet.serviceInternal(RouteGroupCollectionServlet.java:152)

	at com.inductiveautomation.ignition.gateway.dataroutes.AbstractRouteGroupServlet.service(AbstractRouteGroupServlet.java:40)

	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)

	at org.eclipse.jetty.ee10.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1385)

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

	at org.eclipse.jetty.ee10.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1622)

	at com.inductiveautomation.catapult.filters.GatewayFilter.doFilter(GatewayFilter.java:119)

	at jakarta.servlet.http.HttpFilter.doFilter(HttpFilter.java:97)

	at org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter(FilterHolder.java:205)

	at org.eclipse.jetty.ee10.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1594)

	at org.eclipse.jetty.ee10.servlet.ServletHandler$MappedServlet.handle(ServletHandler.java:1555)

	at org.eclipse.jetty.ee10.servlet.ServletChannel.dispatch(ServletChannel.java:823)

	at org.eclipse.jetty.ee10.servlet.ServletChannel.handle(ServletChannel.java:440)

	at org.eclipse.jetty.ee10.servlet.ServletHandler.handle(ServletHandler.java:470)

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

	at org.eclipse.jetty.ee10.servlet.SessionHandler.handle(SessionHandler.java:717)

	at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1071)

	at org.eclipse.jetty.rewrite.handler.RewriteHandler$LastRuleHandler.handle(RewriteHandler.java:159)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.HeaderPatternRule$1.handle(HeaderPatternRule.java:89)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.HeaderPatternRule$1.handle(HeaderPatternRule.java:89)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.HeaderPatternRule$1.handle(HeaderPatternRule.java:89)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.HeaderPatternRule$1.handle(HeaderPatternRule.java:89)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:143)

	at org.eclipse.jetty.server.Handler$Sequence.handle(Handler.java:805)

	at org.eclipse.jetty.server.Handler$Sequence.handle(Handler.java:805)

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

	at org.eclipse.jetty.server.internal.HttpChannelState$HandlerInvoker.run(HttpChannelState.java:677)

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

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

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

	at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)

	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:480)

	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:443)

	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:293)

	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:201)

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

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

	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1211)

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

	at java.lang.Thread.run(:0)

java.util.NoSuchElementException: java.util.NoSuchElementException: No value present


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

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

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

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

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

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

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

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

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

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

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

	at java.desktop/javax.swing.SwingWorker.run(Unknown Source)

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

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

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

Caused by: java.util.NoSuchElementException: No value present

	at java.util.Optional.orElseThrow(:0)

	at com.automation_pros.simaids.gateway.ToolkitRPCImpl.runInGateway(ToolkitRPCImpl.java:77)

	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(:0)

	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(:0)

	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(:0)

	at java.lang.reflect.Method.invoke(:0)

	at com.inductiveautomation.ignition.gateway.rpc.RpcDelegate$DelegateRpcHandler.handle(RpcDelegate.java:275)

	at com.inductiveautomation.ignition.gateway.rpc.RpcRoutes.lambda$handle$1(RpcRoutes.java:209)

	at com.inductiveautomation.ignition.gateway.rpc.RpcRoutes.safelyHandle(RpcRoutes.java:225)

	at com.inductiveautomation.ignition.gateway.rpc.RpcRoutes.handle(RpcRoutes.java:209)

	at com.inductiveautomation.ignition.gateway.dataroutes.Route.service(Route.java:355)

	at com.inductiveautomation.ignition.gateway.dataroutes.RouteGroupImpl.service(RouteGroupImpl.java:117)

	at com.inductiveautomation.ignition.gateway.dataroutes.RouteGroupCollectionServlet.serviceInternal(RouteGroupCollectionServlet.java:152)

	at com.inductiveautomation.ignition.gateway.dataroutes.AbstractRouteGroupServlet.service(AbstractRouteGroupServlet.java:40)

	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)

	at org.eclipse.jetty.ee10.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1385)

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

	at org.eclipse.jetty.ee10.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1622)

	at com.inductiveautomation.catapult.filters.GatewayFilter.doFilter(GatewayFilter.java:119)

	at jakarta.servlet.http.HttpFilter.doFilter(HttpFilter.java:97)

	at org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter(FilterHolder.java:205)

	at org.eclipse.jetty.ee10.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1594)

	at org.eclipse.jetty.ee10.servlet.ServletHandler$MappedServlet.handle(ServletHandler.java:1555)

	at org.eclipse.jetty.ee10.servlet.ServletChannel.dispatch(ServletChannel.java:823)

	at org.eclipse.jetty.ee10.servlet.ServletChannel.handle(ServletChannel.java:440)

	at org.eclipse.jetty.ee10.servlet.ServletHandler.handle(ServletHandler.java:470)

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

	at org.eclipse.jetty.ee10.servlet.SessionHandler.handle(SessionHandler.java:717)

	at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1071)

	at org.eclipse.jetty.rewrite.handler.RewriteHandler$LastRuleHandler.handle(RewriteHandler.java:159)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.HeaderPatternRule$1.handle(HeaderPatternRule.java:89)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.HeaderPatternRule$1.handle(HeaderPatternRule.java:89)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.HeaderPatternRule$1.handle(HeaderPatternRule.java:89)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.HeaderPatternRule$1.handle(HeaderPatternRule.java:89)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:143)

	at org.eclipse.jetty.server.Handler$Sequence.handle(Handler.java:805)

	at org.eclipse.jetty.server.Handler$Sequence.handle(Handler.java:805)

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

	at org.eclipse.jetty.server.internal.HttpChannelState$HandlerInvoker.run(HttpChannelState.java:677)

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

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

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

	at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)

	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:480)

	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:443)

	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:293)

	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:201)

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

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

	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1211)

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

	at java.lang.Thread.run(:0)

Traceback (most recent call last):
  File "<input>", line 1, in <module>
java.util.NoSuchElementException: No value present

	at java.util.Optional.orElseThrow(:0)

	at com.automation_pros.simaids.gateway.ToolkitRPCImpl.runInGateway(ToolkitRPCImpl.java:77)

	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(:0)

	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(:0)

	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(:0)

	at java.lang.reflect.Method.invoke(:0)

	at com.inductiveautomation.ignition.gateway.rpc.RpcDelegate$DelegateRpcHandler.handle(RpcDelegate.java:275)

	at com.inductiveautomation.ignition.gateway.rpc.RpcRoutes.lambda$handle$1(RpcRoutes.java:209)

	at com.inductiveautomation.ignition.gateway.rpc.RpcRoutes.safelyHandle(RpcRoutes.java:225)

	at com.inductiveautomation.ignition.gateway.rpc.RpcRoutes.handle(RpcRoutes.java:209)

	at com.inductiveautomation.ignition.gateway.dataroutes.Route.service(Route.java:355)

	at com.inductiveautomation.ignition.gateway.dataroutes.RouteGroupImpl.service(RouteGroupImpl.java:117)

	at com.inductiveautomation.ignition.gateway.dataroutes.RouteGroupCollectionServlet.serviceInternal(RouteGroupCollectionServlet.java:152)

	at com.inductiveautomation.ignition.gateway.dataroutes.AbstractRouteGroupServlet.service(AbstractRouteGroupServlet.java:40)

	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)

	at org.eclipse.jetty.ee10.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1385)

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

	at org.eclipse.jetty.ee10.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1622)

	at com.inductiveautomation.catapult.filters.GatewayFilter.doFilter(GatewayFilter.java:119)

	at jakarta.servlet.http.HttpFilter.doFilter(HttpFilter.java:97)

	at org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter(FilterHolder.java:205)

	at org.eclipse.jetty.ee10.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1594)

	at org.eclipse.jetty.ee10.servlet.ServletHandler$MappedServlet.handle(ServletHandler.java:1555)

	at org.eclipse.jetty.ee10.servlet.ServletChannel.dispatch(ServletChannel.java:823)

	at org.eclipse.jetty.ee10.servlet.ServletChannel.handle(ServletChannel.java:440)

	at org.eclipse.jetty.ee10.servlet.ServletHandler.handle(ServletHandler.java:470)

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

	at org.eclipse.jetty.ee10.servlet.SessionHandler.handle(SessionHandler.java:717)

	at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1071)

	at org.eclipse.jetty.rewrite.handler.RewriteHandler$LastRuleHandler.handle(RewriteHandler.java:159)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.HeaderPatternRule$1.handle(HeaderPatternRule.java:89)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.HeaderPatternRule$1.handle(HeaderPatternRule.java:89)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.HeaderPatternRule$1.handle(HeaderPatternRule.java:89)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.HeaderPatternRule$1.handle(HeaderPatternRule.java:89)

	at org.eclipse.jetty.rewrite.handler.Rule$Handler.handle(Rule.java:108)

	at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:143)

	at org.eclipse.jetty.server.Handler$Sequence.handle(Handler.java:805)

	at org.eclipse.jetty.server.Handler$Sequence.handle(Handler.java:805)

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

	at org.eclipse.jetty.server.internal.HttpChannelState$HandlerInvoker.run(HttpChannelState.java:677)

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

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

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

	at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)

	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:480)

	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:443)

	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:293)

	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:201)

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

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

	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1211)

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

	at java.lang.Thread.run(:0)

java.util.NoSuchElementException: java.util.NoSuchElementException: No value present

Thoughts

Gateway: 8.3.4-SNAPSHOT (b2026010816)
Toolkit: 2.1.1 (b252721938)

Did you remember to save the project? Gateway scope cannot run unsaved content from the designer.

Yup, the project is saved. I also tried restarting the designer without any change.

Hmmm. This is the relevant code:

            if (ClientReqSession.exists()) {
                project = (String) ClientReqSession.get().getAttribute(ClientReqSession.SESSION_PROJECT_NAME);
            } else {
                project = ScriptContext.getDefaultProject().orElseThrow();
            }

This might be an unexpected dependency on Vision. I'll have to dig into this and figure out the corresponding Perspective-only project reference. If you would, add Vision and try again--I suspect that it will suddenly work.

Even weirder then, I already have Vision installed.

Hmm. Is this an inheritable project?

Nope, not inheritable.

This is on a development gateway, I can try anything you’d find useful.

Did you get a gateway log entry, too?

Nah, I don’t see any gateway log messages coming from the Toolkit module.

My dev gateway regularly throws ClockDriftDetector messages, but I doubt that’s relevant :man_shrugging:t2:

Oops, debug level for ToolkitRPCImpl. Should provide a more specific line number--77 is the beginning of the try.

I think I may have to pass the project name as an actual argument, since I can't seem to rely on ClientReqSession or ScriptContext.

If you're using the standard machinery/happy path/RpcDelegate, you can use the static utility on RpcDelegate:
com.inductiveautomation.ignition.gateway.rpc.RpcDelegate.projectName()

But internally this is just reporting from the RpcContext, which is backed by the ClientReqSession:

String projectName = (String) session.getAttribute(ClientReqSession.SESSION_PROJECT_NAME);

So no idea why it wouldn't be working.