Alarms in C++ programming
Introduction
Essential alarm status features
Every alarm is oriented towards the OPC UA Alarms & Conditions specification and has these properties:
Property | Meaning or purpose | Restrictions |
---|---|---|
AlarmId |
The unique name of the alarm on the device. | |
AlarmType |
The alarm type can be used for filtering in the client. | |
Active |
The alarm condition is active. | |
Acknowledged |
The user has seen the alarm condition. | |
Confirmed |
The user has solved the problem that caused the alarm. | |
Severity |
The severity of an alarm is set by values from 1 = information to 1000 = severe condition. |
|
Retain |
The alarm is to be shown to the user (evaluated by the client). | |
Message |
The message to be shown to the user. | |
comment |
The latest comment provided by the user. | firmware 2020.6 or newer |
language |
Identifier of the LocaleID for a comment (according to ISO 639-1 and ISO 3166-1, e.g. "en-US"). | firmware 2020.6 or newer |
user |
The latest user who has acknowledged, confirmed, or changed the comment. | firmware 2020.6 or newer |
Optionally, timestamps
for a variety of substatuses can be set.
Registration of alarms
To introduce an alarm to the system, it has to be registered before the first use. As a result, you can see in the OPC UA® Server which alarms can occur.
Note: It is not possible to remove a registered alarm. However, they are deleted during each cold and warm restart. This is why alarms have to be registered after each cold or warm restart. Registering an alarm twice does not trigger an error message.
Acknowledgement and confirmation of alarms
Some alarms must be acknowledged and sometimes even be confirmed. To do so, the Acknowledge
and Confirm
methods can be used. These are also messages in PLCnext Technology. However, they are sent from a client to the alarm source. The alarm source must process this message. Usually, this results in a new alarm status which, as usual, is sent to all clients.
From firmware 2020.6 and newer, the client can pass a localized comment and the the user's name along with the Acknowledge
and Confirm
properties. This is also reflected in the alarm state.
Additional information to send with the alarm message
Often there is the requirement to add additional information to an alarm, which is available in the client and can be displayed in the message. For this, the alarm state also holds a list of up to 10 custom parameters. These parameters must be entered during registration with their name and data type so that they are known by the client. Elementary data types including strings are supported.
There are alarm blocks that can take on a structure with additional parameters. These parameters must be entered during registration so that they are known to the client. In the message, the parameters can be referenced using placeholders. The following placeholders are supported:
Placeholder | Meaning |
{0} | Alarm name - must be unique within the controller |
{1} | Alarm type |
{2} | 1st user parameter |
{3} | 2nd user parameter |
... | |
{11} | 10th user parameter |
Using Alarms in C++ programs
For programming in C++, the PLCnext Technology SDK provides the AlarmAccess
class. It can be used for alarm sources and alarm sinks.
During initialization of PLCnext Technology, the AlarmAccess
class should be instantiated and initialized (e.g., in SetupConfig
of a PLCnext Technology component). C++ programs can use the instance to send alarms. Using one instance for all alarms makes sense as many AlarmAccess
instances would result in a correspondingly large number of messages in PLCnext Technology, which would strain the system.
The classes can be included using the following headers:
#include "Arp/System/NmPayload/Alarms/AlarmAccess.hpp"
#include "Arp/System/NmPayload/Alarms/AlarmState.hpp"
#include "Arp/System/NmPayload/Alarms/AlarmUserParameter.hpp"
The alarm classes are contained in theArp::System::NmPayLoad::Alarms
namespace. To use a class, you must create an instance and call theInit
method:
using namespace Arp::System::NmPayload::Alarms;
AlarmAccess alarmAccess;
alarmAccess.Init("xxxxxx.CppClient");
Note: The name for the AlarmAccess
instance has to be unique on the PLC.
Methods for sending messages
Announcing a new alarm to the server
int32 AddAlarm(AlarmState& alarmState);
Announcing a new alarm is useful, for example, for browsing in OPC UA.
These fields are used:
alarmId
is a unique name of the alarm instance on the server.alarmType
is a name of the subtype ofDiscreteAlarmType
that is generated as a result of this method call.severity
is a number between 1 and 1000 where 1 is informative and 1000 is a fatal error.
The user parameters with name and type are mapped to variables of the newAlarmType
.
The return values are:
- 0 if successful
- -1 if not initialized
- -2 if empty
string
parameters
Informing the AlarmServer
about a new alarm state
int32 NewAlarmState(AlarmState& alarmState);
This includes coming alarms, going alarms or changes to sub states.
An alarm source can inform the AlarmServer
about state changes of its alarms. Only the source should call this methods for its alarms.
The return values are:
- 0 if successful
- -1 if not initialized
- -2 if empty
alarmId
Asking for acknowledgement of an alarm instance
From firmware 2020.6 - for legacy firmware releases see the note below
int32 AcknowledgeWithComment(const String& alarmId, const String& comment, const String& language, const String& user);
A client can ask for acknowledgement of an alarm instance (if supported by an alarm).
comment
can be a string with a maximum length of 80 bytes of an UTF-8 coded string.
language
shall be the LocaleId
for the comment (e.g. "en-US").
user
shall be the name of the user who asks for acknowledgement.
The return values are:
- 0 if successful
- -1 if not initialized
- -2 if empty
alarmId
Asking for confirmation of an alarm instance
From firmware 2020.6 - for legacy firmware releases see the note below
int32 ConfirmWithComment(const String& alarmId, const String& comment, const String& language, const String& user);
A client can ask for confirmation of an alarm instance (if supported by an alarm).
comment
can be a string with a maximum length of 80 bytes of an UTF-8 coded string.
language
shall be the LocaleId
for the comment (e.g. "en-US").
user
shall be the name of the user who asks for confirmation.
The return values are:
- 0 if successful
- -1 if not initialized
- -2 if empty
alarmId
Adding a comment to an alarm instance
From firmware 2020.6
int32 AddComment(const String& alarmId, const String& comment, const String& language, const String& user);
A client can add a comment to an alarm instance (if supported by an alarm).
comment
can be a string with a maximum length of 80 bytes of an UTF-8 coded string.
language
shall be the LocaleId
for the comment (e.g. "en-US").
user
shall be the name of the user who asks for confirmation.
The return values are:
- 0 if successful
- -1 if not initialized
- -2 if empty
alarmId
- 100 if notification queue is full
Methods for receiving messages
Subscribing to Acknowledge
request
int32 SubscribeAcknowledge(std::function<void(const String& alarmId, const String& comment, const String& language, const String& user)> handler);
An alarm source that supports acknowledgable alarms should subscribe to acknowledge request by a client.
As a result to a call of the handler function, the alarm source might change the state of the alarm and call NewAlarmState
again.
Note: The provided handler function is called by a different thread!
The return values are:
- 0 if successful
- -1 if not initialized
- -2 if no handler function
Subscribing to Confirm
request
int32 SubscribeConfirm(std::function<void(const String& alarmId, const String& comment, const String& language, const String& user)> handler);
An alarm source that supports confirmable alarms should subscribe to confirm request by a client.
As a result to a call of the handler function the alarm source might change the state of the alarm and call NewAlarmState
again.
Note: The provided handler function is called by a different thread!
The return values are:
- 0 if successful
- -1 if not initialized
- -2 if no handler function
Subscribing to AddAlarm
calls
int32 SubscribeAddAlarm(std::function<void(const AlarmState& alarmState)> handler);
A client can subscribe to AddAlarm calls. This feature is used e.g. by the OPC UA Server to show the alarms in the address space.
Note: The provided handler function is called by a different thread!
The return values are:
- 0 if successful
- -1 if not initialized
- -2 if no handler function
Subscribing to NewAlarmState
calls
int32 SubscribeNewAlarmState(std::function<void(const AlarmState& alarmState)> handler);
A client can subscribe to NewAlarmState
calls to track the state of alarms.
Note: The provided handler function is called by a different thread!
The return values are:
- 0 if successful
- -1 if not initialized
- -2 if no handler function
Alarm status
The alarm status is held in the AlarmState
structure. The following commented code blocks show the state with substates of an alarm from firmware 2020.6:
class AlarmState
{
public:
String AlarmId; // unique Id of the alarm instance within the PLC
String AlarmType; // type of the alarm, use as key to lookup
// a localized text for the alarm message
String Message; // optional message, if Message is empty the AlarmType
// is the key retrieval of a translated message
bool ActiveState; // indication if the alarm condition is true
DateTime ActiveStateChanged; // timestamp for the last change of ActiveState
bool AckedState; // acknowledged state of the alarm (the user has seen the alarm)
DateTime AckedStateChanged; // timestamp for the last change of AckedStateChanged
bool ConfirmedState; // confirmed state of the alarm (the user has resolved the problem)
DateTime ConfirmedStateChanged; // timestamp for the last change of ConfirmedStateChanged
String Comment; // user comment to the alarm from the Acknowledge, Confirm or AddComment method
String Language; // language of the user comment
String User; // user who most recently changed the comment
bool SuppressedState; // the server wants to hide the alarm
DateTime SuppressedStateChanged; // timestamp for the last change of SuppressedState
int16 Severity; // severity between 1 and 1000 (1 = information; 1000 = fatal error)
bool Retain; // true to indicate that the alarm should be displayed to the client
DateTime RetainChanged; // timestamp for the last change of RetainChanged
DateTime AlarmChanged; // timestamp for the last change of AlarmChanged
std::vector<AlarmUserParameter> UserParameters; // User parameters
};
Note: Alarms for firmware 2019.0 LTS to 2020.3 have been a little bit different.
Methods for sending messages
These two methods were different with firmware 2019.0 LTS to 2020.3:
Asking for acknowledgement of an alarm instance
int32 Acknowledge(const String& alarmId);
A client can ask for acknowledgement of an alarm instance (if supported by an alarm).
The return values are:
- 0 if successful
- -1 if not initialized
- -2 if empty
alarmId
Asking for confirmation of an alarm instance
int32 Confirm(const String& alarmId);
A client can ask for confirmation of an alarm instance (if supported by an alarm).
The return values are:
- 0 if successful
- -1 if not initialized
- -2 if empty
alarmId
Alarm Status
The following commented code blocks show the state with substates of an alarm from firmware 2019.0 LTS to 2020.3:
class AlarmState
{
public:
String AlarmId; // unique Id of the alarm instance within the PLC
String AlarmType; // type of the alarm, use as key to lookup
// a localized text for the alarm message
String Message; // optional message, if Message is empty the AlarmType
// is the key retrieval of a translated message
bool ActiveState; // indication if the alarm condition is true
DateTime ActiveStateChanged; // timestamp for the last change of ActiveState
bool AckedState; // acknowledged state of the alarm (the user has seen the alarm)
DateTime AckedStateChanged; // timestamp for the last change of AckedStateChanged
bool ConfirmedState; // confirmed state of the alarm (the user has resolved the problem)
DateTime ConfirmedStateChanged; // timestamp for the last change of ConfirmedStateChanged
bool SuppressedState; // the server wants to hide the alarm
DateTime SuppressedStateChanged; // timestamp for the last change of SuppressedState
int16 Severity; // severity between 1 and 1000 (1 = information; 1000 = fatal error)
bool Retain; // true to indicate that the alarm should be displayed to the client
DateTime RetainChanged; // timestamp for the last change of RetainChanged
DateTime AlarmChanged; // timestamp for the last change of AlarmChanged
std::vector<AlarmUserParameter> UserParameters; // User parameters
};