What's the best way to use system.tag.configure on an entire folder structure of tags?

I want to write a script that will search a tagpath recursively, and configure an alarm on each tag.

alarms = [{"name":"Alarm", "mode":"Equality", "setpointA":1}]
config = system.tag.getConfiguration("[default]", True)

#[{u'path': [default],
#  u'tagType': Provider,
#  u'tags': [{u'name': u'root level tag',
#             u'path': root level tag,
#             u'tagType': AtomicTag,
#             u'value': 1,
#             u'valueSource': u'memory'},
#            {u'name': u'root level folder',
#             u'path': root level folder,
#             u'tagType': Folder,
#             u'tags': [{u'name': u'nested tag',
#                        u'path': nested tag,
#                        u'tagType': AtomicTag,
#                        u'value': 2,
#                        u'valueSource': u'memory'},
#                       {u'name': u'nested folder',
#                        u'path': nested folder,
#                        u'tagType': Folder,
#                        u'tags': [{u'name': u'double nested tag',
#                                   u'path': double nested tag,
#                                   u'tagType': AtomicTag,
#                                   u'valueSource': u'memory'}]}]},
#            {u'path': _types_, u'tagType': Folder}]}]

for tag in config: # What type of iteration needs to go HERE so I hit every AtomicTag exactly once?
	tag['alarms'] = alarms
system.tag.configure("[default]", config, "o")

What is the best way, in python, to script going through a tag hierarchy dictionary like that? I can do it with a recursive function like this:

def make_alarms(tagdict):
	if "value" in tagdict.keys():
		tagdict['alarms'] = [{"name":"Alarm", "mode":"Equality", "setpointA":1}]
		return tagdict
	if "tags" in tagdict.keys():
		for tag in tagdict['tags']:
			tag = make_alarms(tag)
	return tagdict

Is this really the best way to accomplish this? Is there a simpler way?

Yep, that’s the best way afaik. I do this in my script tools and it’s super fast.
Not relevant here, but In python 3 you would need to convert the tagdict.keys() part to a list

Thanks for the reply! Do you agree that IA might want to add some kind of function to make this, and other similar operations, a little more simple? They added the recursive option to getConfig for a reason, and the whole point of getConfig is that you can make changes and then pass the object right back to system.tag.configure. If querying the tags recursively is as simple as 'recursive':True then maybe modifying tags recursively should be likewise simple?

Currently, although it does need some understanding of json and specifically the tag json structure, it does offer the ultimate flexibility in terms of configuring tags. I guess there could be some functions defined that work with this and do certain things for you. Might be worth a post in the ideas page
https://ideas.inductiveautomation.com/ignition-features-and-ideas

I think I will suggest it there, thanks!

I mean, before they added 'recursive':True you had to program your own recursive function to even browse tags recursively. But they realized that was rather inconvenient so they added the built-in option. But once you have your conveniently generated recursive tag structure, it’s impossible to do anything on the entire set without writing another recursive function.

Currently system.tag.getConfiguration returns a list (always of size 1, as far as I can tell) of tag dictionaries. What if instead it returned an object that could act like the tag dictionaries, but also had a method .modify(config, filters={}) that would search through the configuration and overwrite with the specified config, applying the specified filters?

alarms = [{"name":"Alarm", "mode":"Equality", "setpointA":1}]
config = system.tag.getConfiguration("[default]", True)
config.modify({"alarms":alarms}, {"tagType":"AtomicTag"})
system.tag.configure("[default]", config, "o")

Actually, the recursive option was always there (at least it has been since v7.x), it just had bugs when they remade it in v8 that got pushed back. It used to work but it wouldn't return the full path of the tag, just the name in the tags within folders, so they hid the option from documentation. You could still set it though :smile:

Sounds like a decent idea though, if you add it, be sure to copy the link to it back into this post in your OP

Disclaimer: Thinking out loud, not suggesting this will ever happen.

I could envision something like a call that combines system.tag.configure and system.tag.getConfiguration - something that allows you to define your (possibly recursive) browse, and specify a visitor function that will fire for each item it visits - allowing you to do whatever modifications you had. That would probably be easier to implement (and in my opinion, better style) than wrapping browse results in a different class; in my perfect world, basically every scripting function just returns a native Python data structure where possible.

4 Likes

You heard it here first, folks... 8.1.6 confirmed.

But seriously, I like that implementation much better honestly. The "visitor function" would be of the level of simplicity we've come to expect for ignition scripting. AND it lets you be more flexible than just a filter query. You can do some complex stuff to decide what to do with any specific tag!

4 Likes