Skip to content

Alarms: programming

This page covers working with alarms from code.

For the concepts and day-to-day use, see Alarms: overview.

For full descriptions of the programming interfaces (e.g. all the optional parameters that aren't mentioned here), see the API reference for C++ (al_xxx), Python (midas.client) and JavaScript (midas.js).

Implementation details

Alarms are evaluated every 10s when programs perform their periodic tasks. For remote clients, the checks are performed by mserver, rather than by the remote process itself. As result, all alarm checks run inside a process directly attached to the local midas shared memory. Each and every midas client runs the alarm checks. To prevent race conditions between different midas clients, access to al_check() is serialized using the ALARM semaphore.

Special note should be made of the ODB setting /Alarms/Classes/xxx/System message interval, which has a surprising effect - after an alarm is recorded into system messages (using cm_msg(MTALK)), no record is made of any subsequent alarms until the time interval set by this variable elapses. With default value of 60 seconds, after one alarm, no more alarms are recorded for 60 seconds. Also, because all the alarms are checked at the same time, only the first triggered alarm will be recorded.

Defining a new alarm

INT status = al_define_odb_alarm("alarm_name", "/Runinfo/Run number > 100", "MyAlarmClass", "my message");
client.create_evaluated_alarm("alarm_name", "/Runinfo/Run number > 100", "my message", "MyAlarmClass")

For Bash and Javascript, you can use ODB commands to copy an existing alarm and then manipulate it.

Defining a new alarm class

cmd = "/path/to/some/script.sh"
interval_secs = 60
client.create_alarm_class("MyAlarmClass", cmd, interval_secs)

For C++, Bash and Javascript, you can use ODB commands to copy an existing alarm class and then manipulate it.

Triggering an internal alarm

INT status = al_trigger_alarm("MyAlarmName", "my message", "MyAlarmClass", "", AT_INTERNAL);
client.trigger_internal_alarm("MyAlarmName", "my message", "MyAlarmClass")
mjsonrpc_al_trigger_alarm("MyAlarmName", "my message", "MyAlarmClass", "", AT_INTERNAL).then(function(rpc) {
  if (rpc.result.status == 1) {
    console.log("SUCCESS!");
  }
}).catch(function(error) {
  mjsonrpc_error_alert(error);
});

Accessing triggered alarms

Note that the C++ interface returns the name of the alarm class, while the python interface returns the name of the alarm itself.

std::string alarms;
INT status = al_get_alarms(&alarms);

// alarms is populate with one line per alarm.
// Format for evaluated alarms:
//   <alarm class>: <condition>
// Format for other alarms:
//   <alarm class>: <message>
alarms = client.get_triggered_alarms()

# alarms is a dict of {alarm_name: message}

Resetting an alarm

INT status = al_reset_alarm("MyAlarmName");
client.reset_alarm("MyAlarmName")
mjsonrpc_al_reset_alarm(["MyAlarmName1", "MyAlarmName2"]).then(function(rpc) {
  let status_alarm1 = rpc.result.status[0]; // status of al_reset_alarm() for 1st alarm
  let status_alarm2 = rpc.result.status[1];
}).catch(function(error) {
  mjsonrpc_error_alert(error);
});

Resetting all alarms

INT status = al_reset_alarm("");
client.reset_alarm("")
mjsonrpc_al_reset_alarm([""]).then(function(rpc) {
  let status = rpc.result.status[0];
}).catch(function(error) {
  mjsonrpc_error_alert(error);
});
odbedit -c "alarm"