- Introduction
- Guide details
- When to use Notifications
- Limitations
- Quick-start example
- PART 1 - Receiving notifications
- PART 2 - Creating custom notifications
- PART 3 - Sending notifications
- PART 4 - Debugging notifications
- PART 5 - Logging notifications
- PART 6 - Viewing notification history
- IMPORTANT NOTE on notification logging
- Further information
The Notification manager allows the sending and receiving of notifications between components on a controller.
Notifications are messages referring to special events. They are identified by name and can transport a payload of user data.
Both the PLCnext Technology firmware and user-defined components can send notifications.
Description | Value |
---|---|
Created | 20.09.2019 |
Last modified | 15.02.2021 |
Controller | AXC F 2152 |
FW | 2021.0.0 LTS |
Arpversion | 21.0.0.35466 |
SVN Revision | 35466 |
SDK | 2021.0.0 LTS (21.0.0.35466) |
PLCnext CLI | 21.0.0 LTS (21.0.0.489) |
Notifications are useful when event data must be transferred between two otherwise independent components on a PLCnext Control device.
The following are some examples of how the Notification manager can be used by a user component:
-
Receive a notification when network settings change (e.g. Default Gateway).
-
Receive notification of network interface up/down events (e.g. link up/link down, connection established/interrupted).
-
Receive notification of changes to the PLC runtime state (e.g. Running, Stopped).
-
Send custom notifications when errors or exceptions are detected.
Notifications are not designed to send process data, and they do not operate in a real-time context.
At present, the Notification Manager can only be accessed by C++ components and programs on a PLCnext Control. It is not possible for the Notification Manager to be accessed directly from IEC 61131 POUs in PLCnext Engineer.
This example demonstrates features of the Notification Manager.
It is assumed that the user has some experience building C++ Components and Programs for PLCnext Control.
Prerequisites:
-
PLCnext Command Line Interface (CLI) tool, version 2021.0. This is included in the "PLCnext Technology C++ tool chain", available on the Phoenix Contact website.
-
Software Development Kit (SDK) for the AXC F 2152 PLCnext Control, version 2021.0.0. This is also included in the "PLCnext Technology C++ tool chain".
-
PLCnext Engineer version 2021.0.1.
Procedure:
-
Clone this repository, e.g.
git clone https://github.com/PLCnext/CppExamples.git
-
Change directory into the Notification Example project
cd CppExamples/Examples/NotificationExample
-
Build the project and package it as a PLCnext Engineer library
plcncli generate all plcncli build plcncli deploy
-
Copy the file
NotificationExample.pcwlx
from thebin
directory to the User Library directory of PLCnext Engineer (default: C:\Users\Public\Documents\PLCnext Engineer\Libraries) -
In PLCnext Engineer, add the library as a User Library.
-
Create an instance of the two programs:
- PG_SendNotification
- PG_ReactToNotification
-
Download and run the project.
-
Add the following program variables to the Watch window:
- IP_uiInfoValue
- IP_uiWarningValue
- OP_uiInfoValue
- OP_uiWarningValue
-
Change the values of the two input port variables. The values will appear in the corresponding Output port variables.
The data transfer observed above is done via Notifications.
-
Establish a Secure Shell (ssh) session on the PLC, and monitor the Output.log file:
cat /opt/plcnext/logs/Output.log | grep NotificationExample.COMP_Notifications
-
Note the following log messages:
- A list of all the notification names (and their IDs) that have been registered with the Notification manager.
- PLC State change notification messages.
- Custom notification log messages for every change in the value of the Input port variables in PLCnext Engineer.
All these messages in the Output.log file are generated by the custom PLCnext C++ Component, based on notifications received from the Notification Manager.
In the following sections, we will examine the C++ source code to see how this example uses the Notification Manager.
As a rule, notification subscriptions should only be made by PLCnext Components (not Programs).
In order to use the Notification Manager, the NotificationManager.hpp header file must be included in your project.
In the project Component source file COMP_Notifications.hpp:
#include "Arp/System/Nm/NotificationManager.hpp"
In order to receive notifications, a header file must be included for each notification type, which defines the format of the notification payload.
#include "Arp/System/NmPayload/Plc/PlcStateChangedPayload.hpp"
#include "Arp/System/NmPayload/Device/NetworkConfigurationChangedPayload.hpp"
#include "ExamplePayload.hpp"
The above code snippet includes header files that describe the payloads for two PLCnext Runtime system notifications ("PlcStateChanged" and "NetworkConfigurationChanged") and one custom notification ("Example").
A list of all available PLCnext Runtime system notifications is available in the PLCnext Technology Info Center.
To subscribe to a custom notification, the developer of the component that generates the notification must provide the header file that defines the notification payload.
Next, a reference to the global Notification Manager service is obtained:
Arp::System::Nm::NotificationManager& nm = NotificationManager::GetInstance();
One Notification Subscriber object is created for each notification:
Arp::System::Nm::NotificationSubscriber Custom_subscription;
Arp::System::Nm::NotificationSubscriber Custom_subscription2;
Arp::System::Nm::NotificationSubscriber NetworkConfigurationChanged_subscription;
Arp::System::Nm::NotificationSubscriber PlcStateChanged_subscription;
... and in the Component constructor, each Subscriber is associated with with a notification name:
COMP_Notifications::COMP_Notifications(IApplication& application, const String& name)
: ComponentBase(application, ::NotificationExample::NotificationExampleLibrary::GetInstance(), name, ComponentCategory::Custom)
, programProvider(*this)
, ProgramComponentBase(::NotificationExample::NotificationExampleLibrary::GetInstance().GetNamespace(), programProvider)
, Custom_subscription("My.NameSpace.1")
, Custom_subscription2("My.NameSpace.2")
, NetworkConfigurationChanged_subscription("Arp.Device.Interface.NetworkConfigurationChanged")
, PlcStateChanged_subscription("Arp.Plc.Domain.PlcManager.StateChanged")
{
}
The notification names used in this constructor are registered by senders of notifications, and must be unique on the notification manager. The name of custom notifications ("My.NameSpace.1" and "My.NameSpace.2" in this example) must be provided by the developer of the component that generates these notifications.
After notification subscriber objects have been created and associated with specific notifications names, a callback function (or "delegate") is registered for each Notification Subscriber. This callback function will be invoked every time a new notification is received by that subscriber.
In the COMP_Notifications.cpp file:
void COMP_Notifications::Initialize()
{
// ...
// subscribe events from the event system (Nm) here
this->Custom_subscription.OnNotification += make_delegate(this, &COMP_Notifications::NM_Subscription1_Callback);
this->Custom_subscription2.OnNotification += make_delegate(this, &COMP_Notifications::NM_Subscription2_Callback);
this->NetworkConfigurationChanged_subscription.OnNotification += make_delegate(this, &COMP_Notifications::NetworkConfigurationChanged_Callback);
this->PlcStateChanged_subscription.OnNotification += make_delegate(this, &COMP_Notifications::PlcStateChanged_Callback);
}
... and in each corresponding callback function, the payload is handled. For example, the NetworkConfigurationChanged handler in this example writes payload information to the log file:
// Receive Network Configuration Changes.
void COMP_Notifications::NetworkConfigurationChanged_Callback(const Arp::System::Nm::Notification& notification)
{
auto payload = notification.GetPayloadAs<Arp::System::NmPayload::Device::NetworkConfigurationChangedPayload>();
//Configuration of network interface {number} changed: {Parameter} = {Value}
auto parameter = payload.GetChangedParameter();
auto deviceId = payload.GetDeviceId();
auto id = payload.GetId();
auto name = payload.GetName();
auto value = payload.GetValued(); // No, this is not a typo :(
log.Info("Parameter:{0},devieId:{1},id:{2},name:{3},value:{4}",parameter,deviceId,id,name,value);
}
The payload structure for System notifications are defined in the corresponding header files, which can be found in the SDK.
The structure of custom payloads can be seen in the header file provided by the notification developer.
Notifications include payloads, and the structure of the payload associated with a custom notification must be defined. A payload is defined as a class that inherits the SpecializedPayload
template. A payload class includes custom methods which allow the notification receiver to extract information from the payload. In this example, the payload for the custom notification is defined in the source file ExamplePayload.hpp.
Before custom notifications can be sent via the notification manager, details of the custom notification type - including the name and severity of the custom notifications - must first be registered with the notification manager.
In the project Program source file PG_SendNotification.hpp:
#include "Arp/System/Nm/NotificationManager.hpp"
#include "ExamplePayload.hpp"
Next, a reference to the global Notification Manager service is obtained:
Arp::System::Nm::NotificationManager& nm = NotificationManager::GetInstance();
One Notification Registration object is created for each notification type:
NonBlockingNotificationRegistration<ExamplePayload> MySenderRegistration1; // non-blocking needed because of real-time code execution
NonBlockingNotificationRegistration<ExamplePayload> MySenderRegistration2;
Because this example sends notifications from a real-time Program running on the ESM, Registration objects are of type NonBlockingNotificationRegistration
. If notifications will be sent from (non-real-time) Components, then Registration objects can simply be of type NotificationRegistration
.
In the Program constructor, each Registration object specifies a notification namespace and severity:
///////////////////////////////////////////////////////////////////////////////
// inline methods of class ProgramBase
inline PG_SendNotification::PG_SendNotification(NotificationExample::COMP_Notifications& cOMP_NotificationsArg, const String& name)
: ProgramBase(name)
, cOMP_Notifications(cOMP_NotificationsArg)
, MySenderRegistration1("My.NameSpace.1", name, Severity::Info, nm) // Registrations for the two notifications to be sent
, MySenderRegistration2("My.NameSpace.2", name, Severity::Warning, nm)
{
}
The notification namespaces used in this constructor ("My.NameSpace.1" and "My.NameSpace.2" in this example) must be unique on the notification manager.
It is now possible to send custom notifications using the Notification Registration objects.
Sending a custom notification is as simple as calling the SendNotification
(or the SendNotificationWithTimestamp
) method on the notification registration object.
In the PG_SendNotification.cpp file:
// Date time stamp in each cycle
TimeStamp = now();
// Compare port value of "IP_uiInfoValue" with previous value to detect a change
if(IP_uiInfoValue != uiPrevInfoValue)
{
MySenderRegistration1.SendNotificationWithTimestamp(TimeStamp, ExamplePayload{IP_uiInfoValue,"This is a placeholder message" });
uiPrevInfoValue = IP_uiInfoValue;
}
In the above code snippet, one notification is sent whenever the value of the variable IP_uiInfoValue
changes. In this case, a custom payload object of type ExamplePayload
is created for every new notification. Because the Registration object is of type NonBlockingNotificationRegistration
, these notifications can be safely sent from a real-time program.
Custom notifications generated by your application may be useful to components created by other developers. To receive notifications, an application must have access to the following information:
- The header file that defines the payload for the notification.
- The namespace on the notification manager, where notifications can be received.
- Documentation describing the contents of the payload (if not clear from the header file).
If your application generates notifications that may be useful to others, then this information should be published with your application.
When a notification is sent to the notification manager, it is immediately distributed to all the receivers that have subscribed to that notification (if any). During development, you probably want to check that your custom notifications are being generated correctly, however this requires a receiver to subscribe to those custom notifications. To save you the effort of creating a dummy notification receiver, the PLCnext Runtime includes a Notification Debugger for precisely this purpose. When enabled, the notification debugger simply logs all received notifications to the standard Output.log file on the PLC.
To enable the Notification Debugger:
-
Create a configuration file that defines
- what notifications should be received
- the logging level in the Output.log file.
-
Create a settings file that contains a reference to the configuration file.
-
Create an
.acf.config
file that instantiates the Notification Debugger ACF component, using the settings file created in the previous step. -
Restart the PLCnext Runtime.
Now, messages similar to the following will appear in the Output.log file for every new notification:
05.08.20 12:28:25.243 Arp.Services.NmUtilities.NotificationDebugger.Internal.NotificationDebugger INFO - Got notification: id=15, notificationName='My.NameSpace.1'(110), sender='COMP_Notifications1/PG_SendNotification1', timestamp=2020-08-05T12:28:25.240733, severity=Info, payloadType=NotificationExample::ExamplePayload, payload: The value is: 42
Examples of the configuration and settings files required for the notification debugger are provided here:
- Notification debugger configuration file: MyNmDebug.config
- Component settings file: MyNmDebug.settings
- ACF configuration file: My_Nm.acf.config
In this case all three files will be located in the PLC directory /opt/plcnext/projects/Default
.
It is also possible to send notifications to a persistent data store, if required, using the Notification Logger. The Notification Logger can be configured to subscribe to custom notifications and store these notifications in non-volatile memory.
The notification logger can be configured using configuration files (in XML format), located in a specific directory on the PLCnext Control. The required format and location of the configuration file is described in the PLCnext Technology User Manual.
By default, the PLCnext Runtime configures the notification logger to store notifications from the Arp
and Security
namespaces. The default configuration files can be seen on the PLC, in the /opt/plcnext/projects/Default/Services/NotificationLogger
directory.
To apply a custom configuration file to the notification logger, additional configuration file(s) can be added to the /opt/plcnext/projects/Default/Services/NotificationLogger
directory on the PLC, and the PLC restarted. There can be any number of configuration files in this directory, but only file names ending in .config
will be recognised by the notification logger.
An example of a custom notification logger configuration file is My_Nm_Logger.config, which will log the custom notifications generated by this project.
Notifications that are sent to a persistent data store using the Notification Logger can be viewed:
- In PLCnext Engineer, in the "Notifications" section of the controller "Cockpit" window. Note that PLCnext Engineer must be connected to the PLC for notifications to be displayed.
- On the PLCs Web Based Management page, in the "Notifications" section of the "Diagnostics" window.
Notification archives can be managed in C++ using the Notification Logger RSC service.
The notification logger stores notification messages in an sqlite database, in the location specified in the .config
file. In this example, the sqlite database is located at /opt/plcnext/logs/My_Nm_Logger.sqlite
. This database can be copied from the PLC if necessary, and accessed in the same way as any other sqlite database (e.g. using DB Browser for SQLite).
Note that custom notifications are not logged by default. The Notification Logger must be configured to store custom notifications in a persistent data store, otherwise custom notifications will not be retained.
If you are thinking of using the notification logger to record changes in process data - please don't!
The notification manager (and the notification logger) are intended for information and error notifications, not for the transfer of real-time process data.
If the logging of process data is required, then the solution is to use the Data Logger service, which is designed specifically for this purpose.
- PLCnext Technology Info Center - "Notifications"