Concept

In general scripts are attached to objects that exist in the different models of system:inmation. Technically speaking, scripts are hosted by properties of objects. Depending on the object type, the property that hosts the script can be different, and the effect of setting it can have a different outcome.

A GenericItem Running a Lua Script
Figure 1. A GenericItem Running a Lua Script
Because scripts reside in object properties, they can be read and written like any other property, including access from external interfaces like .NET API!

Some object types are able to execute scripts while others can only store them. The latter type is used to store scripts in higher tree levels, so that their successors (children in tree) can access and make use of them. Such scripts are stored as Lua script libraries.

A GenericFolder Holding a Script Library
Figure 2. A GenericFolder Holding a Script Library

Object Types Actively Executing Scripts

The object types that can execute scripts are:

I/O Model
  • GenericItem This object type is used to generate data on a periodical basis. It can generate data in various ways, including a Lua script execution.

  • ActionItems This object type is used to execute a script on an event trigger. Various triggers can be defined. The most common one being another object changing its value.

  • Rule The Rule object type can be used during automatic object discovery to make changes to the discovered object while it is being created in system:inmation. One action type of a rule is the execution of a Lua script.

Object Types Passively Executing Scripts

The object types that can keep script libraries are:

I/O Model
  • System The tree’s top level object. Libraries setup here are available to all objects in the whole system.

  • Core Libraries setup here are available to all objects below the particular Core object.

  • Connector Libraries setup here are available to all objects below the particular Connector object.

  • Datasource Libraries setup here are available to all objects below the particular Datasource object.

  • I/O Node Libraries setup here are available to all objects below the particular I/O Node object.

  • Folder Libraries setup here are available to all objects below the particular Folder object.

Lua Scope and inmation Extension

In addition, the scripting engine was extended by an inmation library that allows you to work with system:inmation models, objects and their properties. Functions in the inmation library can be used to create, update, or delete inmation objects. For a detailed description of the inmation Lua extension, please refer to the chapter Lua Scripting in the System Documentation. An online version can be found here.

Creating A Simple Script

As a first step into the Lua scripting environment, we will create a very simple calculation to be executed by the system:inmation Core. This will be done in 3 steps. First we will prepare a location in the object tree to host the objects we need for this example. In the second step we’ll create objects that simulate data, before finally creating the first simple calculation.

Step 1: Preparation of Object Hierarchy

To do so open DataStudio and login with administrative rights. Then go to the I/O Model tree and right click the Core object. Select Admin  New  Data Processing  Folder from the context menu.

Create New Folder
Figure 3. Create New Folder

In the Create Folder Wizard enter "Examples" in the Object Name edit box. Leave all other options as default and click the Create button.

Create Folder Wizard Step 1
Figure 4. Create Folder Wizard Step 1

Select the newly created folder and create a subfolder called "Lua", executing the step mentioned above. Repeat this once more to create a folder within the Lua folder named "Jump Start". You should see something like this in your DataStudio:

Lua Jump Start Object Hierarchy
Figure 5. Lua Jump Start Object Hierarchy
The nested object hierarchy created is not required to run the script! Its only purpose is to structure the application logic, and to fit the example import (see also CHAPTER 3 on page 20).

Step 2: GenericItem for Data Generation

As a starting point, we will create two items that generate simulated data. If you already have a real data source connected to system:inmation, you can skip this step and use real data points. Right click the Jump Start folder and select Admin  New  Generic Item from the context menu.

Create New GenericItem
Figure 6. Create New GenericItem

In the Create Generic Item wizard’s Common step enter Saw Tooth in the Object Name edit box. Leave all other options default and click Next.

Saw Tooth Common Step
Figure 7. Saw Tooth Common Step

In the Limit Settings step, do not make any changes, and click Next In the Generation Type step, change the Function Period to 30000 and click Next.

Saw Tooth Generation Type Step
Figure 8. Saw Tooth Generation Type Step

In the Archive Options step, change the Archive Selection to Production Archive and check the Raw History option. Now click Create to create this object in the tree.

Saw Tooth Archive Options Step
Figure 9. Saw Tooth Archive Options Step

Now create a second simulation item. Right click the Jump Start folder and select Admin  New  Generic Item from the context menu to start the Object Creation wizard again. In the Create Generic Item wizard’s Common step enter Sinus in the Object Name edit box. Leave all other options default and click Next.

Sinus Common Step
Figure 10. Sinus Common Step

In the Limit Settings step, do not make any changes, and click Next. In the Generation Type step, change Function to Sine wave values and the Function Period to 30000. Now click Next.

Sinus Generation Type Step
Figure 11. Sinus Generation Type Step

In the Archive Options step, change the Archive Selection to Production Archive and check the Raw History option. Now click the Create button to create this object in the tree.

Sinus Archive Options Step
Figure 12. Sinus Archive Options Step

You should see something like this in the I/O Model panel of DataStudio:

Simulation Items
Figure 13. Simulation Items

Step 3: Periodical Calculation

In this step we will create another GenericItem, that executes a script making a simple addition calculation periodically. Right click the Jump Start folder and select Admin; New; Generic Item from the context menu. In the Create Generic Item Wizard’s Common step, enter Simple Calc in the Object Name edit box, and select 5000 ms as Generation Period. Now click Next.

Create Periodical Calculation
Figure 14. Create Periodical Calculation

Leave the Limit Settings step as default, and click Next. In the Generation Type step, select the Lua Script Data Generator option, and then click the button to open the Lua Script Body Editor. Enter the following code into the script editor:

function calc()
    -- get the values of the two simulation items
    local sin = inmation.getvalue("/System/INMWS011/Examples/Lua/Jump Start/Sinus")
    local saw = inmation.getvalue("/System/INMWS011/Examples/Lua/Jump Start/Saw Tooth")
    -- return the sum of the values
    return sin + saw
end
-- return the result of the calculation
-- it becomes the current value of the calculation
return calc

The code appears in the Lua Script Body window as shown below:

Calculation Code
Figure 15. Calculation Code

You can see that the editor highlights the Lua syntax in different colors (keywords in blue, comments in green, and strings, including paths in red). Also used in this script is the inmation extension to the Lua environment. Here the getvalue function is called to read a value from an object by using the object’s path in the object tree. The script editor also gives support while you are coding through the LuaSense feature, making suggestions and providing useful explanations of functions, as you type:

LuaSense Coding Help
Figure 16. LuaSense Coding Help

To view the LuaSense suggestions at a particular point in already written code, move the blinking cursor to the required position and press Ctrl+Space to open the information display. The LuaSense feature can also be toggled on/off using the icon in the menu bar of the script editor. After writing the script click Ok to close the editor, then click the Next button. In the Archive Options step, change the Archive Selection to Production Archive and check the Raw History option. Now click the Create button to create this object in the tree.

Simple Calc Archive Options Step
Figure 17. Simple Calc Archive Options Step

The I/O Model panel and the object properties panel for Simple Calc should now look something like the following:

Simple Calc Working
Figure 18. Simple Calc Working

Note how the calculation is executed every 5000 milliseconds (as was configured during creation of the object), independently of the inputs from the Saw Tooth and Sinus objects that change every 1000 milliseconds (as was configured during their creation). If you add the Saw Tooth, Sinus and Simple Calc objects to a RealTimeGrid display (see DataStudio documentation for more details) the different execution times can be observed concurrently, as the respective object values update. An example how to execute a script based on an input data change can be found in CHAPTER 4.

Error Handling

Lua scripts that run into an error during execution will return their error as the current value of the item hosting the script. As an example, open a Script Editor in DataStudio via the Open  Script Editor menu. Then drag & drop the Simple Calc object (created in 2.4.3 Step 3: Periodical Calculation on page 12) from the I/O Model tree into the editor. In the icon menu at the top of the Script Editor display, click this Show Watch Items icon, to display the Watch Items area.

Show Watch Items
Figure 19. Show Watch Items

The watch item will be shown in the Script Editor display below the programming area.

Watch Items
Figure 20. Watch Items

Note that the script item itself is automatically added to the list. Add more items from the I/O Model tree to the watch item list using drag & drop. For example, add the Saw Tooth and Sinus objects that are the inputs for the Simple Calc calculation:

Watch Items Edited
Figure 21. Watch Items Edited

To see how the error handling works, we will create an error in the script. For example, remove the plus sign from line 6. Then click the Update Object icon to apply the change.

Update Script Object
Figure 22. Update Script Object

This creates a syntax error in the script.

Syntax Error in Script
Figure 23. Syntax Error in Script

Note that A) The script editor identifies the syntax error and highlights the section of the code with a red curly underline B) The item’s value becomes the error message, with information about which line is causing the error ("@6") and what the error is. C) The item’s quality turns Bad (red dot by the object in the marked items area and in the I/O model panel)

Distributed Script Execution and Its Limitations

The ability to have scripts housed at various levels of the I/O model (in particular having scripts at the Core and the Connector level), means the scripts can be executed by different components running on different physically distributed hosts (for instance, a Core in the headquarters, or Connectors in remote locations). Basically this means that a script residing on the Core level is actually executed by the inmation Core service, while a script residing on the Connector level is actually executed by the inmation Connector service. This distributed computation approach has an impact on the execution possibilities of each script, and when these scripts can execute. Clearly a script on the Connector level can no longer be executed when the Connector service is shut down. On the other hand, it can be executed independently from an active connection to the Core service. The same applies to scripts on Core level, which can run independently of any connected Connector. This ability comes with the limitation that the Connector can only work with objects, and their values, that belong to the Connector’s model tree hierarchy, meaning objects that are successors of the Connector object in the I/O model. The Core however, can operate on all objects, including ones of various Connectors, because they are all successors of the Core object. In addition, the Core can also operate across the different models, that logically reside in the Core. This means a Lua script on Core level can make changes to multiple models at the same time (e.g. create new objects in the I/O model and KPI model, and link them).

Scripts and Thread Balance

The Lua script engine is embedded in the backend services of system:inmation. Therefore, all execution of scripts happens on the server side. This allows the complete server side CPU power of all participating machines within system:inmation to be used, but also requires that users create scripts in a responsible way. The real time engine of the backend services also executes scripts in real time on shared resources. Should a script cause a very high memory allocation, or CPU load, this can have a negative impact on the backend service executing it! This has particular relevance for scripts that run for a time longer than a second (for example when scripts query data from some other data source like a SQL database). In these cases, it is strongly advised that they are run on a dedicated thread. To configure this, check the Dedicated Thread Execution property of the script:

Dedicated Thread Execution
Figure 24. Dedicated Thread Execution

However, it does not make sense to run all scripts on a dedicated thread as a high number of threads can also slow down a backend service (depending on the available hardware). Because of this it is important to balance the number of scripts running on dedicated threads with the ones running on shared resources. Should you run into the situation where many scripts (1000+) have to execute the same long running code, we recommend that you create a single script running on a dedicated thread, that can deal with a queue of executions within the script environment.