Clearing alarms in ServiceLink when the associated data item on the agent clears

Our systems that we're connecting to ServiceLink publish alarms to the Dashboard. Some of these alarms require human attention to clear them. Others are self clearing on the agent. I am working on a way to make these self-clearing alarms clear on the Dashboard (set state to CLOSED) when the digital data item that triggered them goes to zero.

I have two Groovy scripts so far that accomplish this. We have designated an alarm severity of 42 for those alarms we want to be self-clearing. The first one is connected via an Expression Rule to a 30 minute Rule Timer. We had it set at a 1 minute timer, but this proved too taxing on the system. 30 minutes, however, is a bit lower resolution than we were hoping for. When triggered, it searches all the alarms and all the data item values and looks for matches that meet our criteria. This is very processor intensive.

==================================================================================================

import com.axeda.drm.sdk.data.Alarm;
import com.axeda.drm.sdk.data.AlarmFinder;
import com.axeda.drm.sdk.data.CurrentDataFinder;
import com.axeda.drm.sdk.data.DataValue;
import com.axeda.drm.sdk.data.DataValueList;
import com.axeda.common.sdk.jdbc.NumericQuery;
import com.axeda.drm.sdk.data.AlarmState;

AlarmFinder alarmFinder2 = new AlarmFinder(context.context);
alarmFinder2.setDevice(context.device);
alarmFinder2.setSeverity(NumericQuery.exactly(42));
alarmFinder2.setState(AlarmState.STARTED);
List alarms = alarmFinder2.findAll();
CurrentDataFinder dataValueFinder = new CurrentDataFinder(context.context, context.device);
DataValueList dataValueList = dataValueFinder.find();

for (Alarm alarm : alarms)
{
  for (DataValue dataValue : dataValueList)
  {
    if (dataValue.getDataItem().getName() == alarm.getName() && dataValue.asInteger() == 0)
    {
      alarm.setState(AlarmState.CLOSED, "");
    }
  }
}

==================================================================================================

My second approach is tied to an Expression Rule that triggers on a Data Item change and utilizes the list of data items that triggered the rule. This rule is far less taxing on processing resources, but would be run far more often.

==================================================================================================

import com.axeda.drm.sdk.data.Alarm;
import com.axeda.drm.sdk.data.AlarmFinder;
import com.axeda.drm.sdk.device.DataItem;
import com.axeda.common.sdk.jdbc.NumericQuery;
import com.axeda.drm.sdk.data.AlarmState;

for (DataItem dataItem : dataItems)
{
   AlarmFinder alarmFinder = new AlarmFinder(context.context);
   alarmFinder.setDevice(context.device);
   alarmFinder.setAlarmName(dataItem.getDataItemName());
   alarmFinder.setSeverity(NumericQuery.exactly(42));
   alarmFinder.setDataItemValue("0");
   alarmFinder.setState(AlarmState.STARTED);
   Alarm alarm = alarmFinder.findAll();
   alarm.setState(AlarmState.CLOSED. "");
}

==================================================================================================

So, my question is this: Is there a way to further limit the processing burden and still achieve the goal? Which of these scripts/strategies would you recommend I use? Is there a better way altogether? We have varying lists of alarms and a large quantity of thems so working on a alarm by alarm basis is out of the question. It has to be generic. I can provide more information if needed.

Thanks,

David

Hi David, As I understand it,

Hi David,

As I understand it, you will have dataitems with the same name as the alarm. When these dataitems come in, any alarms with that name, severity 42 (the answer to everything), and dataItemValue of "0" should be closed.

Your second script is pretty efficient, except that it will query n times if there are n dataitems in the batch. If your agent posts data item one at a time this won't be a problem. If it sends 10-20 data items in a single message, then this code will cause 10-20 database transactions.

Another approach assumes that the number of started alarms for the device is relatively low, so instead of iterating each data item and querying for a specific alarm, let's iterate all open alarms for the device and close those that have a data item in the posted list. Something like this (not tested! just for the general idea)

 

 

AlarmFinder alarmFinder = new AlarmFinder(context.context);
alarmFinder.setDevice(context.device);
alarmFinder.setSeverity(NumericQuery.exactly(42));
alarmFinder.setDataItemValue("0");
alarmFinder.setState(AlarmState.STARTED);

alarmFinder.findAll().each {Alarm al->
  def match = dataItems.find { it.name == al.name }
  if (match != null) {
    al.setState AlarmState.CLOSED, ""
    al.store()
  }
}