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"