# Active and Unacked Tag Doesn't Match Alarm Table

**URL:** <https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279>\
**Category:** Ignition\
**Tags:** ignition81\
**Created:** [August 28, 2024, 4:09pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279 "2024-08-28T16:09:40Z")\
**Posts on this page:** 16\
**Page:** 1

<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:** [August 28, 2024, 4:09pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/1 "2024-08-28T16:09:40Z")

</div>

I have an alarm table that shows alarms that are all active and acked.  
I have an expression tag that is the system tag for the active and unacked alarm count.

The table shows no active and unacked tags (minimum priority is diagnostic) but the tag counts 6 active and unacked tags.

I also have 10 shelved alarms. Do shelved alarms retain there unacked status if shelved before being acked? If so, how do I require that alarms be acked before shelving, or automatically ack the alarm if it's being shelved?

I'll have to do something with the `onShelve` [extension function](https://docs.inductiveautomation.com/docs/8.1/appendix/components/vision-components/alarming/alarm-status-table/alarm-status-table-scripting#onshelve). Where can I find more info on the format of "alarms"?

Tried: `system.alarm.acknowledge(alarms)` and that did not work.

Printing to the console, `alarms` looks like this:

```python
[{Source: 'prov:Area_01:/tag:Alarms/Odor_Control_Heat_Trace_ALM/ALM_IND:/alm:Alarm', Display Path: 'HDWK', UUID: 'b837ed7b-eb76-4ba8-b308-b394b4922243', Current State: 'Active, Acknowledged', Priority: 'Medium', Active Data: {ackPipeline=Alarms, setpointA=1.0, eventValue=true, activePipeline=Alarms, clearPipeline=Alarms, name=Alarm, eventTime=Wed Aug 28 11:22:35 CDT 2024, label=Odor Control Panel Heat Trace, priority=Medium, displayPath=HDWK, enabled=true}, Clear Data: null, Ack Data: {ackPipeline=Alarms, setpointA=1.0, ackUser=usr-prov:Users:/usr:admin, activePipeline=Alarms, clearPipeline=Alarms, name=Alarm, eventTime=Wed Aug 28 11:23:08 CDT 2024, label=Odor Control Panel Heat Trace, priority=Medium, displayPath=HDWK, enabled=true}, Runtime Data: {isShelved=false, shelfUser=usr-prov:Users:/usr:admin, shelveExpiration=null}}]

```

---

<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:** [August 28, 2024, 4:40pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/2 "2024-08-28T16:40:14Z")

</div>

Trying to print the UUID from the alarms object, assuming that's the ID I need for `system.alarm.acknowledge()`:

```python
print(alarm['UUID'] for alarm in alarms)

```

I get `<generator object <genexpr> at 0x4>`

---

<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:** [August 28, 2024, 4:44pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/3 "2024-08-28T16:44:41Z")

</div>

Try:

```python
for alarm in alarms:
   print alarm.id

```

---

<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:** [August 28, 2024, 4:47pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/4 "2024-08-28T16:47:25Z")

</div>

Thanks. Issue was two-fold. I needed to use `.id` and I needed to print the results individually.

Easy enough now:

```python
ids = []
	if alarms:
		for alarm in alarms:
			ids.append(str(alarm.id))
			
		system.alarm.acknowledge(ids, '')

```

---

<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:** [August 28, 2024, 4:55pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/5 "2024-08-28T16:55:51Z")

</div>

Golf:

```python
if alarms:
    system.alarm.acknowledge([str(alarm.id) for alarm in alarms], "")

```

---

<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:** [August 28, 2024, 4:59pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/6 "2024-08-28T16:59:21Z")

</div>

You don't need the `if alarms` check, assuming it's checking if it's empty.  
If you iterate through an empty list, then nothing will happen, no error there.  
If it can be null, that's a different story, but in this case I'd suggest making this explicit:

```python
if alarms is not None:
    ids = [str(alarm.id) for alarm in alarms]
else:
    ids = []

```

or, to golf it further:

```python
ids = [str(alarm) for alarm in alarms or []]

```

---

<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:** [August 28, 2024, 5:02pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/7 "2024-08-28T17:02:10Z")

</div>

This list is straight from the alarm table, so I don't think it will ever be null. But an extra check won't hurt anything.

I'll take readability over golf, considering I'm the only SCADA guy at my empolyer that _knows_ let alone _ **likes** _ text-based languages.

---

<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:** [August 28, 2024, 5:03pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/8 "2024-08-28T17:03:01Z")

</div>

I'd argue that a proper comprehension is way more readable than explicit loops and appends...

---

<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:** [August 28, 2024, 5:05pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/9 "2024-08-28T17:05:53Z")

</div>

List comprehension is one of the new things that I had to learn with more Python exposure. I like them now, but with limited exposure I did not like it, initially. It can be alot to read if you're not used to reading the 'list comprehension sentences"

---

<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:** [August 28, 2024, 5:12pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/10 "2024-08-28T17:12:54Z")

</div>

> [@pascal.fragnoud](#):
>
> I'd argue that a proper comprehension is way more readable than explicit loops and appends...

Eh, while I generally agree with you I've become aware of a whole category of folks who prefer imperative loops (whether from genuine preference or a dogged insistence that X language worked that way, so should Python).

I've also soured somewhat on comprehensions in general after having seen the light of functional operations and method chaining, e.g. Java streams, Kotlin collection extension methods, Linq in C#, etc. Python just goes out of its way to make those awkward to use, especially in Python 2's syntax.

Bonus, extra silly:  
👎

```python
ids = [str(alarm) for alarm in alarms or []]

```

👍

```python
ids = map(lambda a: str(a.id), alarms)

```

It saves six whole characters! 😆

---

<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:** [August 28, 2024, 5:17pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/11 "2024-08-28T17:17:03Z")

</div>

Save 6 characters, confuse 100's of beginner programmers

---

<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:** [August 28, 2024, 5:17pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/12 "2024-08-28T17:17:31Z")

</div>

> [@paul-griffith](#):
>
> It saves six whole characters! 😆

And no comprehension involved ! What more could you possibly ask for ?

---

<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:** [August 28, 2024, 5:18pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/13 "2024-08-28T17:18:56Z")

</div>

Here's a prime example of where list comprehension can go overboard, especially if a newish Python dev is reading it:

```python
if not areas:
		tagsToWrite = [tag + suffix for tag_list in area_tags.values() for tag in tag_list]
	else:
		tagsToWrite = [tag + suffix for area,tag_list in area_tags.items() if area in areas for tag in tag_list]

```

I wrote it, I know it works, but I have to reread it a couple times every time I come back to it.

I digress...

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [August 28, 2024, 5:27pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/14 "2024-08-28T17:27:22Z")

</div>

> [@paul-griffith](#):
>
> method chaining

One must be careful to ensure that you actually stream through these, instead of constructing then discarding intermediate lists. Another gotcha for casual programmers.

---

<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:** [August 28, 2024, 5:33pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/15 "2024-08-28T17:33:49Z")

</div>

Assuming `areas` can't be null, you can remove the checks and keep the second comprehension only. Same deal as the `alarms` earlier.

I don't think it's overboard, it's a pretty simple nested comprehension. The condition inside makes it a bit funky, but...  
You can make things easier by decomposing it on several lines:

```python
tagsToWrite = [
	tag + suffix
	for area, tag_list in area_tags.items() if area in areas
	for tag in tag_list
]

```

But you can usually make things cleaner with `itertools`.

---

<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:** [August 28, 2024, 5:34pm UTC](https://forum.inductiveautomation.com/t/active-and-unacked-tag-doesnt-match-alarm-table/95279/16 "2024-08-28T17:34:03Z")

</div>

Hey, digression's fun.

I'm a big proponent of using whitespace to make things like that more clear:

```python
if not areas:
    tagsToWrite = [
        tag + suffix 
        for tag_list in area_tags.values()
        for tag in tag_list
    ]
else:
    tagsToWrite = [
        tag + suffix
        for area, tag_list in area_tags.items()
        if area in areas
        for tag in tag_list
    ]

```

But I would probably also extract the filtering portion from the joining logic, so you've got a statement that returns `tag_list` separate from your statement that returns `tagsToWrite`
