Script library variables and reading tag values

I wanted to cache some tag values that are basically set once via query when Ignition starts, cache them inside a script library's variables like this:

TAG1 = system.tag.readBlocking('path')[0].value

so then I can refer to that instead of having to read the tag each time I need it in a script

project.util.TAG1

However, just recently the GW had a patch update applied and it rebooted, and scripts that were using the value were failing due to TAG1 being None.

I assume that this is because when it rebooted, the tag system wasn't up yet before the scripting system was and before the library had initialised, hence the None value trying to read the tag that wasn't there yet. Is this correct?

What would be the best way to resolve this? For now I'm just going to use a dreaded while with time.sleep to check if it's null and keep reading it until it isn't :confused:
I figure a sleep at such an early once off init stage isn't going to have an effect

No harm in reading the tag if you need to.

Instead of reading the variable, call a function, the function can simply check that the value isn’t 'None' and return the top level variable value, or if it is, read the tag, set the variables value, and then return.

This way you essentially have the same processing time, but can read the tag if needed.

3 Likes

This is an extremely bad idea in the load path of a script module. Don't do it.

And the observed behavior shouldn't be a surprise--tags use event scripts, so scripts must load before tags.

Consider caching as @lrose suggests, but use the query in the script, not the tag.

3 Likes

You could always add a timer script to check if your global script variables are None and then run the script if it is None.

I'm implementing something along the lines of @lrose's and @pturmel's suggestions, but I'm stumped at something I found.

If I put this into a script library project.util:

TEST = None
TEST2 = None
TEST3 = None
TEST4 = NONE
def setTest():
	global TEST
	TEST = 'Hello'
def getTest():
	setTest()
	return TEST

def setTest2():
	global TEST2
	TEST2 = 'Hello2'
def getTest2():
	project.util.setTest2()
	return project.util.TEST2

def setTest3():
	global TEST3
	TEST3 = 'Hello3'
def getTest3():
	setTest3()
	return project.util.TEST3

TEST4 = None
def setTest4():
	global TEST4
	TEST4 = 'Hello4'
def getTest4():
	project.util.setTest4()
	return TEST4

and run from the script console:

print project.util.getTest()
print project.util.TEST
print
print project.util.getTest2()
print project.util.TEST2
print
print project.util.getTest3()
print project.util.TEST3
print
print project.util.getTest4()
print project.util.TEST4

I get:

>>> 
Hello
Hello

Hello2
None

None
Hello3

None
None

Can someone explain why print project.util.TEST2 isn't equal to Hello2? and why print project.util.getTest3() isn't equal to 'Hello3'? and both test 4's result in None?

I normally like to include the full library references to make finding things simpler... but maybe I shouldn't be doing that??

I also think maybe I should be using system.util.getGlobals() instead of module variables

IMHO system.util.getGlobals() is the best solution to persist data in the gateway scope and avoid reset on script frequent reload

Even using getGlobals has the same issue :confused:

Nevermind that.. I was just being dumb, it does work, just more annoying in terms of accessing the variables.

I'm still very curious to know why my other tests resulted in what they did though

No, but consider running that test from a button (Vision and Perspective) instead of the script console.