Examples of alert handling
In the following examples the continuous alert handling will be compared with the discrete alert handling. For every example configuration the curve of the original value will be shown in a trend diagram.
Example of an continuous alert handling
In this example an alert will be triggered, when the filling level of a tank is too low. It is specified that there is no upper limit, because the tank is filled wit a defined refill capacity as soon as a specific bottom range will be reached. The maximum filling level of the tank is 100 litre and the minimum is 0 litre.
In the following figure a continuous alert handling with 4 ranges has been configured.
The limiting values have been set as follows:
-
range 4: good range - 40-100 litre
-
range 3: information range - 39-21 litre
-
range 2: warning range - 20-11 litre
-
range 1: alerts range - 10-0 litre
The hysteresis of [-2,2] between the ranges 4 and 3 effects that the information alert will be returned only then, if the filling level goes below 38 litre. Just as well the information alert goes only then, if the filling level of 43 litre will be exceeded. The hysteresis shall avoid that the fluctuation in the 40 litre area always triggers a information alert.
In the following diagram the filling level of the tank reaches the following states:
-
Filling level sinks: 100..75..55..45..40..37..20..10
-
The tank will be filled automatically -> during the fill a defect occurs. The filling level fluctuates, because the draining process did not stop and the tank is tried to be filled: 11..21..35..45..43..41..37..55..37..20
-
Defect eliminated -> filling level raises till 100 litre again: 21..30..50..70..90..100
Diagram: Curve in the trend
Abbreviations:
IC - information came
WC - warning came
WW - warning went
AC - alerts came
AW - alerts went
Example of a discrete alerts handling
This example describes the water temperature in a tank. The water is heated continuously, but must not exceed the temperature of 100°C. The current temperature of the water is detected and returned every 5 seconds.
The following figure shows an example configuration for this description above.
The limiting values have been set as follows:
-
range 1: good range - 20, 40, 60°C
-
range 2: information range - <0, 0-19, 21-39, 41-59, 61-69, >100°C
-
range 3: warning range - 70-89°C
-
range 4: alerts range - 90-100°C
The following water temperatures (states) are reached:
-
Water is heated to a temperature of 60°C (optimal temperature): 5, 9, 20, 29, 40, 53, 60°C.
-
The automatized measurement equipment has a defect -> the heating process continuous: 65, 75, 85, 92°C
-
Coolant is added, what has the effect that the temperature rapidly sinks: 90, 75, 60, 50, 40, 25°C
-
Tank with the coolant is empty -> the temperature is raising again: 35, 40, 55, 65, 80°C
-
The defect on the equipment could be eliminated -> temperature goes back to 60°C (optimal temperature)
Diagram: Curve in the trend
Abbreviations:
IC - information came
IW - information gone (no went text defined, so it is not visible in the event screen)
WC - warning came
WW - warning went
AC - alerts came
AW - alerts went
The range values are always scanned from the highest to the lowest range for a match. That means that in this example the alarm range is checked firstly. If the value is not in the range/range value, so the warning range will be checked, etc. In this example is the information range the most interesting one. This alert shall be returned every time (see configuration) when the value is unequal 20, 40 or 60. This means that in continuous value changes an information will be always returned, after one of these three ranges is exceeded. This can be useful for a better controlling of processes.
If the value matches the alert range, the lower ranges will not the checked anymore.
Example of how to set an alert handling for multiinstance alerts by using CTRL function calls
Multiinstance alerts are set with alertSet() and queried by using an SQL query (e.g. dpQuery()). In contrast to the other alert handling types, not the actual values (_alert_hdl.._act*) are relevant but the attribute "_alert_hdl.<i>._event"_alert_handling. This triggers an event action to trigger, update or acknowledge an alert. In addition, the periphery sets a unique ID is set for each multiinstance alert (_alert_hdl.._alert_id). Having the ID and the alert time, every multiinstance alert can be identified uniquely (separately for CAME and WENT alerts for each alert couple).
In the following example a message is sent to the Event-Manager using alertSet(). This sets the corresponding attributes the already existing data point "MI_Demo" with configured multiinstance alert handling. Next, an SQL query dpQuery() is called to search for matches in the set attributes of the data point. The matches give then the information about the count when they are called as parameters in getACount().If the count is known the function alertGet() can be used, for example, to synchronize multiinstance alerts on redundant systems.
main()
{
//Set additional values
dyn_anytype addVal = makeDynAnytype(1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32);
time t;
dyn_dyn_anytype attr;
//The current time is stored in a local variable
t = getCurrentTime();
//set an alert on the data point 'MI_Demo.',
//with the alert class 'warning
//with the _add_values we declared above
//and with our alert id
alertSet(t, 0, "MI_Demo.:_alert_hdl.._event", DPATTR_ALERTEVENT_CAME,
t, 0, "MI_Demo.:_alert_hdl.._class", "warning.",
t, 0, "MI_Demo.:_alert_hdl.._add_values", addVal,
t, 0, "MI_Demo.:_alert_hdl.._alert_id", "MI_Demo_id");
//Now we query a config from the data point where the came time and
//the alert id are same as ours
dpQuery("SELECT ALERT '_alert_hdl.._class' FROM 'MI_Demo.' WHERE '_alert_hdl.._alert_id'= \"MI_Demo_id\" AND '_alert_hdl.._came_time' = \"" + formatTime("%Y.%m.%d %H:%M:%S",t, ".%03d") + "\"", attr);
while (dynlen(attr) <= 1)
{
delay(0, 200);
}
DebugTN("ALERT COUNT: " + getACount((atime)attr[2][2]));
//Returns => ALERT COUNT: 0
// => ALERT COUNT: 1 (at next call)
// => ALERT COUNT: 2 (at next call)
// ...
}
The following example sets a multi-instance alert with CAME alert (DPATTR_ALERTEVENT_CAME) and addValues meaning additional values.
int _alertSet(string dpe)
{
time t = getCurrentTime();
/* Add the strsplit to one row. In this example, the example contains a line break for demonstration purposes */
dyn_anytype addValues = strsplit("1c\n2c\n3c\n4c\n5c\n6c\n7c\n8c\n9c\n10c\n11c\n12c\n13c\n14c\n15c\n16c
\n17c\n18c\n19c\n20c\n21c\n22c\n23c\n24c\n25c\n26c\n27c\n28c\n29c\n30c\n31c\n32c",
"\n");
int rc = alertSetWait( t, 0, dpe + ":_alert_hdl.2._event",DPATTR_ALERTEVENT_CAME
,t, 0, dpe + ":_alert_hdl.2._class" , "information."
,t, 0, dpe + ":_alert_hdl.2._add_values", addValues);
}
Example of how to set a binary alert from CAME to WENT
In the following example all alert couples (CAME time and WENT time) of the data point MI_Demo are inserted into a variable. Each alert time is of the type atime, the internal time format including count and data point identifier. In the Log Viewer it looks like this:
[2012.12.22 12:12:12.000 (7 ) System1:MI_Demo. (Type: 41 Sys: 1 Dp: 508 El: 1 : 0..0)]
With the function getACount() you get the count of the given alert time (in this case the count would be 7). In order to address multiinstance alerts you need the alert time and the count.
With the status bits (direction, obsolete, visible) you can check whether it's a valid CAME alert and must be set to WENT.
This example is only working for binary multiinstance alerts. If you want to use it for nonbinary multiinstance alerts, you have to specify the details. For example "MI_Demo.:_alert_hdl.2._event" in order to set an WENT action for this alert range. See the second example below.
main()
{
dyn_anytype alarm;
bit32 state;
//All alert couples (CAME time & WENT time) of DP MI_Demo are inserted into the
//variable
dpGet("MI_Demo.:_alert_hdl.._alerts", alarm);
//Then all alerts of the _alerts attribute will be checked whether they are
//CAME actions and must be set to WENT.
for(int j = 1; j <=dynlen(alarm); j++)
{
//The status bits of each alert are needed for checking.
int rc = alertGet(alarm[j], getACount(alarm[j]), "MI_Demo.:_alert_hdl.._state", state);
//Shows the pending alerts (alert time, count, status bits)
DebugN("pending alarms:", rc, alarm[j], getACount(alarm[j]), "MI_Demo.:_alert_hdl.._state",
state, state[1], state[4], state[0], state[31]);
//It's checked if the alerts are still valid and if its direction is CAME with
//the status bits "obsolete", "visible" and "direction"
if (rc != 0 || state[1] == 1 /*obsolete*/ || state[4] == 0 /* visible */ || state[0] == 0 /* went */)
continue;
//If the alert fulfills this requirements, the alertSet() function is executed
//and the alert will be set to WENT with the constant DPATTR_ALERTEVENT_WENT
int rc = alertSet(alarm[j], getACount(alarm[j]),"MI_Demo.:_alert_hdl.._event", DPATTR_ALERTEVENT_WENT);
DebugN(rc);
}
}
EXAMPLE
Multiinstance alerts can be triggered via Control. The following two Control examples show how to set multiinstance alerts to CAME and WENT.
In the following example a multiinstance alert is triggered for the data point "ExampleDP_Arg2". The alert is triggered via the attribute "_event". The attribute is set to "CAME" via the constant "DPATTR_ALERTEVENT_CAME". Note that you have to specify the alert range for the alert handling. For a multiinstance alert with a good range and two alert classes (limit values) - Warning and alert, the alert classes (bad ranges) would be the range 2 (Warning) and 3 (Alert). In the following example a warning is triggered via the "_alert_hdl.2._event". If an alert should be triggered, specify the alert range 3 (_alert_hdl.3._event").
main()
{
int retVal;
time t = makeTime(2016,04,20,15,44,00,000);
retVal = alertSet(t,0, "System1:ExampleDP_Arg2.:_alert_hdl.2._event",DPATTR_ALERTEVENT_CAME);
/* Note that when you want to set an alert to WENT, the time must correspond to the
CAME time and you have to specify the exact time including the milliseconds. In addition,
the ID (meaning the alert count)of the alert must correspond to the count of the
CAME alert. In this example the alert count is 0. See the second parameter in the
alertSet function call*/
DebugN("RetVal:", retVal);
}
In order to set the alert to WENT, use the constant "DPATTR_ALERTEVENT_WENT".
main()
{
int retVal;
time t = makeTime(2016,04,20,15,44,00,000);
retVal = alertSet(t,0, "System1:ExampleDP_Arg2.:_alert_hdl.2._event",DPATTR_ALERTEVENT_WENT);
DebugN("RetVal:", retVal);
}
You can query the alert time, for example, by using the attribute _alert_hdl.._alerts (returns alert pairs) and the function getAcount() which returns the alert count.
main()
{
dyn_anytype alert;
bit32 state;
//All alert pairs are written to the variable "alert"
dpGet("System1:ExampleDP_Arg2.:_alert_hdl.._alerts", alert);
DebugN("dpGet of the alert:", alert);
//Outputs all alerts
for(int j = 1; j<=dynlen(alert); j++)
{
/* The attribute _alert_hdl.._state contains the status bits for an alert in a bit32.
getACount returns the count that is needed for the alertSet, see example above */
int rc = alertGet(alert[j], getACount(alert[j]),"ExampleDP_Arg2.:_alert_hdl.._state",state);
//Outputs the pending alerts (alert time, count)
DebugN("Pending alerts:", rc, alert[j],"getAcount:", getACount(alert[j]));
}
}
The output of the code:
WCCOAui1: ["dpGet of the alert:"][dyn_anytype 2 items
WCCOAui1:
1: 2016.04.20 16:25:40.591 (0 ) :_alert_hdl.3 (Type: 0 Sys: 0 Dp: 0 El: 0 : _alert_hdl.3.0)
WCCOAui1:
2: 2016.04.20 16:27:59.869 (1 ) :_alert_hdl.3 (Type: 0 Sys: 0 Dp: 0 El: 0 : _alert_hdl.3.0)
WCCOAui1:
]
WCCOAui1:
["Pending alerts:"][0][2016.04.20 16:25:40.591 (0 ) :_alert_hdl.3 (Type: 0 Sys: 0 Dp: 0 El: 0 : _alert_hdl.3.0)]["getAcount:"][0]
WCCOAui1:
["Pending alerts:"][0][2016.04.20 16:27:59.869 (1 ) :_alert_hdl.3 (Type: 0 Sys: 0 Dp: 0 El: 0 : _alert_hdl.3.0)]["getAcount:"][1]
EXAMPLE
The following example sets a multi-instance alert with CAME alert (DPATTR_ALERTEVENT_CAME), alert class "Information" and addValues meaning additional values.
main()
{
int retVal;
time t = makeTime(2019,05,13,9,54,00,000);
retVal = alertSet(t,0, "System1:ExampleDP_Arg1.:_alert_hdl.2._event",DPATTR_ALERTEVENT_CAME);
/* Note that when you want to set the alert to WENT, the time must correspond
to the CAME time (including milliseconds)
In addition, the ID of the alert, meaning the alert count must correspond to the
count of the CAME alert. In this example the alert count is 0.
See the second parameter in the alertSet function call */
DebugN("RetVal:", retVal);
dyn_anytype addValues = strsplit("1c\n2c\n3c\n4c\n5c\n6c\n7c\n8c\n9c\n10c\n11c\n12c\n13c\n14c\n15c\n16c\n17c\n18c\n19c\n20c\n21c\n22c\n23c\n24c\n25c\n26c\n27c\n28c\n29c\n30c\n31c\n32c","\n");
int rc = alertSet( t, 0, "System1:ExampleDP_Arg1.:_alert_hdl.2._event",DPATTR_ALERTEVENT_CAME
,t, 0, "System1:ExampleDP_Arg1.:_alert_hdl.2._class", "information."
,t, 0, "System1:ExampleDP_Arg1.:_alert_hdl.2._add_values",addValues);
}
Example of how to acknowledge a multi instance alert via a driver
External alerts of peripheral devices (S7, BACnet, OPC) must be written on the internal data point elements _Driver.AL.AckDps and _Driver.AL.AckData to be acknowledged via the respective driver (refer to Multiinstance alerts for further information). This can be realized by acknowledging the alert via the alert screen or using the function isAckable(). Following example shows how an alert can be passed to the isAckable() function in order to be acknowledged.
main()
{
int ret;
//time, count and DPE must correspond to an unacknowledged alert
//The attribute of the DPE (in our case _abbr) does not matter
time t = makeTime(2016,4,12,14,30,23, 608, true);
atime a = makeATime(t, 14, "System1:ClientAlarm_2.boolean:_alert_hdl.2._abbr");
dyn_atime dps = makeDynATime(a);
isAckable(2, dps, ret);
DebugN(ret);
}