AlarmManager: add and remove Listener for all alarms of all tags below a folder

I try to ack an alarm with:
com.inductiveautomation.ignition.gateway.alarming.AlarmManager

Interface AlarmManager

acknowledge​(java.util.Collection<java.util.UUID> eventIds, EventData ackData)

I dont know what to provide for ackData ?

EventData eventData = new EventData();
boolean cr = this.context.getAlarmManager().acknowledge(uuids, eventData);

return error:

An alarm could not be acknowledged. It may no longer be registered. Event details: 5db44117-3b8d-4596-b5d8-02b7df3ea518 / {{eventTime=Thu Jun 03 18:06:30 CEST 2021}}

Construct a new EventData and add CommonAlarmProperties if you know them, such as AckUser or AckNotes; such as:

        EventData ackData = new EventData(timestamp);
        ackData.set(CommonAlarmProperties.AckUser, userPath);
        if (StringUtils.isNotBlank(notes)) {
            ackData.set(CommonAlarmProperties.AckNotes, notes);
        }
1 Like

I don’t understand why the alarm is not ack. UUID is Ok.

Is there any access right restriction ?
this code is executed on the gateway in a module in a routeHandler ?


EventData ackData = new EventData(System.currentTimeMillis());
ackData.set(CommonAlarmProperties.AckNotes, "TEST ACK");
boolean cr = this.context.getAlarmManager().acknowledge(uuids, ackData);

Are you acknowledging in a remote alarm provider? Do you have the right service security in place to allow remote acknowledgement?

No it’s a on a local gateway with a local alarm provider.

code is executed in a routeHandler:

	@Override
	public void mountRouteHandlers(RouteGroup routes){

		logger.info("mountRouteHandlers() - add route to /data/{}/ackalarm/(alarm hash code)",MOUNT_PATH_ALIAS);
		routes.newRoute("/ackalarm/:ackcode")
				.handler((req, res) -> ackAlarm(req, res, req.getParameter("ackcode")))
				.type(RouteGroup.TYPE_TEXT_HTML)
				.restrict(WicketAccessControl.STATUS_SECTION)
				.mount();
	}

ackAlarm

it works with “Live Event Limit = 1” instead of 5.
I had forgot to change the setting on my test env.

Ignition 8.1.6
I have the error message too in the alarm status component.
I need to restart Ignition to solve this issue.

What means this error message: An alarm could not be acknowledged. It may no longer be registered ?

An alarm could not be acknowledged. It may no longer be registered. Event details: ac05fc40-daae-44b7-a807-0eacf27c6938 / {{ackUser=usr-prov:default:/usr:admin, eventTime=Fri Jun 04 12:02:35 CEST 2021}}

@PGriffith,
I suspect there is something wrong about removeListener in the alarmManager or my use of it.
The issue occur when I restart my Module which is listening for alarms becoming active.

In my module at module shutdown

gatewayContext.getAlarmManager().removeListener(qp, myAlarmListenerBlock);

In my module at module startup

gatewayContext.getAlarmManager().addListener(qp, myAlarmListenerBlock);

removeListener is well executed, with no error, and I think that it remove too the listener of the Designer or Vision Client !

I become to this conclusion because, each time, after reloading my module, and can’t ack anymore alarms in the designer or vision !
even if after a restart of them ! The only solution is to restart the whole gateway.

The way acknowledgement works is that you pass in your event ID(s), then the AlarmManager loops through your IDs and tries to acknowledge them in each subprovider, if possible. If it gets to the end of that loop and there's still event IDs left, it throws that error message back.

I don't know if you'll be able to cast to these classes from your module, but try this:

var alarmStateModel = ((AlarmManagerImpl) gatewayContext.getAlarmManager()).getLocalProvider();
var listeners = ((AlarmStateModel) alarmStateModel).getAllListenersFor(qp);

I can't import AlarmManagerImpl or AlarmStateModel in my module
I can't find them in the Javadoc SDK ?

do I need other dependency ???

 <dependency>
            <groupId>com.inductiveautomation.ignitionsdk</groupId>
            <artifactId>alarm-notification-common</artifactId>
            <version>${ignition-sdk-version}</version>
            <type>pom</type>
            <scope>provided</scope>
</dependency>

<dependency>
            <groupId>com.inductiveautomation.ignitionsdk</groupId>
            <artifactId>ignition-common</artifactId>
            <version>${ignition-sdk-version}</version>
            <type>pom</type>
            <scope>provided</scope>
</dependency>

<dependency>
            <groupId>com.inductiveautomation.ignitionsdk</groupId>
            <artifactId>gateway-api</artifactId>
            <version>${ignition-sdk-version}</version>
            <type>pom</type>
            <scope>provided</scope>
</dependency>

Those classes aren’t part of the SDK.

Yeah, I had a hunch that wouldn’t work. You could use reflection to retrieve those named methods and try the same thing, but :man_shrugging:

It’s probably not your hunch about the listeners, but you could start commenting out/disabling chunks of your module to isolate what is causing the issue?

All is working well…
But I have the error when I ack alarm in my module or in the designer or in vision, ONLY just after I have reloaded my module so when onShutdown / onStartup had been executed.
The issue persist until I restart the gateway and I reproduce it when I restart my module.

In my module at module shutdown

gatewayContext.getAlarmManager().removeListener(qp, myAlarmListenerBlock);

In my module at module startup

gatewayContext.getAlarmManager().addListener(qp, myAlarmListenerBlock);

I think that the cause of the error is that the removeListener delete my module listener and delete too the listener of vision and the designer as a side effect !

I have no way to check that ?
How the removeListener method make difference beetween listeners added ?
QualifiedPath + listener object ?

MyAlarmListenerBlock implements AlarmListener

public class MyAlarmListenerBlock implements AlarmListener {

	public MyAlarmListenerBlock(){
	...}

	private void processAlarm(AlarmEvent alarmEvent){
	...}

    @Override
    public void onActive(AlarmEvent alarmEvent) {
        if (this.onActive) {
            processAlarm(alarmEvent);
        }
    }

    @Override
    public void onClear(AlarmEvent alarmEvent) {
        if (this.onClear) {
            processAlarm(alarmEvent);
        }
    }

    @Override
    public void onAcknowledge(AlarmEvent alarmEvent) {
        if (this.onAcknowledge) {
            processAlarm(alarmEvent);
        }
    }
}

Hi @PGriffith,
I think I’ve found the source of my issue.

Tags in [default]:

image

TEST1 with alarm : Alarme1
TEST1 with alarm : Alarme2

I added the listener using the following path:
(Gateway is restarted before running each test)

  • Case 1:
QualifiedPath qualifiedPath = QualifiedPath.parseSafe("prov:default:/tag:TEST_NOTIF");
gatewayContext.getAlarmManager().addListener(qualifiedPath , myAlarmListenerBlock)

The events for both alarms are provided to my listener.

But after a gateway module shutdown with the following code, all alarms acknowledge failed.

gatewayContext.getAlarmManager().removeListener(qualifiedPath , myAlarmListenerBlock)
  • Case 2:
QualifiedPath qualifiedPath = QualifiedPath.parseSafe("prov:default:/tag:TEST_NOTIF/TEST1:/alm:Alarme1");
gatewayContext.getAlarmManager().addListener(qualifiedPath , myAlarmListenerBlock)

The events for Alarme1 are provided to my listener.

After a gateway module shutdown with the following code, all alarms can be acknowledge without error.

gatewayContext.getAlarmManager().removeListener(qualifiedPath , myAlarmListenerBlock)
  • Case 3:
QualifiedPath qualifiedPath = new QualifiedPath.Builder().build();
gatewayContext.getAlarmManager().addListener(qualifiedPath , myAlarmListenerBlock)

The events for both alarms are provided to my listener.

After a gateway module shutdown with the following code, all alarms can be acknowledge without error.

gatewayContext.getAlarmManager().removeListener(qualifiedPath , myAlarmListenerBlock)

I conclude that I must doing something wrong or unsupported in case 1.
So, what is the way to listen for all tag’s alarms below a folder ?
Is there any wildcard (*) or some parts are mandatory in alarms Qualified Path ?

@PGriffith, do you know how to construct an AlarmListener for all alarms in a folder ???

SDK javadoc:

void addListener​(alarmPath,AlarmListener listener)

Registers a listener for events generated at the specified path location or below.

http://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.0/com/inductiveautomation/ignition/gateway/alarming/AlarmManager.html#addListener(com.inductiveautomation.ignition.common.QualifiedPath,com.inductiveautomation.ignition.common.alarming.AlarmListener

if I use:

QualifiedPath qualifiedPath = QualifiedPath.parseSafe("prov:default:/tag:path/to/myFolder");
gatewayContext.getAlarmManager().addListener(qualifiedPath , myAlarmListenerBlock)

It seems to work, but broke ignition ackwonledge process immediatly after I use removeListener !
(message alarm ackwonledgement failed in vision or perspective alarm status and a gateway error: an alarm could not be acknowldge. It may no longer be registered)

A very simple test project to reproduce the “issue”.
tags.json (1.1 KB) test_20210617170713.zip (51.6 KB)

Perhaps it is related to the fact that there is no :/alm: in the path provided to addListener ?

Yeah, it seems like there might be a “bug” of sorts where equality on the listener is being compared poorly on remove, or something. I’m not well versed enough in this area to speculate much, but I’ll file a ticket.

1 Like