Hi there,
Thanks for getting back to me, it definitely helped!
However, I’ve implemented this logic in the way you suggested and while it seems to work, I’ve noticed that the alarms seem to trigger when the value is one
off the value I set as the limit. I think this is best explained with a Boolean example that I’ve included here:
initial_time = time.time()
seconds, nanoseconds = extract_seconds_and_nanoseconds_from_timestamp(initial_time)
timestamp = PvTimeStamp(seconds, nanoseconds, 0)
display = PvDisplay(0, 10, 'Test Display', 'Test Format', 'units')
alarm = PvAlarm()
alarm_values = PvValueAlarm(BOOLEAN)
pv_types = {
'value': BOOLEAN,
'timeStamp': timestamp,
'display': display,
'alarm': alarm,
'alarm_values': alarm_values
}
pv_values = {
'timeStamp': timestamp.toDict(),
'display': display.toDict(),
'alarm': alarm.toDict(),
'alarm_values': alarm_values.toDict()
}
pv = PvObject(pv_types, pv_values)
pv['alarm_values.highAlarmLimit'] = True # should alarm when the value is True (1)
pv['alarm_values.highAlarmSeverity'] = 2
pv['alarm_values.active'] = True
server = PvaServer()
server.addRecord('counter', pv)
c = 0
try:
while True:
time.sleep(1)
if c == 2:
c = 0
seconds, nanoseconds = extract_seconds_and_nanoseconds_from_timestamp(time.time())
if c == pv['alarm_values.highAlarmLimit']:
# setting match value to True will raise an alarm when this is false
# it sets the settings on the right value but propagates through for the wrong value
(severity, status, message) = (pv['alarm_values.highAlarmSeverity'], 1, 'HIGH ALARM')
else:
(severity, status, message) = (0, 0, 'ALL CLEAR')
print(f'changing match alarm setting for value {c} to: \n severity: {severity}, status: {status}')
epics_message = {
'value': c,
'timeStamp': {
'secondsPastEpoch': seconds,
'nanoseconds': nanoseconds
},
'alarm': {
'severity': severity,
'status': status,
'message': message
}
}
pv.set(epics_message)
server.update(pv)
c += 1
finally:
server.stop()
In this case, the settings are set correctly for the value, which I can see with the output of the print statement:
changing match alarm setting for value 0 to:
severity: 0, status: 0
changing match alarm setting for value 1 to:
severity: 2, status: 1
But when I run a pvmonitor on counter in a terminal window, the alarms come through when the value is false:
pvmonitor counter
counter 2021-06-09 23:34:46.275 false MAJOR DEVICE HIGH ALARM
counter 2021-06-09 23:34:47.276 true
counter 2021-06-09 23:34:48.277 false MAJOR DEVICE HIGH ALARM
counter 2021-06-09 23:34:49.279 true
counter 2021-06-09 23:34:50.280 false MAJOR DEVICE HIGH ALARM
Although I’ve not included an example here, I see a similar pattern with range alarms where the alarm message is still visible on the pvmonitor on value 2
when the lower warning is set to 1 and lower alarm is 0 for example.
Again, apologies if I’ve misunderstood how the library works but is this behaviour expected? Is it the case where the alarm message only propagates through
to the monitor on the next update?
Thanks again for your help,
Kathryn
From: Veseli, Sinisa <sveseli at anl.gov>
Sent: 07 June 2021 18:48
To: tech-talk at aps.anl.gov; Baker, KRL, Kathryn (STFC,RAL,ISIS) <k.baker at stfc.ac.uk>
Subject: Re: Problems configuring alarms with PvaPy
At the moment there is no automated handling of alarm values. You would have to do something like this (compared to your original code example):
bluegill2> diff s.py s.py.orig
< server.addRecord('counter', pv.copy())
> server.addRecord('counter', pv)
< (severity, status, message) = (0, 0, 'ALL CLEAR')
< if c >= pv['alarm_values.highAlarmLimit']:
< (severity, status, message) = (pv['alarm_values.highAlarmSeverity'], 1, 'HIGH ALARM')
< elif c >= pv['alarm_values.highWarningLimit']:
< (severity, status, message) = (pv['alarm_values.highWarningSeverity'], 1, 'HIGH WARNING')
< elif c <= pv['alarm_values.lowAlarmLimit']:
< (severity, status, message) = (pv['alarm_values.lowAlarmSeverity'], 1, 'LOW ALARM')
< elif c <= pv['alarm_values.lowWarningLimit']:
< (severity, status, message) = (pv['alarm_values.lowWarningSeverity'], 1, 'LOW WARNING')
bluegill2>
I will add better alarm handling in the next release.
Scientific Software Engineering & Data Management
Argonne National Laboratory
(630)252-9182
Hello Tech-Talk,
I am working with PvaPy to create and update some PVs and am trying to work out how to configure the alarms for the pv.
I have created the object using the code below, which creates the ‘counter’ pv and updates the values (which I can see with a pvmonitor or a pvinfo).
initial_time = time.time()
seconds, nanoseconds = extract_seconds_and_nanoseconds_from_timestamp(initial_time)
timestamp = PvTimeStamp(seconds, nanoseconds, 0)
# configure display values
display = PvDisplay(0, 10, 'Test Display', 'Test Format', 'units')
# set up alarm - severity (0=NO_ALARM, 1=MINOR, 2=MAJOR, 3=INVALID, 4=UNDEFINED), status, message
alarm = PvAlarm()
alarm.setSeverity(0)
alarm.setMessage('test alarm message')
alarm_values = PvValueAlarm(FLOAT)
alarm_values.setHighAlarmLimit(9)
alarm_values.setLowAlarmLimit(2)
alarm_values.setHighWarningLimit(8)
alarm_values.setLowWarningLimit(3)
alarm_values.setHighAlarmSeverity(2)
alarm_values.setLowAlarmSeverity(2)
alarm_values.setHighWarningSeverity(1)
alarm_values.setLowWarningSeverity(1)
alarm_values.setActive(True)
pv = PvObject({
'value': FLOAT,
'timeStamp': timestamp,
'display': display,
'alarm': alarm,
'alarm_values': alarm_values
}, {
'timeStamp': timestamp.toDict(),
'display': display.toDict(),
'alarm': alarm.toDict(),
'alarm_values': alarm_values.toDict()
})
server = PvaServer()
server.addRecord('counter', pv)
c = 0
startTime = time.time()
try:
while True:
time.sleep(1)
if c == 11:
c = 0
seconds, nanoseconds = extract_seconds_and_nanoseconds_from_timestamp(time.time())
epics_message = {
'value': c,
'timeStamp': {
'secondsPastEpoch': seconds,
'nanoseconds': nanoseconds
}
}
pv.set(epics_message)
c += 0.5
finally:
server.stop()
This creates a PV with the following structure:
float value 10.5
time_t timeStamp 2021-06-07 13:31:45.733
long secondsPastEpoch 1623069105
int nanoseconds 732768297
int userTag 0
display_t display
double limitLow 0
double limitHigh 10
string description "Test Display"
string format "Test Format"
string units units
alarm_t alarm
int severity 0
int status 0
string message "test alarm message"
valueAlarm_t alarm_values
boolean active true
float lowAlarmLimit 2
float lowWarningLimit 3
float highWarningLimit 8
float highAlarmLimit 9
int lowAlarmSeverity 2
int lowWarningSeverity 1
int highWarningSeverity 1
int highAlarmSeverity 2
byte hysteresis 0
As you can hopefully see from the code, I have set up the alarms with severity 0 (NO_ALARM) to begin with and set the severity of the warnings and limits to be MINOR and MAJOR (2 and 3).
However, using this set-up I would expect to see the alarm messages raised when the value of the PV approaches 0 or 10, but no alarm messages are displayed. The only time I am able to see messages is if I set the severity of the alarm
object to be something other than 0, but this then raises alarm messages for all value states which is not the desired behaviour.
Is there something that I’m missing in the configuration of the alarms? Is there something that I need to set to ‘activate’ the logic behind the alarms?
Kathryn Baker (she/her)
Software Development for Accelerator Control Systems Graduate
Science and Technology Facilities Council
k.baker at stfc.ac.uk
This email and any attachments are intended solely for the use of the named recipients. If you are not the intended recipient you must not use, disclose, copy or distribute this email or any of its attachments and should notify
the sender immediately and delete this email from your system. UK Research and Innovation (UKRI) has taken every reasonable precaution to minimise risk of this email or any attachments containing viruses or malware but the recipient should carry out its own
virus and malware checks before opening the attachments. UKRI does not accept any liability for any losses or damages which the recipient may sustain due to presence of any viruses. Opinions, conclusions or other information in this message and attachments
that are not related directly to UKRI business are solely those of the author and do not represent the views of UKRI.