Detect project update from client in notify mode

Continuing the discussion from Update Project Programmatically: I just tried implementing @WillMT10’s solution to detect a newer project version ([System]Client/System/EditCount higher than it was when client was opened) in Ignition 7.9.9. It’s not working as it turns out this tag–at least in this version–reflects the edit count when client was opened/updated, not the edit count in available project update. Is there another way to detect from client scripting that a project update is available?

What we’d like to accomplish is have some clients update (via system.util.retarget back to themselves) when idle on a system set to notify (rather than push) updates.

1 Like

Could you do this with a client timer script checking idle time? Using the one provided with one of the starter projects, just have it call retarget if idle > x time and between certain hours of the day if needed. Might be the easier approach

1 Like

Thanks @Stevenson.Yuan. That's what we did (system.util.getInactivitySeconds followed by retarget), but we were hoping to only call it when there was a newer version available. Is there a way to check via scripting in client whether there is a newer project version (higher edit count) available?

@witman thanks for pointing this out. Was completely unaware that this no longer functions the same way in newer Ignition versions. I can only think of more clunky workarounds. (Could create a Gateway Memory tag that you have to manually change to some value when you want the client to retarget. When the client retargets, write to a Client tag the current value of the Gateway tag. Constantly compare these two tags in the Client Timer Script - or configure as a Tag Change Script - to know when to trigger the retarget.)

@Stevenson.Yuan - Can you confirm that this is indeed the intended way for these [System]/Client/System tags to work from now on (i.e. - only update their values after the client has applied the update)? If so, any chance a future Ignition version could include tags that have the most recent update information (EditCount, LastModifiedBy, and LastModifiedDate specifically) available to the client? These tools are really useful for getting screens up to date when they need to be. We often have many TVs displaying projects that users don’t interact with. So it would be nice to be able to get updates out to these TVs as soon as they are available while giving operators the option of delaying updates on their machines. The idle time is a less than ideal solution because it’s then a tradeoff between getting updates quickly (short inactivity time) and not interrupting the display with retargets (long inactivity time).

1 Like
from javax.swing import SwingUtilities
from com.inductiveautomation.factorypmi.application.runtime import InfoBar


def recSearch(obj):	
	result = False
	for sub in obj.getComponents():
		print "*"*10, type(sub)
		if not result:
			if isinstance(sub,InfoBar):
				print "FOUND"
				return True
			else:
				result = recSearch(sub)			
	
	return result

swRoot = SwingUtilities.getRoot(event.source)
print recSearch(swRoot)

This should work- you’ll need an initial component to kickoff the check if putting into timer script. Probably easiest to use getOpenedWindow and pass that in.

As for how that tag should work- I’m working with training and dev to determine the intent and update the user manual with the final response.

4 Likes

Thanks @Stevenson.Yuan. Just to make sure I’m on the same page, this is just looking to see if there is any info bar at the top of the client?

@witman Be aware that this script will capture the info bar at the top of the staging client (blue banner). So you will run into false positives with this method if you are running this in a Staging Client and haven’t closed the banner.

1 Like

Thanks @Stevenson.Yuan! That solution should do the trick. My 2 cents regarding tags: the current (v7.9.9) behaviour is what I would expect from [System]Client/System/EditCount. If we could get another tag something like [System]Client/System/EditCountUpdateAvailable (probably can come up with a better name) that would be slick.

Thanks @WillMT10, that’s good to know and might save a minute of head scratching. I imagine with a little more scripting we could get around the staging client infobar too, though I don’t have a solution off the top of my head.

1 Like

Yea it’s just looking for the infobar at top.

Looking at the infobar javadoc you could add something like:

if sub.getLabel().text == "Project update available. Click here to update."
   return True

under the isinstance check to prevent the false positive of the staging infobar…

4 Likes

Just in case anyone runs into trouble with this, I had to put this code inside a project/shared script and call this from the client script to get it to work. Seems like Client Event Scripts do not like recursive function calls when the function is defined inside the Client Event Script (at least in 7.9.3).

3 Likes

Works as desired; thanks! In case it helps someone else, the below updates on idle, re-opening all the windows that were open in the primary desktop after updating. It also prints a line to client console recording update.

Script in shared.gui (edit: improved with @cmaynes suggestion in following post):

from com.inductiveautomation.factorypmi.application.runtime import UpdateAvailableInfoBar

# Is an update available for client?
def getUpdateNotification(obj):
	result = False
	for sub in obj.getComponents():
		#print "*"*10, type(sub)
		if not result:
			if isinstance(sub,UpdateAvailableInfoBar):
				return True
			else:
				result = getUpdateNotification(sub)			
	return result

Script in client event timer script:

from javax.swing import SwingUtilities

# If client has been inactive for an hour, check for update.
if system.util.getInactivitySeconds() > 3600:
	# Get windows in main desktop where notification is shown.
	windows = system.gui.getOpenedWindows()
	# Get root of first window.
	root = SwingUtilities.getRoot(windows[0])
	# If there's an update notification, update client.
	if shared.gui.getUpdateNotification(root):
		# Get project name and opened windows.
		print "Found update notification info bar while idle. Updating client."
		projectName = system.tag.read('[System]Client/System/ProjectName').value
		openWindows = system.gui.getOpenedWindowNames()
		# Update by retargeting back to same project and open same windows.
		system.util.retarget(projectName, None, None, openWindows)
3 Likes

You can use the following class in place of checking the label text to make sure you found the update info bar:

from com.inductiveautomation.factorypmi.application.runtime import UpdateAvailableInfoBar
2 Likes

For anyone interested in completely controlling when they allow updates, you can remove the update bar so the user won’t be able to click it with…

sub.parent.remove(sub)

Note that this only works the first time. After you hide this once the update info bar will not appear again until you retarget the client, so you will need to keep track of the fact an update is pending if you are going to hold off.

In my case, I use client properties to keep a socket open. I need to properly dispose of the socket before allowing the client to update or I will have trouble opening another connection and will have to wait for the last one to timeout.

If I recall correctly, the dictionary from system.util.getGlobals() survives retargeting and scripting restarts. That’s where you should place your socket.

1 Like