Executing Client Batch File from Gateway Events

I have 4/5 clients running external python scripts via .bat files from scripts in their "Project Library".

def run():
		bat_path = 'C:\\python_project\\run.bat'
		system.util.execute([bat_path])

It happens that the machine(5/5) housing the Gateway will not be configured with local python scripts I would like to run. I am wanting to run one of the client's .bat files at 5:00am everyday. When using "Gateway Events" scripts, is there a way I can execute a Client's "Project Library" script? I have tired referencing a shared folder, but the Gateway PC still requires Python, which is not an option. i.e.

def run():
		bat_path = '\\\\xxx.xxx.xxx.xxx\\python_project\\run.bat'
		system.util.execute([bat_path])

I am using Vision windows and a button to execute the script manually, which works just fine. As another inquiry, Is there other ways to schedule at the client level rather than the gateway level?


Edit for Solution:
Gateway Events > Scheduled > Scheduled Script

def onScheduledEvent():
	project="My_Project"
	messageHandler="clientScriptTrigger"
	scope="GCS"
	myDict = {'message': " hello message"}
	
	results=system.util.sendMessage(project,messageHandler,myDict,scope)

Vision > Client Events > Message > clientScriptTrigger

def handleMessage(payload):
	script.run()

This runs "script.run()" in the client scope from a gateway event.

You can use system.util.sendMessage() to send a request to a client to run the scripts.

Unfortunately the Vison Client Events do not have a Schedule Event like the Gateway Scheduled Event.

You will need to include a client ID or other mechanism to insure that only one client executes the script, otherwise all of the clients would execute the scripts.

system.util.sendRequest() is used if you're expecting a response, however, I am not sure if you can use that in a Gateway > Client context or not (a little unclear from the documentation).

Why are these scripts being executed externally? Are they using modules that are incompatible with Jython? Is there not a Java equivalent to that?

If you can give some information about what the scripts are doing, then perhaps we can provide some guidance on how to accomplish that internally to Ignition.

I am fully aware that there are instances where this is not possible, just wondering if it is perhaps possible but was given up on because while the python part of Jython can't do it. Perhaps Java can?

1 Like

Thank you for the response. In short, large, mulit-team repositories can be ran. Most deployments are in python3, which is installed on the PC.

Further reasons..
There are abstracted classes that would be cumbersome to migrate into Ignition as a structural example. Outdated libraries is another thing. The requests library has a urllib3 dependency. I tried to migrate to a urllib2 version and add to py-lib, but lost patience quickly. URL responses are much better handled with the requests python library rather than ignition's system.net.httpClient(). With it, I was not able to make a get request, which returned a log-in page, and hold onto the client to make the necessary log-in, post request.

Can you help me create a functional line of code with sendRequest or sendMessage? I've been trying for some time to get these working today.

Below is the example.
Project - I assume is the client name.
messageHandler - How does the client script receive this if it is instantiated on the gateway side?
payload = Is this the command I need to run? {system.util.execute([bat_path]}

`returnValue ` `=` `system.util.sendRequest(project` `=` `'ACME'` `, messageHandler` `=` `'test'` `, payload` `=` `{` `'hoursOn'` `:` `15` `})`

I appreciate any help with the low level questions.

system.util.sendRequest(project, messageHandler, [payload], [remoteServer], [timeoutSec])

  • Parameters

String project - The name of the project containing the message handler.

String messageHandler - The name of the message handler that will fire upon receiving a message.

Dictionary[String, Any] payload - A dictionary which will get passed to the message handler. Use "payload" in the message handler to access dictionary variables. [optional]

String hostName - Limits the message delivery to the client that has the specified network host name. [optional]

String remoteServer - A string representing a target Gateway Server name. The message will be delivered to the remote Gateway over the Gateway Network. Upon delivery, the message is distributed to the local Gateway and clients as per the other parameters. [optional]

String timeoutSec - The number of seconds before the sendRequest call times out. [optional]

https://docs.inductiveautomation.com/display/DOC81/system.util.sendRequest

system.util.sendRequest() doesn't have a scope argument because it can only target gateway scope. Messages to Vision Clients are only possible as "fire-and-forget" via system.util.sendMessage().

1 Like

I've found "Gateway Message Handlers" page is there "Client Message Handlers" page?

In "Gateway Event Scripts" I have a scheduled script.

project="My_Project"
messageHandler="clientScriptTrigger"
scope="GCS"
myDict = {'message': "hello message"}

results = system.util.sendMessage(project,messageHandler,myDict,scope)

The only way I've found to receive this message is remaining in "Gateway Event Scripts" > "Message," referencing the script matching the messageHandler, "clientScriptTrigger"

def handleMessage(payload):
	script.run()

script.run() is in the Project Library and references file paths local to the PC running the client.

def run():
		bat_path = 'C:\\python_project_folder_in_client\\run.bat'
		system.util.execute([bat_path])

Receiving the message in "Gateway Message Handlers" executes the Project Library at the gateway PC scope still. How can Project Library scripts be triggered from a message and ran at the Client scope?

My indication of run() being executed at the Gateway level is a file modification I am making in run as well. The file path is being created in the Gateway PC and not modified in the Client PC. It's a .json file to pass parameters from the front end, ignition, to the back end, .bat executed code.

def run():
        config = {
                param": "test_string"
		}
		config_str = json.dumps(config)
		config_path =  'C:\\python_project_folder_in_client\\config.json'
        system.file.writeFile(config_path, config_str)

		bat_path = 'C:\\python_project_folder_in_client\\run.bat'
		system.util.execute([bat_path])

Define client message handlers in Project Menu > Client Event Scripts > Message

Project Menu > Scripting > Gateway Events > Message is the only path I can find to receive message events, but that is at the Gateway scope. I am asking how to receive messages at the client scope. Hypothetically a "Client Event Script."

Oops, looks like they're here now:

2 Likes

Wonderful! Thank you for directing there. Although the logs threw an error, it is communicating! The error in the logs is from the DispatchManager:

Gateway script MessageHandlerException, project 'My_Project',
message handler 'clientScriptTrigger':
com.inductiveautomation.ignition.common.script.message.MessageHandlerException:
The message handler "clientScriptTrigger" could not be found!
Check your event script message handlers.

It seems to have found it though....

Your scope is set to send everywhere. So the gateway is also trying to find that named message handler. Set your scope to just "C" to target just Vision clients.

1 Like