Alarms in C++ programming

Introduction

Essential alarm status features

Every alarm is oriented towards the OPC UA Alarms and Conditions specification and has these properties:

  • 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 the alarm (from 1 = information to 1000 = severe error)
  • Retain – the alarm is to be shown to the user (evaluated by the client)
  • Message – the message to be shown to the user
  • optional: timestamps for a variety of substatuses can be set

    Additional from 2020.6:
  • comment – the latest comment provided by the user
  • language – identifier of the LocaleID for a comment (e.g. "en-US")
  • user – the latest user who has acknowledged, confirmed or changed the comment

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.

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. With Acknowledge and Confirm the client can pass a localized comment along with the user's name. This is also reflected in the AlarmState

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 theAlarmAccess class. It can be used for alarm sources and alarm sinks.

During initialization of PLCnext Technology, theAlarmAccess 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 theAlarmAccess 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 emptyalarmId

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 emptyalarmId
  • 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.

Show legacy confirmation, acknowledgement, and alarm stateShow legacy confirmation, acknowledgement, and alarm state  

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
};

 

 


•  Web browser recommendation: Chrome/Edge 88 or newer, Firefox ESR 90 or neweror Safari • 
• Published/reviewed: 2022-09-14 • Revision 046 •