# Alarm statistics perspective

**URL:** <https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074>\
**Category:** Ignition\
**Tags:** perspective, ignition81\
**Created:** [April 5, 2022, 9:30pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074 "2022-04-05T21:30:28Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![tupanaster](https://avatars.discourse-cdn.com/v4/letter/t/5daacb/32.png) [@tupanaster](https://forum.inductiveautomation.com/u/tupanaster)\
**Post date:** [April 5, 2022, 9:30pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/1 "2022-04-05T21:30:29Z")

</div>

Hi Everyone,

What is the best way of showing alarm statistics?

Looking at other posts, global alarm counters can be shown like this:

```auto
count_of_shelved_alarms = len(system.alarm.getShelvedPaths())
ActiveAcked = len(system.alarm.queryStatus(state=["ActiveAcked"]))
ActiveUnacked = len(system.alarm.queryStatus(state=["ActiveUnacked"]))
ClearUnacked = len(system.alarm.queryStatus(state=["ClearUnacked"]))

```

But what can be done when trying to show individual alarm counters?

alarm\_events table can be queried and a COUNT() can be done on the source in a date range. But from there, I’m not sure how to get the property “Label” of the alarm based on the source.

That made me wonder, what is the best approach for statistics using a variety of filters?

Some posts:  
[How to get total alarm duration and occurrences by alarm (NOV 2015)](https://forum.inductiveautomation.com/t/how-to-get-total-alarm-duration-and-occurrences-by-alarm/10758)  
[How to get total alarm duration and occurrences by alarm (DEC 2015)](https://forum.inductiveautomation.com/t/how-to-get-total-alarm-duration-and-occurrences-by-alarm/10873/4)  
[Get Alarm Counter](https://forum.inductiveautomation.com/t/get-alarm-counter/37810)  
[How to pull Associated Alarm Data from the alarm event list generated with system.alarm.queryStatus?](https://forum.inductiveautomation.com/t/how-to-pull-associated-alarm-data-from-the-alarm-event-list-generated-with-system-alarm-querystatus/27527/9)  
[Perspective alarm list with source filtering](https://forum.inductiveautomation.com/t/perspective-alarm-list-with-source-filtering/39801)

Some unanswered posts:  
[system.alarm.queryStatus vs system.alarm.queryJournal](https://forum.inductiveautomation.com/t/system-alarm-querystatus-vs-system-alarm-queryjournal/29332)  
[A friendly guide to count alarms](https://forum.inductiveautomation.com/t/a-friendly-guide-to-count-alarms/31281)

---

<div class="post-metadata">

**Author:** ![josborn](https://avatars.discourse-cdn.com/v4/letter/j/4bbf92/32.png) [@josborn](https://forum.inductiveautomation.com/u/josborn)\
**Post date:** [April 5, 2022, 10:00pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/2 "2022-04-05T22:00:10Z")

</div>

I would stick with using [system.alarm.queryStatus](https://docs.inductiveautomation.com/display/DOC81/system.alarm.queryStatus) or [system.alarm.queryJournal](https://docs.inductiveautomation.com/display/DOC81/system.alarm.queryJournal) vs querying alarm\_events. Also keep in mind alarm\_events is the alarm _journal_ data.

You can get the label like this, just add your own filters:  
`system.alarm.queryStatus()[0].label`

edit:  
This works also, though i don’t know if one is better or more correct:  
`system.alarm.queryStatus()[0].getLabel()`

---

<div class="post-metadata">

**Author:** ![tupanaster](https://avatars.discourse-cdn.com/v4/letter/t/5daacb/32.png) [@tupanaster](https://forum.inductiveautomation.com/u/tupanaster)\
**Post date:** [April 6, 2022, 12:37pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/3 "2022-04-06T12:37:13Z")

</div>

> [@josborn](#):
>
> I would stick with using [system.alarm.queryStatus](https://docs.inductiveautomation.com/display/DOC81/system.alarm.queryStatus) or [system.alarm.queryJournal](https://docs.inductiveautomation.com/display/DOC81/system.alarm.queryJournal) vs querying alarm\_events. Also keep in mind alarm\_events is the alarm _journal_ data.

Is there a reason?  
This:

```auto
SELECT FORMAT(eventtime, 'dd/MM/yyyy HH:mm:ss') AS "Event Time",source
FROM alarm_events
WHERE eventtype = 0 AND
eventtime >= :startDate AND eventtime <= :endDate
ORDER BY eventtime DESC

```

Looks easier than this:

```auto
system.alarm.queryJournal(journalName="AlarmLog", startDate=startDate, endDate=endDate,state=['ActiveUnacked'])

```

With the SQL statement you can get  
`prov:default:/tag:UDT tag:/alm:Alarm`

That's why I was thinking about (somehow) getting the label property out of the SQL results

---

<div class="post-metadata">

**Author:** ![josborn](https://avatars.discourse-cdn.com/v4/letter/j/4bbf92/32.png) [@josborn](https://forum.inductiveautomation.com/u/josborn)\
**Post date:** [April 6, 2022, 4:16pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/4 "2022-04-06T16:16:19Z")

</div>

Querying the table directly only works if you have an database alarm journal configured, and you would have to jump through some not insignificant hoops to get the label. You would need to parse the tag path out of the alarm source, then use [system.tag.getConfiguration](https://docs.inductiveautomation.com/display/DOC81/system.tag.getConfiguration) to get the label. ~~You also cant query active alarms at all that way.~~  
Edit:  
That was poorly worded, you cant query the info you see in the alarm status table might be a better way to say it.

---

<div class="post-metadata">

**Author:** ![tupanaster](https://avatars.discourse-cdn.com/v4/letter/t/5daacb/32.png) [@tupanaster](https://forum.inductiveautomation.com/u/tupanaster)\
**Post date:** [April 6, 2022, 7:32pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/5 "2022-04-06T19:32:24Z")

</div>

> [@josborn](#):
>
> Querying the table directly only works if you have an database alarm journal configured

I think an alarm journal is necessary to get statistics information. Because it's not about the current state, but looking up at past alarms to count them based on some filters.

> [@josborn](#):
>
> and you would have to jump through some not insignificant hoops to get the label.

After playing around with system.alarm.queryJournal(), I went back to SQL to finish the query that gets the label. I'm not sure it's right but at least I get some results.

```auto
SELECT COUNT(ae.eventtime) AS "Trigger count",aed.strvalue
FROM alarm_events AS ae
INNER JOIN alarm_event_data AS aed
ON ae.id = aed.id
WHERE 
ae.eventtype = 0 AND ae.eventtime >= :startDate AND eventtime <= :endDate
AND aed.propname = 'label'
GROUP BY aed.strvalue
ORDER BY COUNT(eventtime) DESC

```

I will give system.tag.getConfiguration a quick test.

> [@josborn](#):
>
> then use [system.tag.getConfiguration](https://docs.inductiveautomation.com/display/DOC81/system.tag.getConfiguration) to get the label.

Is the Report Module easier for this task?

---

<div class="post-metadata">

**Author:** ![josborn](https://avatars.discourse-cdn.com/v4/letter/j/4bbf92/32.png) [@josborn](https://forum.inductiveautomation.com/u/josborn)\
**Post date:** [April 6, 2022, 11:25pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/6 "2022-04-06T23:25:05Z")

</div>

I don’t think the report module would necessarily be easier, but with it you could create an alarm journal query data source then use a script data source to go through the dataset and perform your calculations. One benefit to this approach is that you can use any type of alarm journal.

Edit:  
Are you sure that sql query is doing what you want? I tried it on a testing alarm journal and it yielded zero results. I modified it to see what i was getting.

```auto
SELECT COUNT(ae.eventtime) AS "Trigger count",aed.strvalue, aed.propname as propname
FROM alarm_events AS ae
INNER JOIN alarm_event_data AS aed
ON ae.id = aed.id
GROUP BY aed.strvalue
ORDER BY COUNT(eventtime) DESC

```

Which gave me this:  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/6/b/6b974c4fc89f033b06a45b7579a6a8baddf21ff3.png)

---

<div class="post-metadata">

**Author:** ![tupanaster](https://avatars.discourse-cdn.com/v4/letter/t/5daacb/32.png) [@tupanaster](https://forum.inductiveautomation.com/u/tupanaster)\
**Post date:** [April 7, 2022, 7:24am UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/7 "2022-04-07T07:24:10Z")

</div>

> [@josborn](#):
>
> Are you sure that sql query is doing what you want? I tried it on a testing alarm journal and it yielded zero results. I modified it to see what i was getting.

I do get results and it looks good but I have to recheck. How come you got zero results?

In your query you left out the "where" statement, that's ok for the dates. But you would need "propname = label" as there is the alarm text. "eventtype = 0" would be just the activation event.

I'm not sure, I think event type values are from this table:  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/8/e/8e107f10ae83297499d51e99f0cecfabdd35b8d6.png)

I'm not sure what "dtype" refers to.  
Therese are the tablets from the alarm journal.

![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/b/8/b8ba8c56c090c5e2e9252b46f8397c80ecaa9b43.png)

Edit:  
I get an error when showing my named query on a perspective table.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/0/4/048e507bb7df6b2ae7dda31b4700b40e0d90e64a.png)

Not sure why... it's a common binding. No scripting on it.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/d/2/d2612fa1f0637c567e9bad84f4d7c95c00d055d2.png)

Edit 2:  
"Invalid Key" disappeared. I'm not sure why it was there in the first place.

Edit 3:  
I made a mistake when about the SQL tablets. Here is the documentation:  
[Alarm Journal](https://docs.inductiveautomation.com/display/DOC81/Alarm+Journal)

Alarm Events (alarm\_events)

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/8/8/88d0019463a5360f4649ddb49772ea4d5862b64d.png)

Alarm Event Data (alarm\_event\_data)

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/3/3/3380f1239e1f398227b0b3987a468ad49c09fed9.png)

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [April 7, 2022, 11:49am UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/8 "2022-04-07T11:49:24Z")

</div>

I caution you if you’re calling `system.alarm.queryStatus` from the client. In Vision, these can easily kill client performance. In Perspective, these can easily kill your gateway. Calling this function is expensive and doesn’t scale well.  
Consider calling this function once periodically in a script library to pull in all alarms and store the results in a library variable. Then filter that variable and summarise your alarms per area based on this instead.

---

<div class="post-metadata">

**Author:** ![tupanaster](https://avatars.discourse-cdn.com/v4/letter/t/5daacb/32.png) [@tupanaster](https://forum.inductiveautomation.com/u/tupanaster)\
**Post date:** [April 7, 2022, 12:10pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/9 "2022-04-07T12:10:14Z")

</div>

Thank you for the warning.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/f/7/f7a3baa5c6f805149ed2373c4ff2b30d7365da72.png)

I was looking at my memory usage working around 800mb-1000mb. Normally it’s 400-500mb.

Probably the increased workload is due to `system.alarm.queryStatus`.

SQL queries stress the system the same way?

---

<div class="post-metadata">

**Author:** ![josborn](https://avatars.discourse-cdn.com/v4/letter/j/4bbf92/32.png) [@josborn](https://forum.inductiveautomation.com/u/josborn)\
**Post date:** [April 7, 2022, 4:14pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/10 "2022-04-07T16:14:11Z")

</div>

> [@tupanaster](#):
>
> How come you got zero results?

Not sure, i left out the where clause entirely to try to find out. There are absolutely no labels in my data, despite having labels configured in my alarms.

I think this explains the invalid key warning:

> [@TimeSeriesChart and datasets](https://forum.inductiveautomation.com/t/timeserieschart-and-datasets/57321/2):
>
> The component is throwing the error because ‘series’ is meant to be an array of objects. Each object within the array expects a ‘data’ and ‘name’ property. This doesn’t require any transformation you can just rebuild property and move the binding down to the ‘data’ property. For example: [image]

---

<div class="post-metadata">

**Author:** ![tupanaster](https://avatars.discourse-cdn.com/v4/letter/t/5daacb/32.png) [@tupanaster](https://forum.inductiveautomation.com/u/tupanaster)\
**Post date:** [April 7, 2022, 5:27pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/11 "2022-04-07T17:27:22Z")

</div>

> [@josborn](#):
>
> Not sure, i left out the where clause entirely to try to find out. There are absolutely no labels in my data, despite having labels configured in my alarms.

That's weird. Try posting some screenshots. Maybe your new labels are not logged or you need to reset your trial for them to be logged.

How people mostly use alarms?  
"Name" property is not useful for a dynamic message because it's fixed.  
"Display Path" has the default path. I guess a dynamic message can built here but you would miss the path.  
"Label" seems appropriate to contain a dynamic message.

Default setup for Alarm Status Table shows Display Path and Source. I don't know what's the intention for it.  
Default setup for Alarm Journal Table shows Event ID and Source. Again, I don't know the intention for it.

> [@josborn](#):
>
> I think this explains the invalid key warning:

Out of my head, Dataset is different from Array of Objects. As an example, today I used the Pie Chart binding its "Data" Property. Even though it should accept an Array List, it was able to use a Dataset without any issues.

Anyway, providing some type of statistics is the main topic. I will give it another round of tests tomorrow.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [April 7, 2022, 5:40pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/12 "2022-04-07T17:40:41Z")

</div>

> [@tupanaster](#):
>
> How people mostly use alarms?

Well in 8.1.5 at least (I think maybe you can display custom alarm fields in the ast now), I use:  
Name: the name of the alarm, e.g. Failed to Start  
Label: the device description and equip id, e.g. Agitator [T2334\_M01]  
Display path: the area and parent device if relevant, e.g. Red TF T2334

The alarm source will always contain the path to the tag, so you don't need to worry about replacing display path.

Using this methodology, you can display alarms anywhere with all the info you need.  
For example on a device popup, just show name  
On a tank detail page, show label and name  
On the main alarm page, show all 3

Event id is useless to operators but lets you group different events attached to the same alarm event, e.g. Active, acked, cleared events for a single alarm event

What i would really like to see is all of the alarm info for an alarm event on the one row, so you know when it activated, when it was ackd, and cleared without having to go searching. At least have it an option as sometimes you actually might want to show it more as a timeline as it is now

---

<div class="post-metadata">

**Author:** ![josborn](https://avatars.discourse-cdn.com/v4/letter/j/4bbf92/32.png) [@josborn](https://forum.inductiveautomation.com/u/josborn)\
**Post date:** [April 7, 2022, 5:46pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/13 "2022-04-07T17:46:52Z")

</div>

> [@tupanaster](#):
>
> That’s weird. Try posting some screenshots. Maybe your new labels are not logged or you need to reset your trial for them to be logged.

Fully licensed, and i did try changing the labels and names and saving to see if that made a difference. My previous screen shot is the sum total of every alarm and there is not one instance of a 'label' property.

I am able to get the labels with `system.alarm.queryJournal(journalName="AlarmJournal")[0].getLabel()` which is why i suggested using that instead of querying directly.

---

<div class="post-metadata">

**Author:** ![tupanaster](https://avatars.discourse-cdn.com/v4/letter/t/5daacb/32.png) [@tupanaster](https://forum.inductiveautomation.com/u/tupanaster)\
**Post date:** [April 7, 2022, 10:43pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/14 "2022-04-07T22:43:17Z")

</div>

> [@nminchin](#):
>
> Name: the name of the alarm, e.g. Failed to Start  
> Label: the device description and equip id, e.g. Agitator [T2334\_M01]  
> Display path: the area and parent device if relevant, e.g. Red TF T2334

I will give it a try tomorrow. I think it's a good idea.

> [@nminchin](#):
>
> What i would really like to see is all of the alarm info for an alarm event on the one row, so you know when it activated, when it was ackd, and cleared without having to go searching. At least have it an option as sometimes you actually might want to show it more as a timeline as it is now

I have to think about this one. Maybe it's something I would like but I'm not aware of yet.

> [@josborn](#):
>
> My previous screen shot is the sum total of every alarm and there is not one instance of a ‘label’ property.

Are your tables the same as mine?

> [@josborn](#):
>
> I am able to get the labels with `system.alarm.queryJournal(journalName="AlarmJournal")[0].getLabel()` which is why i suggested using that instead of querying directly.

I actually got some errors out of it. Using a `for` loop I got an error message... something like "index out of range".  
So, I did some debugging with `system.perspective.print()` and I found that some results were `[]`.  
I'm not sure if a should call them Null, None, or empty list.

Edit:  
I'll run the code tomorrow and post the error.

---

<div class="post-metadata">

**Author:** ![josborn](https://avatars.discourse-cdn.com/v4/letter/j/4bbf92/32.png) [@josborn](https://forum.inductiveautomation.com/u/josborn)\
**Post date:** [April 7, 2022, 10:47pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/15 "2022-04-07T22:47:35Z")

</div>

They should be the same, default settings on for an external database alarm journal.  
And my use of `system.alarm.queryJournal` was a simple proof of concept I tested in the script console, The manual says the return results are a list of PyAlarmEvent objects for what its worth.

---

<div class="post-metadata">

**Author:** ![tupanaster](https://avatars.discourse-cdn.com/v4/letter/t/5daacb/32.png) [@tupanaster](https://forum.inductiveautomation.com/u/tupanaster)\
**Post date:** [April 12, 2022, 7:07am UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/16 "2022-04-12T07:07:23Z")

</div>

> [@nminchin](#):
>
> store the results in a library variable

Where can I look up for library variables? A way to store the results to make it available for the clients.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [April 12, 2022, 7:18am UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/17 "2022-04-12T07:18:57Z")

</div>

I call the function to populate the library variable with alarm info from an expression tag using runScript. You can only access the value of the variable within the scope from which you call it. For example, you can’t call the function in the tag scope and read the value from the client scope.  
Calling from a tag gives access to the value from the tag scope so then I can have other expression tags in various folders that filter and summarise the alarms stored in the library variable based on the tag path they’re located in. Filtering the dictionary is super quick compared with calling the queryStatus function 50 times

---

<div class="post-metadata">

**Author:** ![tupanaster](https://avatars.discourse-cdn.com/v4/letter/t/5daacb/32.png) [@tupanaster](https://forum.inductiveautomation.com/u/tupanaster)\
**Post date:** [April 17, 2022, 9:05pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/18 "2022-04-17T21:05:23Z")

</div>

> [@nminchin](#):
>
> Well in 8.1.5 at least

Where do you get that version number from?  
At this date I can see the latest release is 8.1.16  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/5/4/54d5e3eba738e0c2220b0fb0d90586b9513b420e.png)

I'm using 8.1.15  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/8/4/848ff4026857eb9a9a03e4189c73806ee0066b91.png)

> [@nminchin](#):
>
> The alarm source will always contain the path to the tag, so you don’t need to worry about replacing display path.

I've notice that the source path saved in the database has a different format than the one Ignition's use.  
From the database:  
`prov:default:/tag: path here /H:/alm:High Alarm`

I was used to the path you get when you right click on a tag:  
`[default] path here /H/Alarms/High Alarm`

I tested some functions with the path from the database:

```auto
system.tag.readBlocking(path)
system.tag.getConfiguration(path, False)
system.tag.browse(path)

```

But I get not result from them. So I was thinking that some string manipulation have to be done to get the path from the database look like the "normal" one.

> [@nminchin](#):
>
> I call the function to populate the library variable with alarm info from an expression tag using runScript. You can only access the value of the variable within the scope from which you call it. For example, you can’t call the function in the tag scope and read the value from the client scope.  
> Calling from a tag gives access to the value from the tag scope so then I can have other expression tags in various folders that filter and summarise the alarms stored in the library variable based on the tag path they’re located in. Filtering the dictionary is super quick compared with calling the queryStatus function 50 times

Breaking it down into steps:

1. Create a script in the Project Library.
2. Pick a scope and call it. For example, tag scope.
3. Other tags will filter on the tag that is calling the function.
4. Show those results in some Views and filter more if needed.

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [April 18, 2022, 8:54pm UTC](https://forum.inductiveautomation.com/t/alarm-statistics-perspective/58074/19 "2022-04-18T20:54:32Z")

</div>

> [@tupanaster](#):
>
> Where do you get that version number from?

Nick is running an old version and hasn't upgraded to the newest version.

> [@tupanaster](#):
>
> But I get not result from them. So I was thinking that some string manipulation have to be done to get the path from the database look like the “normal” one.

Most of the `system.tag.*` functions expect the path as you would get from right clicking on the designer.
