Scripts and Formulas

The Server application has a built-in engine for executing user scripts. Scripts are used to calculate channel values and statuses, as well as to calculate command values.

Scripts are written to the Scripts table of the configuration database. A project created using a template already contains an initial set of scripts, which can be used as examples for developing your own scripts. Variables and functions implemented in the Scripts table are then called in the Input Formula and Output Formula columns of the Channels table. To perform formula calculations for a channel, select the checkbox in the Formula Enabled column.

Script Creation Rules

General rules for writing and using scripts:

  1. Scripts are written according to the syntax of C# language. Various .NET framework classes are available, such as Math, DateTime, and File.
  2. New constants, fields, properties, and methods are added to the Scripts table and become available in channel formulas.
  3. If at least one script or formula contains an error, Server operation is impossible. Information about errors in scripts is written in the Server application log.

Rules for calculating channel formulas:

  1. An input formula for channels of the Input and Input/Output types is calculated only when Server receives new data for that channels. Use the mentioned types of channels if the data comes from devices.
  2. An input formula for channels of the Calculated and Calculated/Output types is calculated continuously at each iteration of the main Server loop. The calculation sequence is from smaller to larger channel numbers. Calculated channel types are used if the value and status of a channel are calculated based on data of other channels.
  3. An output formula for channels of the Input/Output, Calculated/Output and Output types is calculated when a command is sent to the corresponding channel.
  4. A channel status after calculating an input formula for channels of the Input and Input/Output types is equal to the status of the data transferred to Server, if the status calculation is not explicitly specified in the formula.
  5. For channels of the Calculated and Calculated/Output types, the status is set to Defined if the status calculation is not explicitly specified in the formula.
  6. If an input formula contains the ";" symbol, it is split into two parts: the first part calculates the channel value, and the second part calculates the channel status.
  7. If a channel has specified limits, the channel status is recalculated taking the limits into account after calculating the channel's input formula.
  8. Formulas must return values of certain data types, described below.

Channel input formulas return data of the following types:

Data Type Description
double Channel value
CnlData Channel value and status
long 64-bit integer value of a channel whose data type is set to Integer in the Channels table
string String value of a channel whose data type is set to ASCII string or Unicode string in the Channels table

If a channel's input formula returns a data type other than those listed in the table above, the value returned by the formula is cast to the appropriate type based on the data type of the channel. The part of the channel input formula that calculates the channel status must return an integer value of type int.

Channel output formulas return data of the following types:

Data Type Description
double Command value. To cancel a command, formula must return double.NaN
CnlData Command value. To cancel a command, formula must return CnlData.Empty
byte[] Binary command data. To cancel a command, formula must return null
string String command data. Converted by Server into a byte array

Available Variables

The scripting engine provides the following built-in variables:

Variable Data Type Description
Timestamp DateTime Timestamp of the processed data (UTC)
IsCurrent bool Processed data is current data
CnlNum int Channel number for which the formula is calculated
Channel Cnl Properties of the channel for which the formula is calculated
ArrIdx int Index of the processed array element
Cnl, CnlVal double Channel value transmitted to Server before the calculation
CnlStat int Channel status transmitted to Server before the calculation
CnlData CnlData Channel data transmitted to Server before the calculation
Cmd, CmdVal double Command value transmitted to Server before the calculation
CmdData byte[] Command data transmitted to Server
CmdDataStr string Command data as a string

Available Functions

The scripting engine provides the following built-in functions:

Function Data Type Description
N(n) int Returns the channel number n. Used in channel cloning
Val() double Actual value of the formula channel
Val(n) double Actual value of the channel n
SetVal(n, val) double Sets the current value of the channel n
Stat() int Actual status of the formula channel
Stat(n) int Actual status of the channel n
SetStat(n, stat) int Sets the current status of the channel n
Data() CnlData Actual data of the formula channel
Data(n) CnlData Actual data of the channel n
SetData(n, val, stat) double Sets the current value and status of the channel n
SetData(n, cnlData) double Sets the current data of the channel n
NewData(val, stat) CnlData Creates a new channel data instance
PrevVal() double Previous value of the formula channel
PrevVal(n) double Previous value of the channel n
PrevStat() int Previous status of the formula channel
PrevStat(n) int Previous status of the channel n
PrevData() CnlData Previous data of the formula channel
PrevData(n) CnlData Previous data of the channel n
Time() DateTime Actual timestamp of the formula channel
Time(n) DateTime Actual timestamp of the channel n
PrevTime() DateTime Previous timestamp of the formula channel
PrevTime(n) DateTime Previous timestamp of the channel n
Deriv(n) double Time derivative of the channel n

Functions from Project Template

In a project that was created based on a standard template, the Scripts table contains the following functions:

Function Data Type Description
GetBit(val, n) double Returns the n-th bit of the specified value
GetBit(cnlData, val) CnlData Returns a channel data consists of the n-th bit of the value and the channel status
SetBit(val, n, isOn) double Sets the n-th bit of the specified value
SetBit(cnlData, n, isOn) CnlData Sets the n-th bit of the channel value, keeping the channel status unchanged
GetByte(val, n) double Returns the n-th byte of the specified value
DataRel(offset) CnlData Channel data relative to the current channel
SetData() double Sets the current channel data according to the command value
Now() double The current date and time as a floating-point number. Uses the server time zone
UtcNow() double The current date and time as a floating-point number. Uses universal time zone (UTC)
UnixTime() long The current Unix time in seconds
EncodeDate(dateTime) double Converts the specified date and time to a channel value of Double type
DecodeDate(val) DateTime Converts the channel value to a date and time
EncodeAscii(s) double Converts an ASCII string, up to 8 characters long, to a floating point number
EncodeUnicode(s) double Converts a Unicode string, up to 4 characters long, to a floating point number
DecodeAscii(val) string Converts the specified value to an ASCII string up to 8 characters long
DecodeUnicode(val) string Converts the specified value to an Unicode string up to 4 characters long
Substring(s, startIndex, length) string Extracts a substring from the string with bounds checking
SplitAscii(getStringFunc) string Splits an ASCII string to store by several channels
SplitUnicode(getStringFunc) string Splits an Unicode string to store by several channels
EverySec(getDataFunc) CnlData Executes the specified function every second
EveryMin(getDataFunc) CnlData Executes the specified function every minute
EveryHour(getDataFunc) CnlData Executes the specified function every hour
CountPulse(cnlNum) double Counts a pulse of the specified channel
HourStarted() bool Indicates that a new hour has started. The result is true once for each channel
DayStarted() bool Indicates that a new day has started. The result is true once for each channel
MonthStarted() bool Indicates that a new month has started. The result is true once for each channel

Additional scripts, including those for calculating averages, are available on GitHub.

Debugging Scripts

When developing your own scripts, follow the syntax rules and check that the scripts work correctly. If the Server service failed to compile scripts at startup, error information is displayed in the Server operation log ScadaServer.log, and the compiled source code is available in the CalcEngine.cs file, which is located in the Server log directory. To develop complex formulas, we recommend using Microsoft Visual Studio or Visual Studio Code.

Examples of Formulas

Example 1: Linear transformation of a channel value received from a device. The formula is used for a channel of the Input type.

10 * Cnl + 1

Example 2: The sum of the values of channels 101 and 102. The status is extracted from channel 101. The formula is used for a channel of the Calculated type.

Val(101) + Val(102); Stat(101)

Example 3: The formula that is used for a channel of calculation type extracts the 0th bit from the data of channel 105.

GetBit(Data(105), 0)

Example 4: The formula increments the counter by one every minute, resetting the counter at the beginning of each hour.

EveryMin(() => HourStarted() ? 0 : Val() + 1)