# Tag that summarises/aggregates child tags

**URL:** <https://forum.inductiveautomation.com/t/tag-that-summarises-aggregates-child-tags/68359>\
**Category:** Ignition\
**Created:** [January 9, 2023, 7:17am UTC](https://forum.inductiveautomation.com/t/tag-that-summarises-aggregates-child-tags/68359 "2023-01-09T07:17:57Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Matthew\_Farmer](https://avatars.discourse-cdn.com/v4/letter/m/e274bd/32.png) [@Matthew\_Farmer](https://forum.inductiveautomation.com/u/Matthew_Farmer)\
**Post date:** [January 9, 2023, 7:17am UTC](https://forum.inductiveautomation.com/t/tag-that-summarises-aggregates-child-tags/68359/1 "2023-01-09T07:17:57Z")

</div>

I want to have a tag structure for the factory that summarises (a dynamic number of) child tags, as you look up the tree. For example I have a "line" UDT that has multiple "cell" UDTs below it. I want the "OEE" and "Status" tags in the "line" to be expression tags that summarise the corresponding tags on the child "cell"s. An example simplified structure:  
Line  
-Status  
-OEE  
-Children (Dataset of paths to the cell tags)

Cell  
-Status  
-OEE

What I want is for the "line/OEE" tag to be an average of the child tags (The final implementation will pass the more data, not the top level OEE, but this is a simplified example):  
Pseudo code

```auto
OEEsummary = 0
foreach child in line.Children
    OEEsummary += tag(child + "/OEE")
line.OEE = OEESummary/line.Children.Count

```

For the Status tag I have a feeling the business logic will get very complicated (Based off what managers want shown at their level), so for the moment I will just say that the tag should be the max (Worst case) value:  
Pseudo code

```auto
MaxStatus= 0
foreach child in line.Children
    childStatus = tag(child + "/Status")
    if(childStatus > MaxStatus) MaxStatus = childStatus
line.Status = MaxStatus

```

I have not found a way of achieving this yet. I would prefer this is done as expressions so the code lives within the tags, but maybe this is only achievable with Python?

---

<div class="post-metadata">

**Author:** ![etknorr](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/etknorr/32/33184_2.png) [@etknorr](https://forum.inductiveautomation.com/u/etknorr)\
**Post date:** [January 9, 2023, 8:50am UTC](https://forum.inductiveautomation.com/t/tag-that-summarises-aggregates-child-tags/68359/2 "2023-01-09T08:50:09Z")

</div>

You can write a script for this, then use the `runScript` expression ([documentation](https://docs.inductiveautomation.com/display/DOC81/runScript)) on the tag to run the script.

Expression on the line/Status tag:

> runScript("line.getStatus", [pollRate], {[.]Children})

Expression on the line/OEE tag:

> runScript("line.getOEE", [pollRate], {[.]Children})

(you'll have to choose a reasonable poll rate in ms for your application)

Where the Project Script "line" has the following function:

```auto
def getOEE(childrenTags):
    tags = ["%s/OEE" % childTag for childTag in childrenTags]
    tagRead = system.tag.readBlocking(tags))
    return sum(tagRead)/len(tagRead)

def getStatus(childrenTags):
    tags = ["%s/Status" % childTag for childTag in childrenTags]
    return max(system.tag.readBlocking(tags))

```

Might not be exactly correct, but should get you started.

---

<div class="post-metadata">

**Author:** ![Matthew\_Farmer](https://avatars.discourse-cdn.com/v4/letter/m/e274bd/32.png) [@Matthew\_Farmer](https://forum.inductiveautomation.com/u/Matthew_Farmer)\
**Post date:** [January 12, 2023, 4:55am UTC](https://forum.inductiveautomation.com/t/tag-that-summarises-aggregates-child-tags/68359/3 "2023-01-12T04:55:09Z")

</div>

Thanks for the help I almost have this working, but the data from the tag seems to be imported in a java format, not a python readable format.  
The function is:

```auto
def sumTags(tagArray, subTag):
    tags = [str(childTag) + subTag for childTag in tagArray]
    return sum([x.value for x in system.tag.readAll(tags)])

```

When called with a manually created object ["tag1","tag2"] it works perfectly. When a value is passed from a tag the input data is not formatted correctly (I have tried formatting the tag as both a dataset and an array).  
Printing out "tagArray" I see:  
`[[[Ljava.lang.String;@475a7e29, Good, Tue Jan 10 21:43:33 PST 2023 (1673415813054)]]`  
Printing "tags" from the for loop creates an output like this:  
`["array(java.lang.String, [u'tag1', u'tag2', u'tag3'])/OEE"]`  
The whole arrays seems to be seen as a single string based on the subtag text being appended to the end of the array string, not to the individual items

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [January 12, 2023, 2:38pm UTC](https://forum.inductiveautomation.com/t/tag-that-summarises-aggregates-child-tags/68359/4 "2023-01-12T14:38:12Z")

</div>

Can we see the full call of `sumTags` and the parameters you are passing?

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [January 12, 2023, 4:10pm UTC](https://forum.inductiveautomation.com/t/tag-that-summarises-aggregates-child-tags/68359/5 "2023-01-12T16:10:09Z")

</div>

> [@Matthew\_Farmer](#):
>
> ```auto
> def sumTags(tagArray, subTag):
> tags = [str(childTag) + subTag for childTag in tagArray]
> return sum([x.value for x in system.tag.readAll(tags)])
> 
> ```

Use `system.tag.readBlocking` (unless you're on a very old version).  
Also, use a generator expression instead of list comprehension:

```python
return sum(x.value for x in system.tag.readAll(tags))

```

This won't fix your issue though, but might as well improve things where that can easily be done.

---

<div class="post-metadata">

**Author:** ![Matthew\_Farmer](https://avatars.discourse-cdn.com/v4/letter/m/e274bd/32.png) [@Matthew\_Farmer](https://forum.inductiveautomation.com/u/Matthew_Farmer)\
**Post date:** [January 12, 2023, 10:55pm UTC](https://forum.inductiveautomation.com/t/tag-that-summarises-aggregates-child-tags/68359/6 "2023-01-12T22:55:07Z")

</div>

The two calls I am currently using (from the script console to get debugging) are:  
`print Business_Structure.sumTags(["tag 1","tag 2"], "/OEE")`  
Returns the correct integer  
`print Business_Structure.sumTags(system.tag.readBlocking("Children"), "/OEE")`  
Throws an error because the tags are one malformed string

The issue as I see it is a basic array is structured like this:

```auto
[
   tag1,
   tag2
]

```

The tag is theoretically structured like this:

```auto
[
    [
        tag1,
        tag2
    ],
    quality,
    date
]

```

But I can't seem to iterate over the inner array. If I try to nest for-loops I get:  
`TypeError: 'com.inductiveautomation.ignition.common.model.values.BasicQualifiedValue' object is not iterable`  
It seems like I need to cast that type to Python array

Note: I have simplified the tag paths for ease of reading

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [January 12, 2023, 11:09pm UTC](https://forum.inductiveautomation.com/t/tag-that-summarises-aggregates-child-tags/68359/7 "2023-01-12T23:09:04Z")

</div>

`system.tag.readBlocking` returns a _list_ of _qualified values_.

It looks like from your earlier post you're passing in a string array tag _qualified value_ as the 'list of tags to read':

> [@Matthew\_Farmer](#):
>
> `[[[Ljava.lang.String;@475a7e29, Good, Tue Jan 10 21:43:33 PST 2023 (1673415813054)]]`

`[Ljava.lang.String;@475a7e29` is the default Java `toString()` of a string array.  
The second layer of square brackets (`[[Ljava.lang.String;@475a7e29, Good, Tue Jan 10 21:43:33 PST 2023 (1673415813054)]`) is the `toString()` of the qualified value.  
The _last_ set of square brackets on the outside is indicating you've got a list of results.

You can either unpack things _before_ you pass them in to your `sumTags` function (generally preferred) or you can unpack them inside the function, but you _must_ do one or the other.

E.G:  
`print Business_Structure.sumTags(system.tag.readBlocking("Children"), "/OEE")`  
**Should** instead be:  
`print Business_Structure.sumTags(system.tag.readBlocking("Children")[0].value, "/OEE")`

You must get the first element of the list, then get the .value member, in order to reference _just_ the string array you care about.

---

<div class="post-metadata">

**Author:** ![Matthew\_Farmer](https://avatars.discourse-cdn.com/v4/letter/m/e274bd/32.png) [@Matthew\_Farmer](https://forum.inductiveautomation.com/u/Matthew_Farmer)\
**Post date:** [January 12, 2023, 11:59pm UTC](https://forum.inductiveautomation.com/t/tag-that-summarises-aggregates-child-tags/68359/8 "2023-01-12T23:59:15Z")

</div>

Thanks PGriffith

I type this out before you posted, so I may aswell post it:

Ok I have worked it out the value supplied by readBlocking() is an array of tags not a single tag, I need to reference the 0th item and iterate across the value property:

```auto
def sumTags(tagArray, subTag):
    tags = [str(childTag) + subTag for childTag in tagArray[0].value]
    return sum(x.value for x in system.tag.readBlocking(tags))

```

However after moving it back to the tag, it wasn;t working the value supplied by the expression `{[.]Children}` on the tag is just the value, not the tag, so it actually would have worked on the tag, even though it wasn't working in the scripting console, because I should have been using [0].value, when calling the method in the scripting console.

This is my first time working with Python and the weak typing here made this really hard to understand what was happening...  
Not seeing the actual Python errors on the tag also made it harder.
