Browse tags printing folder

Use .isFolder() to filter out folders, and also turn off recursion if you don’t want tags that are included in the folders.

tags = system.tag.browseTags(parentPath="System1/Efficiency", recursive = False)
for tag in tags:
    if not tag.isFolder():
       print tag.path

@lrose thank you! I want tag path because i want to reset them all all at midnight with something like the full code below:

# Grabs current Date and Time
getDateTime = system.date.now()
# Returns current hour in a 0-23 format
getHour = system.date.format(today, "H")
# Creat array to store tag paths
resetPaths = []
# Checks if time is Midnight
if getHour == 0:
# Gets all tags in folder sub structure and writes to an array
	tags = system.tag.browseTags(parentPath="System1/Efficiency", recursive = True)
	for tag in tags:
    if not tag.isFolder():
    	# Wrties tag path to array
       	resetPaths.append (tag.path)
       	# Writes a 0 to clear all tags in array
		system.tag.writeAll(resetPaths,0)

And I’ll run it in a timer script to check once an hour. Just not sure if client or gateway timer script would be better?

Definitely gateway timer script. A client timer script will 1. only work if there’s at least one client running, and 2. be run by each client you have open.

1 Like

Quick back track @PGriffith and @lrose I’m getting the below error with the above code:
error

All of the indentation must match. Meaning you can’t mix and match “spaces” and “tabs”.

When I typed in the script I used spaces, so you probably just need to fix that.

1 Like

In your script the system.tag.writeAll() should be outside of the for loop. You only want to call it once. You will also need to provide it with a list of values, that matches list of paths.

# Grabs current Date and Time
getDateTime = system.date.now()
# Returns current hour in a 0-23 format
getHour = system.date.format(today, "H")
# Creat array to store tag paths
resetPaths = []
# Checks if time is Midnight
if getHour == 0:
# Gets all tags in folder sub structure and writes to an array
	tags = system.tag.browseTags(parentPath="System1/Efficiency", recursive = True)
	for tag in tags:
        if not tag.isFolder():
    	    # Wrties tag path to array
       	    resetPaths.append (tag.path)
    # Writes a 0 to clear all tags in array
    system.tag.writeAll(resetPaths,[0] * len(resetPaths))

Thank you, I went line by line and found it.

@lrose as I ponder this could I remove the 0 from the array to set them ‘blank’ I just used 0 because I assumed a value had to be written.

You could potentially use None if that is what you mean. I suppose it just depends on the types of the tags you are writing. For integers None is essentially 0.

fair enough, i guess a 0 works more universally per say.

@lrose Hey so I cam back today to no tags reset. It’s in a gateway event timer script set to 3,600,000 fixed rate.

I tried manually running script in script console replacing 0 with current hour, but no tags got cleared.

I tried moving the reset array to a var. but still no luck. Not sure why it’s not resetting anything.

Also there are only string and integer type tags. I’d assume the writing a 0 would work. I don’t get any errors.

Do you have any logging in the script? Do you see any errors in the Wrapper Logs? What are the types of the tags you are resetting and are they all the same type?

@lrose No logging in the script. Nothing in the console logs which i believe is the same as the wrapper log.

some are string and integers
some are opc, memory and expression

I did try adding some logging at the bottom. Not seeing anything. Maybe I’m doing it wrong lol idk.

I appreciate the help.

0 is not the same as "" is not the same as null/None - you probably have to write the correct initial value type for the tag’s type. You could read the data type and have a simple dictionary of tag types : initial tag values.

@PGriffith I tired this code below with no avail:

# Grabs current Date and Time
getDateTime = system.date.now()
# Returns current hour in a 0-23 format
getHour = system.date.format(getDateTime, "H")
# Creates array to store tag paths
intPaths = []
stringPaths = []
# Checks if time is Midnight
if getHour == 7:
# Gets all tags in folder sub structure and writes to an array
    tags = system.tag.browseTags(parentPath="System1/Efficiency", recursive = True)
    for tag in tags:
        if not tag.isFolder():
            if tag.dataType == Int4:
    	    # Wrties tag path to array
       	        intPaths.append (tag.path)
       	    elif tag.dataType == String:
       	        stringPaths.append (tag.path)
    # Creates array for reset values
    resetInt = [None] * len(intPaths)
    resetStr = [""] * len(stringPaths)
    # Writes a 0 to clear all tags in array
    system.tag.writeAll(intPaths,resetInt)
    system.tag.writeAll(stringPaths,resetStr)

I think it has something to do with the for loop. because right now I can not print tag paths right under for tag in tags.

When I delete the code above the for loop and remove indents i can print tag.path to the console. but not with the above code.

The console log is not the same as the wrapper log.

Here is a small example of using a logger.

This:

if tag.dataType == Int4:

Doesn't do what you think it does. Int4 is a type, tag.dataType returns a string value returns a com.inductiveautomation.ignition.common.sqltags.model.types.DataType. The two can never be equivalent.

if tag.dataType == 'Int4':
    #do something
elif tag.dataType == 'String':
   #do something else
I would also use 0 for the default value for Integers. Also, instead of calling writeAll twice, combine the lists first and then call writeAll ``` paths = intPaths + stringPaths values = resetInt + resetStr system.tag.writeAll(paths,values) ```

Edit: See @PGriffith's code below

from com.inductiveautomation.ignition.common import TypeUtilities

# Grabs current Date and Time
getDateTime = system.date.now()
# Returns current hour in a 0-23 format
getHour = system.date.getHour24(getDateTime)
# Creates list to store tag paths
paths = []

# Checks if time is Midnight
if getHour == 7:
	# Gets all tags in folder sub structure and writes to an array
    tags = system.tag.browseTags(parentPath="folder", recursive = True)
    for tag in tags:
        if not tag.isFolder():
        	paths.append((tag.path, TypeUtilities.getInitValueForClass(tag.dataType.javaType)))
        	
    paths, values = list(zip(*paths))
    system.tag.writeAll(paths, values)
3 Likes

@PGriffith that worked like a charm! Now if I can just learn from your code and understand what you did. lol. If you could explain a little more in depth how your code works I’d be very appreciative.

There are just a few tags I’ll need to work on including that im sure are somewhere else. maybe write that tag to another one in a subfolder so this works 100% for me. But that should be easy.

I’d just really like to do some googling and understand it so i’m capable of doing it in the future.

1 Like

Well, the short answer is that I cheated a bit :slight_smile: It helps a lot to just know about this stuff already; discoverability isn't great.

But, starting from the top with changes I made:

TypeUtilities is a Java class we use everywhere in Ignition. Conveniently, Jython allows you to bring in Java classes just like they're Python code. Java uses reverse-domain-name addressing for packages (because class names must be globally unique) - the com.inductiveautomation isn't looking anything up over the internet or anything, it's basically just addressing the local dependency.
We publish a Javadoc for each new release - a bundled set of documentation explaining our (public) code: Javadocs & Notable API Changes · inductiveautomation/ignition-sdk-examples Wiki · GitHub

You can search for TypeUtilities in any of those: TypeUtilities
And find the getInitValueForClass method:
TypeUtilities

Note that this takes a single argument of type Class - Java's equivalent to Python's type(). More on that in a minute.

This line is adding a tuple (constructed with parentheses) to the existing paths list.
Another way to write it would be:
paths.append(tuple(tag.path, TypeUtilities.getInitValueForClass(tag.dataType.javaType)))
A tuple is an immutable sequence of values. In this case, we're using two elements, but a tuple can have any number of elements (including zero).
The first element is the tag's path. For the second, we're using the TypeUtilities method we found earlier to store the type-appropriate "initial" value. To get that initial value, we start from the tag object's dataType. I had initially thought the same as @lrose, that the dataType would be a string, but it turns out to be an instance of DataType - you can find this out by doing a print type(tag.dataType), which will give you something like this: <type 'com.inductiveautomation.ignition.common.sqltags.model.types.DataType'>
If you look at the DataType class (which you can find in the Javadocs linked above for ~most arbitrary classes you find in Ignition), you'll see it has a getJavaType() method. Java doesn't have properties, and instead generally uses "getter" and "setter" methods to retrieve or change a given object's properties. Jython conveniently unwraps these getX/setX methods into properties - so tag.dataType.javaType is actually calling tag.dataType.getJavaType() for you. This retrieves a Class instance for us, which we then pass to the TypeUtilities method.

So at this point your paths list is going to be a data structure that looks like this:

[
	("intPath", 0),
	("stringPath", "")
]

But system.tag.writeAll requires two lists - paths, and values. So we're going to use the builtin function zip to (confusingly) unzip the list we have, by spreading paths into it with the * operator. If it helps - this is not something I remember how to do offhand. Instead I googled for 'python list of tuples into two lists' and found this StackOverflow thread: python - How to convert list of tuples to multiple lists? - Stack Overflow

So list(zip(*paths)) unzips our list, which means our data will look like this:

[
	("intPath", "stringPath"),
	(0, "")
]

We can then use another Python function called unpacking to turn that new list into two new variables, which is what the paths, values = part is doing:

3 Likes