Query mutilple tags with system.tag.query()

Can you query multiple tags using system.tag.query() ? (or something similar)

Current aproach is using system.tag.readBlocking() 3 times to get the corresponding neccesary tags in the same order.

Thank you!


If you are curious on what I'm working

Expected result is something like:
Note that EACH column is a list of tags.

Tag Active Tag Value Tag Code
True 0.5 0001
False 0.0 0002
False 0.0 0003
True 0.5 0004
False 0.0 0005

Then I get the Code from the oldest timestamp from Value that has Active = True and save it in another tag.


Solution to my problem not to what the tittle says. Fast answer to tittle: No (at least in 8.1.38).

What do you mean by this?

The return order is guaranteed to match the supplied tag path list, so you should only need to call readBlocking() once.

As far as system.tag.query() it really depends on what you are needing. The function is really just a scripting implementation of the Tag Report Tool, so if you can configure the query in the tag report tool to get the results you're looking for, then the function can also return those results.

1 Like

3 times because I need 3 tags.

So I get 3 lists of Tag Active, Tag Value and Tag Code

Then I get the expected result using those 3

readBlocking takes a list of tags, will read all tags, and returns a list of fully-qualified tag values. As Louis said, you only need to call it once.

tagPaths = [...]
tagValues = system.tag.readBlocking(tagPaths)
for qv in tagValues:
    print qv
4 Likes

And to echo these other folks: if you're calling readBlocking multiple times in a row with single tag paths, your script is wrong, and you've stumbled onto one of the most common performance footguns in scripting.

Each readBlocking call from the client/designer implies at least two network hops - one to send out the list of tags, another to return the values from the gateway. Calling the function multiple times means you're paying that pain in series.

Calling from the gateway/in a Perspective context is less bad, but still not ideal for performance.

3 Likes

You can also do something like:

values = system.tag.readBlocking(tagPaths)
TagActive, TagValue, TagCode = [v.value for v in values]
3 Likes

I will have to create a list of the 3 list of tags that I have. Something like:

path_active = ["path1", "path2", "path3"]
path_value = ["path4", "path5", "path6"]
path_code = ["path7", "path8", "path9"]

path_all = tag_active + tag_value + tag_code

tag_list = system.tag.readBlocking(tag_all)

# Using list comprehension to create chunks
# Literally copied for showing in example. NOT TESTED
tag_list = [a[i:i + len(tag_active)] for i in range(0, len(a), len(tag_active))]

tag_active = tag_list[0]
tag_value = tag_list[1]
tag_code = tag_list[2]

As a note; paths will be like folder/udtN/active, folder/udtN/value and folder/udtN/code where N is a number.

@PGriffith is this even better than doing 3 readBlocking. Feels like it isn't for the added complexity.

Yes, how quickly will your 3 calls now balloon into 300?

Also, you can do something like this (breaking out the logic to a function):

def chunker(seq, size):
    return (seq[pos:pos + size] for pos in xrange(0,len(seq),size))

tagValues = [qv.value for qv in system.tag.readBlocking(pathAll)]
tagActive , tagValue, tagCode = [chunk for chunk in chunker(tagValues,3)]

Also, if you're doing this in a tagValue change script, don't. Move it to a Gateway Tag Change script. ValueChange scripts can't tolerate the round trip latency of tag reads (especially blocking ones).

2 Likes

Hello everyone!

Just wanted to share my final solution:

	tag_path_list = [x.get("fullPath") for x in system.tag.browse(folder_path)]

	tag_list_active = [str(path) + "/IsActive" for path in tag_path_list]
	tag_list_current = [str(path) + "/CurrentValue" for path in tag_path_list]
	tag_list_code = [str(path) + "/ReasonCode" for path in tag_path_list]

	tag_list_all = tag_list_active + tag_list_current

	tag_list_all = system.tag.readBlocking(
		tag_list_all
	)

	index = -1
	min_current = float('inf')
	n = len(tag_list_active)

	tag_list_active = map(lambda x: x.value, tag_list_all[:n])
	tag_list_current = map(lambda x: system.date.toMillis(x.timestamp), tag_list_all[:n])

	for idx, (active, current) in enumerate(zip(tag_list_active, tag_list_current)):

		if active and current < min_current:
			min_current = current
			index = idx

	if index != -1:
		
		reason_code = system.tag.readBlocking(
			[tag_list_code[index]]
		)[0].value

		system.tag.writeAsync(
			["[UNS]to/path/AlarmCode"], [reason_code]
		)