Using TagBrowseTree's filterBrowseNode script to filter

I have a tag browse tree connected up to a time series chart in perspective and I'd like to filter out some of the tags based on whether History is enabled for that tag. I found some documentation which I'll post below but I'm not completely sure how to put that into action. How would you get at the HistoryEnabled property in a node?

https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.16/com/inductiveautomation/ignition/common/tags/browsing/NodeBrowseInfo.html

In 8.X, you can read any property of a tag directly off the tag path. So you just add it to the end and get a true/false as the return value:

system.tag.readBlocking(["[default]Realistic0.HistoryEnabled"])

That makes sense under normal circumstances but this is a little more niche.
The tag browse component has a unique function built into that you need to set conditions on. My goal is to filter out tags that don't have history enabled so what I think I'm looking for is something like:
if node.[blank] is False:
return false

Where the blank is the HistoryEnabled property of the node

Ah, gotcha. Looks like you need to look through the NodeAttribute set, and then find one with an ID of history. Fairly simple to do with Python's builtin any:

	print any(attr.id == "history" for attr in node.attributes)

I might be missing something obvious so please bear with me:
The only place I've seen Nodes used is in the tag browse tree's filterBrowseNode script. I'm unclear on how we can run the node attribute search outside of that specific script. If we're working in the script console to try and print these attributes, how would you go about that?

The code inside system.tag.browse also uses NodeBrowseInfos, it just packages them into a dictionary before returning. I'm not really sure why the tag browse tree doesn't do the same, but c'est la vie. :grimacing:

You can look at the attribute IDs (if the ID is present, the attribute is set; if it's absent, it's not) with a script like this:

for tag in system.tag.browse("folder"):
	for key, value in tag.items():
		print key, value
	
	for attribute in tag["attributes"]:
		print attribute

Got it! The attribute was just called 'history' instead of 'HistoryEnabled' so that threw me off. Thanks so much for the help! I'll post my solution below in case anyone runs into this issue again:

def filterBrowseNode(self, node):
#Check for tag history.
historized = False
hasChildren = node.hasChildren()

#Search attributes for history (which is HistoryEnabled)
for attribs in node.getAttributes():		
	if "history" in str(attribs):
		historized = True

#Don't return unhistorized tags or tags w/ children (ie folders, udt structures)
if historized is True or hasChildren is True:
	return True	
else:
	return False

This script could be reduced to:

def filterBrowseNode(self,node):
    if node.hasChildren():
        return True

    return any(attr.id == 'history' for attr in node.attributes)

This is optimized. This code will short circuit, if the node is a folder (a.k.a. hasChildren) no need to loop through the attributes in that case, just return True. Also, once you've found that the node has the attribute you're looking for ('history') don't continue looping through the others, just return. In all other cases, just return false.

3 Likes

Good call! Thanks for the input :+1: