Inline Insight Functions¶
ExoSense Administrators have three options for adding additional Insight modules to an ExoSense application:
- Third-party Insights from Exchange
- Create custom inline functions from within ExoSense
- Building a hosted external web service
Once insight functions have been enabled, end-users with the Asset Management permission can then use these functions in their asset configuration.
This document covers how to create and use custom inline Insight modules and functions from within ExoSense.
Custom Inline Insights¶
Advanced Topic
Building custom Inline Insights is a software developer topic.
Custom Insights can be created and managed within an ExoSense application itself. These 'inline' functions operate natively in the data pipeline and do not require any external services.
Hint
Access to Custom Insights are controlled by your ExoSense Tier and management is available by administrative user permission.
User Experience¶
An end user who has the Asset Management permission can use these functions in their pipeline configuration for the asset. They will be provided with a list of modules and functions to choose from including the custom functions. Users are then able to choose matching signals and define any constants.
Creating Modules¶
Within ExoSense's INSIGHTS tab, you may define new modules for your collections of custom functions.
Creating Functions¶
Once you have a module, you can create and edit functions, which includes giving it a name, description, type \(Transform or Rule\), defining Inputs, Outputs, Constants and the actual function logic.
Duplicating¶
Functions can also be quickly duplicated, which provides a quick place to start to generate a new similar function.
Properties¶
Inputs, Outputs, and Constants must be defined. These properties inform and guide users who are configuring the specific function for an asset. If a function is mean to operate only on Temperature data, than the input definitions allow you to limit the application to only allow Temperature signals, with the ability to even restrict down to the unit type.
Logic¶
The custom insights support MathJS or JSON-e expressions. Reference syntax for these languages can be found here:
Math.js
When using MathJS, the 'Logic' is the contents to be provided within a math.evaluate() function
JSON-e
When using JSON-e, the 'Logic' is the JSON-e 'Template'. The Inputs(A,B,C) and Constants are the 'Context' given to the 'Template'
Using Inputs in functions¶
Inputs are available as variables using the tags A
, B
, C
, D
, E
(up to 5 inputs are supported).
Example Function code with 3 Input Signals that are added
A + B + C
{ "$eval": "A + B + C" }
Using constants in functions¶
Constants that are defined are available by simply using the name of the defined constant
Handling Outputs in functions
If there is only one output, the result of the function automatically is applied to the output value.
Example Function
If A = 50 then the Output Signal = 150
A + 100
{ "$eval": "A + 100" }
In the case of multiple output signals, to reference the outlets, we use the set_outlet()
function. Normally, the results of a function go into the first outlet, but if we set the first outlet to a value, then that is used instead of the function results. Also, the set_outlet()
function matches the indexing of the language. So in Math.js the first outlet is 1
, whereas in JSON-e the first outlet is 0
.
Example with multiple output signals
If A = 50; then Output Signal 1 will be 50 and Output Signal 2 will be 1050
set_outlet(2, A + 1000); set_outlet(1, A)
[
{ "$eval": "set_outlet(1, A + 1000)" },
{ "$eval": "set_outlet(0, A)" }
]
If you don't want to return a value to each output every time, then set some of them to undefined
. As long as one outlet has a value, then function will produce output. We can show this with a slightly more complex bit of logic that filters values to one of the two outlets.
Example the shows multiple outputs but filters which output is used
In this case if A = 50; then Output Signal 1 = undefined (not set) and Output Signal 2 = 50
(A > 100)?outlets[1]=A:outlets[2]=A; outlets[1]
{
"$if": "A > 100",
"then": [
{ "$eval": "set_outlet(0,A)" },
{ "$eval": "set_outlet(1,null)" }
],
"else": [
{ "$eval": "set_outlet(0,null)" },
{ "$eval": "set_outlet(1,A)" }
]
}
Using Output Signal Values in functions¶
Sometimes you will have logic that builds on prior results. The outlets are available under the variables in order Z
, Y
, X
W
, V
with Z being the first output signal.
Example using the last output signals value \(last result\)
(isNumeric(Z)?Z:0) + A
{ "$if": "typeof(Z) == 'number'",
"then": { "$eval": "Z + A" },
"else": { "$eval": "A" }
}
Functions with non-numerical data¶
Functions can work with strings, boolean, JSON, and binary data also.
Example using JSON-e to generate a JSON output value
{
"url": {$eval: "A"},
"title": {$eval: "B"}
}
You can use the normalize()
function in JSON-e, which takes 1 or 2 parameters. First is the string to normalize()
, and second is a string of how. The second parameter is one of NFC, NFD, NFKC, NFKD. See https://www.unicode.org/reports/tr15/#Norm_Forms for more information.
Example using Math.js to generate a JSON output value
{
url: A,
title: B
}
Warning
Functions with more than one input are called each time a new value happens for any signal. When first used, the first signal value that triggers calling the function will likely be in a situation where other signals may not have values yet. In this case, the result is 'undefined', When a function returns undefined it is dropped.
Using historical data points¶
Prior values can be accessed from the 'prior' variable. Only one previous data point is necessarily accessible. The first dimension of the array, denotes how many data points historically to trace. The second dimension of the array accesses the timestamp in index 1
and the value in index 2
. (In JSON-e, the indexes will be 0
for timestamp and 1
for the value.)
The current value is the most recent "historical" value, that is, A
is equivalent to prior.inlets.A[1,2]
(in Math.js). This makes the previous historical datapoint prior.inlets.A[2,2]
Example finding the difference between the current and previous first inlet
delta = A - prior.inlets.A[2,2]
{ "$eval": "A - prior.inlets.A[1,1]" }
Creating Custom Rules¶
To create a custom select "Rule" as the Insight Type
Rules must return an output of type "JSON"
This output must return an object that contains a field "level". This level will indicate the state of the rule.
State | Value |
---|---|
Normal | 0 |
Info | 1 |
Warning | 2 |
Critical | 3 |
Error | 4 |
This can be returned either directly or the user can select the state to return via "Constants"
An example where the state is returned directly
normal = 0
info = 1
warning = 2
critical = 3
error = 4
{level: (A == 90) ? warning : normal }
{ "$let": {
normal: 0,
info: 1,
warning: 2,
critical: 3,
error: 4
},
in: { "$if": "A == 90",
"then": { "$eval": "warning" },
"else": { "$eval": "normal" },
}
}
An example where the state is specified in the Rule's configuration
{level: (A == 90) ? level : 0}
{
"level": {
"$if": "A == 90",
"then": { "$eval": "level" },
"else: 0
}
}
Testing¶
The interface also allows in-browser testing of your functions by providing a form to set your input signal values, constants, and last output value (if necessary).
Importing/Exporting¶
When creating a new function, you have the option to Import a file that will generate the entire function for you. Insight files can be exported from your own custom insights, provided to you by Exosite for reference examples or by third-party or partner. Functions can be exported from the Insights interface.
Examples¶
Hint
Users can view the source for off the shelf standard functions included in ExoSense and may duplicate and export these to use for starting a new customized function.
Linear Gain
A
is the input signal, gain
and offset
are constants set by user
A * gain + offset
{ "$eval": "A * gain + offset" }
Continuous Accumulation
A
is the input signal and Z
is the output
A + (isNumeric(Z)?Z:initialValue)
{ "$if": "typeof(Z) == 'number'",
"then": { "$eval": "A + Z" },
"else": { "$eval": "initialValue" }
}
Mapping a signal's numeric range to a status
For example 0 to 10 is off, 10 to 40 is on, and greater than 40 is error
(A>0 and A<10)?"off":(A>10 and A<40)?"on":"error"
{ "$switch": {
"A > 0 && A < 10": "off",
"A > 10 && A < 40": "on",
"A <= 0 || A >= 40": "error"
}
}
Self-Hosted Custom Insights¶
Custom Self-Hosted Insights can be published in the Exosite IoT Marketplace for private or public use. This interface requires hosting a web-service that supports HTTP requests using Exosite's external Insight schema for handling streaming data requests and responses.
These self-hosted Insights can run anywhere you see fit—in Exosite Murano as a custom solution, Amazon Web Services, Microsoft Azure, Google Cloud Products, or any other hosting platform.
Self-Hosted external insight functions have the same properties and functionality as the custom inline insights, with the noted benefits:
- Code-base can be hosted and maintained on any infrastructure you want
- Allows for using external services and platforms for more advanced analytics and functionality
- Insights can be published in Exosite's IoT Marketplace for use by other Exosite customers.
Warning
As insights are streaming data logic operations, functions must be able to respond quickly.