Best Practices for Waiting for PLC

Suppose that you have a button that restarts all devices connected to the PLC and then performs some other actions. What are the best practices for waiting for the PLC to restart the devices?

My approach would be something like this (I’m not much of a PLC programmer or Ignition for that matter):

# button click calls a gateway script
result = RestartDevices()

if not result['success']:
	system.perspective.openPopup("ResartDevicesError",'Popups/ErrorMessage', params = {'error':result['message']}, title = "Error Resetting Device", modal = True)	
import time

def RestartDevices():
	# gateway script writes to the PLC to tell it to begin the restart

	result = {
		'success': True,
		'message': ''
	timeout = time.time() + 10   # 10 seconds from now
	while True:
		 # gateway script waits for a response to the restart, or times out
		# check to see if the PLC is finished with the restart
	    restartComplete = (system.tag.readBlocking([startedRestart]) > 0 
	    					and system.tag.readBlocking([finishedRestart]) > 0)
	    if restartComplete: 
	    	if system.tag.readBlocking([finishedRestart]) > 1:
	    		# there was an error
	    		result['success'] = False
	    		result['message'] = 'The restart had errors'
	    		return result	    		
	    	# the restart ended finished successfully	
	    if time.time() > timeout: 
	    		# there was a timeout
	    		result['success'] = False
	    		result['message'] = 'The restart timed out'
	    		if system.tag.readBlocking([startedRestart]) > 0:
	    			result['message'] += ' because the restart never finished'
	    			result['message'] += ' because the restart never started'	
	    		return result

	# do more stuff after restart
	return result

I was hoping you all might be able to steer me in a better direction.

Can you just put the logic you want to happen after it restarts into a tag change script on the “finishedRestart” tag?

That’s a possibility, but while my example showed only one device to be restarted, our real-world case has many devices that need restarted. From my perspective, the code is a lot better if you’re not jumping between 10 different tag change scripts. For example, if you wanted to add another device later, you might run into problems with which tag change scripts are calling which restarts.

Totally understandable, but you generally can’t block (or hard loop waiting, which is the same thing) a thread like this without gumming up other parts of the system.

If you are going to do it anyway, it’s best to do it inside an invokeAsync call which starts another thread, at which point you’re still dealing with asynchronous completion, but at least the code that runs after the blocking can remain local to the script.

1 Like

OK, thanks Kevin. So if I’m only waiting for one or two PLC responses, I’ll use the tag change scripts. And if I have a bunch of sequential waiting to do, I’ll use the invokeAsync method to avoid blocking the main UI thread. I also might add/remove a loading state to the UI before/after the invokeAsync call (to prevent any other scripts from being fired).

I would use a single tag change event that subscribes to all of the “device restart done” bits and caches their latest status in a script module top-level dictionary. When each update arrives, the script would update the cache and then use python’s all() built-in to check if they are all now true.

1 Like

That’s a good idea! What do you think about the case that it times out? For example, if 30 seconds passes between when I’ve asked the PLC to restart the devices and when it changes the “all devices restarted” tag, then how could you handle that?

Would an invokeLater call on the “request restart” tag that checks whether the other tag has changed work? If so, would you store the original “restart complete” tag value in memory?

And vice versa, if the tag changed after it timed out?

I would probably use a timer event that checks a timestamp for “beginning of restart” against current time. If it is a critical process condition, I’d do it in the gateway and set a memory tag that can be set to alarm.

If just a user-space timeout I’d use a timer component on the screen that does similar, but animates a count-down.

1 Like