Pre-Processing Functions ✔️
Warning: You’re entering an advanced section for engineers and developers. Topics described below are not a needed for most PackOS users. They require some programming skills, but can help you better tune PackOS to your needs
Introduction
You can think of the pre-processing functions as tools that you can use to perform computations on signals that PackOS receive before they are processed and assigned to specific machines.
Example use cases include:
hex-to-decimal conversion
bit selection
value multiplication
signal aggregation
line flow change
changeover end
Syntax
Each function is a C# script. It’s a strongly typed language requiring you to handle type conversions, but also making sure there are no syntactic errors by compiling the script before persisting.
Head to https://docs.microsoft.com/en-us/dotnet/csharp/tour-of-csharp/tutorials/ for a tutorial
In addition to variables and services provided by the platform (more about that below), all operations on Double, Int, String or DateTime variables are available to you.
Configuration
In order to configure pre-processing functions in PackOS, you will need to:
1. Go to Settings by clicking on the Settings button in the left sidebar.
2.Click on the Pre-Processing Functions in the section Advanced located at the bottom of the page.
When you click on Save, the script is compiled and validated. If no errors are shown, it means that that you did not use any forbidden variables or make any typos.
Click on the blue play button to test your function using any trigger input value.
Specifying trigger tags
Each function is triggered when one of the defined tags is observed. Each tag is a pair of Source URI and Device ID.
Source URI usually specifies OPC UA tag available in the OPC Server. If another type of data source is used – it’s the corresponding tag assigned to that node in LogiX Gate.
Device ID further specifies which data source (LogiX Gate’s input) for the Source URI is used, mostly needed when there are multiple OPC Servers publishing the same tags.
You can also trigger a function based on an internal system events. Such us new downtime. To subscribe on them, use the following tags:
Source URI:
event_[MachineName]_WorkLogOpenedEvent
, DeviceId:lineName
Source URI:
event_[MachineName]_WorkLogUpdatedEvent
, DeviceId:lineName
e.g. event_Cartoner_WorkLogOpenedEvent
/ Line1
To trigger on a number of tags at once, you can use *
in the SourceURI, which is a placeholder for a number of any characters.
e.g. event_*_WorkLogOpenedEvent
/ Line1
will be triggered by a new downtime on any machine from that line.
Available variables
The following variables are available and can be used in the script. There are nested objects containing multiple simple types, and services which can be used to query more data.
TriggerValue [string?]
-- value from the message which triggered the functionTrigger [object]
– details about the triggerNodeId [string?]
-- Source URI from the message which triggered the functionApplicationUri [string?]
-- Device ID from the message which triggered the functionValue [object]
-- details about the trigger valueValue [string?]
-- same as TriggerValue variable aboveSourceTimestamp [DateTime]
-- timestamp of the messageStatusCode [object?]
-- details of the connection errorSymbol [string]
-- Name of the issueCode [long]
– OPC error code
TagValue [service]
-- access to current values of all received tagsstring GetValue(string sourceUri, string? deviceId)
– getting raw string value of a tag (it does not necessarily need to be one of the trigger tags)T? GetValue<T>(string sourceUri, string? deviceId)
– value of a tag converted to the desired type (or a default value of that type if conversion invalid)DateTime? GetUpdate(string sourceUri, string? deviceId)
– timestamp of the last update of this tag
Element [service]
-- access to current element stateWorkLog? WorkLog(string elementName)
– current state of the elementElementId [Guid]
– machine/line identifierIsForced [bool]
– true/false if the current state is forcedWorkStateName [string]
– code name of the current state (e.g. holdup)WorkEventId [Guid]
– problem identifierWorkEventOwnerId [Guid]
– identifier of the machine, which is the owner of the problemWorkEventName [string]
– name of the problemStartDate [DateTime]
– timestamp when the state bugRootElementId [Guid?]
– identifier of the root elementRootWorkEventId [Guid?]
– identifier of the root element problemRootStateName [string?]
– code name of the root state (e.g. holdup)RootStartDate [DateTime?]
– timestamp of the root state
double GetUnitMultiplier(string elementName, string fromUnit, string toUnit)
- reads the specified conversion from the active unit conversion matrix (indirect conversions will be also returned)CounterValue Counter(string elementName, string counterName)
- current value of a specified counter (value already validated by the counter guard)SignalValue Signal(string elementName, string signalName)
- current value of a specified signalstring CurrentFlow(string lineName)
- returns the current flow of the lineIReadOnlyCollection<ElementInfo> GetLineMachines(string lineName)
- list of machines from that lineId [Guid]
- machine IdentifierName [string]
- name of the machine
IReadOnlyCollection<WorkEvent> GetWorkEvents(string elementName)
- dictionary of problems assigned to the machineId [Guid]
- problem IdentifierName [string]
- (not translated) name of the problemWorkStateName [string]
- code of the work state the problem is assigned to
Guid? RunWorkEventRules(string elementName)
- execute rules specified for the element. Returns identifier of the problem, if no rule is true - null is returned.
Store [service]
-- memory space for custom variablesbool TryGet(string key, out string value)
– getting value of the keyvoid Set(string key, string value)
– setting value of the key
Logger [service]
-- loggervoid Log(string message)
- logging custom messages, to be inspected while debugging
In service methods, specifying deviceId
is optional. If not provided, the first matching Source URI value will be returned.elementName
is either directly a name of the line, or a path to a machine in the format:
LineName/ MachineName (e.g. Line1/Filler)
Function result
Pre-processing function returns a list of commands, all implementing IPreProcessingCommand
type. There are numerous command types available, each function can return a mix of them. New commands will be added in the future to cover more scenarios.
Tag(string value, string sourceUri, string? deviceId = "")
- returns a new value with new SourceUri and DeviceId which then can be mapped to one of the signals in machine or line definition.SetFlow(string lineName, string flowName)
- changes active flow on the selected lineResetBuffers(string lineName)
- resets all tracked line buffers (see: [In Progress: Differential waste calculation])EndForcedState(string elementName)
- forces state recalculation from rules on the provided element, ending the forced stateSetWorkLog(string elementName, string rootElementName, DateTime from, DateTime to, string problemName)
- injects specific downtime in the line/machine history. Will override any existing downtimes in the specified time rangeCurrentWorkLog(string elementName, string problemName, string rootElementName)
- allows to specify directly what is a line/machine state, and point to a root cause on a specific machineSetExpectedPerformance(
string elementName, PerformanceType performanceType, double value, string unit)
available performance types:
PerformanceType.Designed
PerformanceType.Validated
Example functions:
The simplest valid function can return just an empty list:
return new IPreProcessingCommand[0];
2. Calculate a sum of 3 tags “a”, “b”, “c” and return it as tag “sum”
// 1. Use tag dictionary to get latest values for each of the tags
double a = TagValue.GetValue<double>(“a”);
double b = TagValue.GetValue<double>(“b”);
double c = TagValue.GetValue<double>(“c”);
// 2. Calculate the sum
double sum = a + b + c;
// 3. Return the calculated variable as a command
return new []
{
new Tag(sum, “sum”)
};
Execution history inspection
By inspecting “Executions history”, you can review recent and past function runs.
This way you can see:
- results
- logs generated (if any)
- exceptions raised