Skip to content

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.


Access to Custom Insights are controlled by your ExoSense Tier and management is available by administrative user permission.

Custom Insight Function Management

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.

Example showing a custom function configuration

Creating Modules

Within ExoSense's INSIGHTS tab, you may define new modules for your collections of custom functions.

Create a Insight Module

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.

Create a new function


Functions can also be quickly duplicated, which provides a quick place to start to generate a new similar function.


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.

Adding Constants to a function

Adding Inputs to a function


The custom insights support MathJS or JSON-e expressions. Reference syntax for these languages can be found here:


When using MathJS, the 'Logic' is the contents to be provided within a math.evaluate() function


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'

Example of using MathJS

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, Vwith 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"}

Example using Math.js to generate a JSON output value

    url: A,
    title: B


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

Selecting the Rule type

Rules must return an output of type "JSON"

Setting the output type to 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

Adding a Constant to a rule


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

Testing the custom logic


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.



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.


As insights are streaming data logic operations, functions must be able to respond quickly.