system.nav.getCurrentWindow() in Client Tag Change scripts does not the expected behaviour

Hi!

I design an HMI on ignition vision. When I'm on a specific window, I need to wait that a modbus register changes from 0 to 1 to change to another window. To do this, I created a client tag change script on the modbus register. But I need to know if I'm in the specific waiting window to swap to the desired window (ex : don't swap to that window if the current window is the home page). So, on the event, I check the current opened window with "system.nav.getCurrentWindow()", but the function don't always return the window that is showing in the HMI. If there is other windows that are still opened in background, the function sometimes return one of those windows.

What is happening?

How can I get the "Currently showing window" in the client tag change scripts?

There is the complete script:

print event.tagPath
print initialChange
print newValue.value
current_window = system.nav.getCurrentWindow()
print "this is the current window : "
print current_window 
if current_window == "main_windows/rfid_successs" and newValue.value == 1:
	system.nav.closeWindow(current_window)
	system.nav.openWindow("main_windows/charging_2")
	system.tag.writeBlocking("[Sample_Tags]_Intesis OCPP 1_6 Modbus Gateway_/UnitId 0/trans_id0-trans_id0/trans_id0", 321)
	system.tag.writeBlocking("[Sample_Tags]_Intesis OCPP 1_6 Modbus Gateway_/UnitId 0/start_proces0-start_proces0/start_proces0", 1)

Thank you!

Tag Change Scripts are in a different scope than the GUI. Thanks for setting me straight @pturmel

You should create a custom property on the root container and bind it to the tag that represents the modbus register you want to wait for the change on. Then in the property change script of the root container you can filter for the custom property and when it changes to 1 execute any script that you want.

if event.propertyName == 'yourPropertyName':
    system.tag.writeBlocking(['[Sample_Tags]_Intesis OCPP 1_6 Modbus Gateway_/UnitId 0/trans_id0_trans_id0/trans_id0','[Sample_Tags]_Intesis OCPP 1_6 Modbus Gateway_/UnitId 0/start_proces0-start_proces0/start_proces0'],[321,1])
    system.nav.swapTo('main_windows/charging_2')

Notice that I combined your two writeBlocking() calls into a single call. This is the preferred way to use the function as it is much more efficient.

https://docs.inductiveautomation.com/display/DOC81/system.tag.writeBlocking

Also, notice that I have changed the order of the code so that you write to the tags prior to navigating away from the window. This guarantees that the tag write occurs before the window closes since writeBlocking() blocks the thread until it returns. If you don't want to wait to navigate, then consider using writeAsync() instead.

Since you are closing the current window and opening another, you can just use system.nav.swapTo(), the function closes the current window and opens the window at the provided path.

https://docs.inductiveautomation.com/display/DOC81/system.nav.swapTo

Emile specifically called out Client Tag Change Scripts, which are very much in client scope in Vision. But "current window" is only for main windows, and if there are more than one of those, the result is unreliable. Popups are not main windows.

But this is spot on.

Is there a ‘getActiveWindow’ or equivalent? I know that Ignition can differentiate between active windows because the ‘internalFrameActivated’ event listener exists.

This might work:

from java.awt import Window

def activeWindow():
	"""
	Returns the currently active window, if any, or else None.
	"""
	return next(w for w in Window.getWindows() if w.active)

I'd do:

def getActiveWindow():
    for w in system.gui.getOpenedWindows():
        if w.focusOwner:
            return w
    return None

Based on java.awt.Window.getFocusOwner().

1 Like

@pturmel the string representation of this object is simply the lowest project tree node of the window. Is there a way to get the full path of the window?

It is the actual window object. Don't stringify it. (If you are opening multiple instances of windows, duplicate names are possible. Use the object, not the name.) But look at the documentation. :man_shrugging:

Because the system/Client/CurrentWindow tag has the same unpredictable behavior as OP’s code, how would I go about creating a client tag that monitors the focusOwner?

The easiest answer is to not bother with a client tag - just run the script on demand wherever you need it.

2 Likes

So from the code below we were seeing that the system.nav.getCurrentWindow() was not printing the new opened window if the timeout was active. We changed to swapTo() and now it is updating will the client tag stay in any opened window if we don’t close it? I’m using Vision 8.1.38

print(system.nav.getCurrentWindow())

if system.nav.getCurrentWindow() != 'MainWindows/Login':
	# Read Username and User Roles from system client tags
	userRole = system.tag.readBlocking(['[System]Client/User/RolesString'])[0].value
	userName = system.tag.readBlocking(['[System]Client/User/Username'])[0].value
	
	# only run if not already logged in as default user
	# should be redundant now if checking window
	if 'default' not in userName.lower():
		
		# set different timeout for operator role
		if ('operator' in userRole.lower()) and (userRole.count(',') == 0):
			timeInactive = 3600
		elif (('engineer' in userRole.lower()) and (userRole.count(',') == 0)) or (('engineer' in userRole.lower()) and ('administrator' in userRole.lower()) and ('operator' not in userRole.lower())):
			timeInactive = 180
		else:
			timeInactive = 60
			
		print(timeInactive)
	
		# if timeout exceeded, switch to default account, go to login window, and close alarm popup
		if system.util.getInactivitySeconds() > timeInactive:
			system.security.switchUser('default','default')
			system.nav.swapTo('MainWindows/Login')
			system.nav.closeWindow('Popups/TemplateWindows/activeAlarmPopup')
			print(system.nav.getCurrentWindow())
			
elif system.nav.getCurrentWindow() == 'MainWindows/Login':
	if (system.util.getInactivitySeconds() > 10) and (system.tag.readBlocking(['[client]User/Login/username'])[0].value != ''):
		print("inactivity: " + str(system.util.getInactivitySeconds()))
		system.tag.writeBlocking(['[client]User/Login/username'], [''])

system.nav.getCurrentWindow() returns the same value as the Vision system tag for CurrentWindow. Neither can be used if you allow multiple main windows to be open at the same time. In other words, you must only use system.nav.openWindow() for popups (or docks), not for main windows. You MUST use system.nav.swapTo() for all main windows if you want .getCurrentWindow() to be accurate. That is the whole point of the workarounds in this topic: how to get the focused window even when not constraining main windows.

I assumed that might be the case but wasn’t 100% sure. Thanks for the info.