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 function

  • Trigger [object] details about the trigger

    • NodeId [string?] -- Source URI from the message which triggered the function

    • ApplicationUri [string?] -- Device ID from the message which triggered the function

    • Value [object] -- details about the trigger value

      • Value [string?] -- same as TriggerValue variable above

      • SourceTimestamp [DateTime] -- timestamp of the message

      • StatusCode [object?] -- details of the connection error

        • Symbol [string] -- Name of the issue

        • Code [long] – OPC error code

  • TagValue [service] -- access to current values of all received tags

    • string 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 state

    • WorkLog? WorkLog(string elementName) – current state of the element

      • ElementId [Guid] – machine/line identifier

      • IsForced [bool] – true/false if the current state is forced

      • WorkStateName [string] – code name of the current state (e.g. holdup)

      • WorkEventId [Guid] – problem identifier

      • WorkEventOwnerId [Guid] – identifier of the machine, which is the owner of the problem

      • WorkEventName [string] – name of the problem

      • StartDate [DateTime] – timestamp when the state bug

      • RootElementId [Guid?] – identifier of the root element

      • RootWorkEventId [Guid?] – identifier of the root element problem

      • RootStateName [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 signal

    • string CurrentFlow(string lineName) - returns the current flow of the line

    • IReadOnlyCollection<ElementInfo> GetLineMachines(string lineName) - list of machines from that line

      • Id [Guid] - machine Identifier

      • Name [string] - name of the machine

    • IReadOnlyCollection<WorkEvent> GetWorkEvents(string elementName) - dictionary of problems assigned to the machine

      • Id [Guid] - problem Identifier

      • Name [string] - (not translated) name of the problem

      • WorkStateName [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 variables

    • bool TryGet(string key, out string value) – getting value of the key

    • void Set(string key, string value) – setting value of the key

  • Logger [service] -- logger

    • void 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 line

  • ResetBuffers(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 state

  • SetWorkLog(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 range

  • CurrentWorkLog(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 machine

  • SetExpectedPerformance(
    string elementName, PerformanceType performanceType, double value, string unit)

    • available performance types:

      • PerformanceType.Designed

      • PerformanceType.Validated

Example functions:

  1. 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