Rule Engine

Rule Engine

Rule engine - is a powerful tool that allows you to create the actions you need that will be executed according to your own rules. The rule engine has 3 main components: trigger, rule, and action.

Triggers

Trigger - is a component that reacts to some event (depending on trigger type) and sends the event’s context to the rule (or rules) it is attached to. For example, the ‘Endpoint time series updated’ trigger will send to rule the context with time series data of the event and some basic information like app version name of the endpoint that the event happened on.

Here is the list of all trigger types:

  • Endpoint metadata updated - triggers when someone updates the metadata of the endpoint that the trigger is attached to.
  • Endpoint time series updated - triggers when an endpoint sends new time series data.
  • Endpoint data sample updated - triggers when endpoint sends new data samples.
  • Schedule - triggers by CRON expression (e.g. every 10 minutes or every Tuesday at 15:00).
  • Alert lifecycle event - triggers when some change happens to any alert (e.g. alert created, resolved, acknowledged, etc.)

Rules

Rule - is a component that receives the context from trigger(s) attached to it and according to condition executes (or not) attached actions. The condition in the rule is a JavaScript expression that should return true, false, or null. Depending on the returned value, the rule will execute:

  • true - attached to the rule actions that must be run on the positive outcome of the rule evaluation.
  • false - attached to the rule actions that must be run on the negative outcome of the rule evaluation.
  • null - nothing.

Context

To make rules satisfy your special requirements, you can use context in the condition.

Context (ctx) contains several objects in it: endpoint, data, tenantId, toolbox and trigger.

Endpoint

Represents the endpoint that the rule is currently executing on. The endpoint object is present in context regardless of trigger type and contains the following methods:

  • getId() - returns the endpoint’s ID.

    Example:

return ctx.endpoint.getId() === "b1857120-9e72-4886-b3c2-b1bddccbf475";
  • getChildren() - returns list of endpoint’s children endpoints.

    Example:

return ctx.endpoint.getChildren()
           .some((endpoint) => endpoint.getId() === "b1857120-9e72-4886-b3c2-b1bddccbf475") ? true
                                                                                            : false;
  • getParent() - same as getChildren(), but returns single parent endpoint.

    Example:

return ctx.endpoint.getParent().getId() === "b1857120-9e72-4886-b3c2-b1bddccbf475" ? true : false;
  • getMetadata() - returns endpoint’s metadata.

    Example:

return ctx.endpoint.getMetadata().maxVoltage <= 14;
  • getTimeSeries() returns the endpoint’s time series object, which has the next methods
    • last()
    • last(String beforeDate)
    • last(Integer count)
    • last(String beforeDate, Integer count)
    • data(String fromDate, String toDate)
    • data(String fromDate, String toDate, String sort)

    Examples:

return ctx.endpoint.getTimeSeries("temperature").last("2023-08-17T13:08:31").values.value == 20.2;
return ctx.endpoint.getTimeSeries("temperature")
           .data("2017-04-19T00:00:00.000Z", "2017-04-22T00:00:00.000Z").length == 2;
  • getAggregation() - returns an object that helps with aggregation functions. That object has the next methods:
    • min(String fieldName, String fromDate, String toDate)
    • max(String fieldName, String fromDate, String toDate)
    • avg(String fieldName, String fromDate, String toDate)

    Examples:

return ctx.endpoint.getAggregation()
           .max("temperature","2017-04-19T00:00:00.000Z", "2017-04-22T00:00:00.000Z") >= 50;
  • getRelations(String relationType) - giving a relation type, returns a list of endpoint relations. The relation type here is an enum and has the next possible values:
    • CONTAINS
    • IS_CONTAINED_BY
    • SUPPORTS
    • IS_SUPPORTED_BY
    • MANAGES
    • IS_MANAGED_BY
    • CONTROLS
    • IS_CONTROLLED_BY

    Each object in the returned list has the next methods:

    • getEntityId()
    • getEntityType()
    • getRelations(String relation)

    Example:

    const driver = ctx.endpoint.getRelations('IS_MANAGED_BY')[0];
    const endpoint = driver.getRelations('MANAGES')[0];
    return driver.getEntityId() === 'driver_id_1' && endpoint.getEntityId() === 'endpoint_id_1';
    
Data

Data is a free-form map where the user can place any data he needs to be stored during whole lifecycle of the trigger-rule-action execution. For example, we can add some information during rule execution:

ctx.data.set('ruleExecutionTime', Date.now());
return true;

And then, use that information in any action that supports expressions:

return `Rule exeution time is: ${ctx.data.get('ruleExecutionTime')}`;
TenantId

TenantId - it’s an ID of the endpoint’s tenant.

return ctx.tenantId === "tenant-id-1";
Trigger

Context’s trigger object contains the data of the event that triggered the rule, and its syntax may vary depending on trigger type. Here are examples of context syntax for different trigger types.

Data sample

Humidity and temperature in the next snippet - are examples of data samples.

{
  "ctx": {
    "trigger": {
      "isEndpointDataSamplesReceived": true,
      "endpointDataSamplesReceived": {
        "endpointId": "b1857120-9e72-4886-b3c2-b1bddccbf475",
        "appVersionName": "smart-kettle-v1",
        "dataSamples": [
          {
            "temperature": 10,
            "humidity": 48
          },
          {
            "temperature": 11,
            "humidity": 47
          }
        ]
      }
    }
  }
}
return ctx.trigger.endpointDataSamplesReceived.dataSamples[0].temperature === 10;
return ctx.trigger.isEndpointDataSamplesReceived === true;
return ctx.trigger.endpointDataSamplesReceived.endpointId === 'b1857120-9e72-4886-b3c2-b1bddccbf475'
       && ctx.trigger.isEndpointDataSamplesReceived;
Time series

The temperature in the next snippet - is just an example of time series values.

{
  "ctx": {
    "trigger": {
      "isEndpointTimeSeriesUpdated": true,
      "endpointTimeSeriesUpdated": {
        "endpointId": "b1857120-9e72-4886-b3c2-b1bddccbf475",
        "appVersionName": "smart-kettle-v1",
        "timeSeriesName": "temperature",
        "temperature": [
          {
            "timestamp": 1710942992,
            "values": {
              "value": 30
            }
          },
          {
            "timestamp": 1710946448,
            "values": {
              "value": 29
            }
          }
        ]
      }
    }
  }
}
return ctx.trigger.endpointTimeSeriesUpdated.temperature[0].timestamp >= (Date.now() - 10000) &&
       ctx.trigger.endpointTimeSeriesUpdated.temperature[0].values.value >= 10;
return ctx.trigger.isEndpointTimeSeriesUpdated === true;
return ctx.trigger.endpointTimeSeriesUpdated.endpointId === 'b1857120-9e72-4886-b3c2-b1bddccbf475'
       &&
       ctx.trigger.isEndpointTimeSeriesUpdated;
Endpoint Metadata Updated

Humidity, temperature and pressure in the next snippet - are just examples of metadata values.

{
  "ctx": {
    "trigger": {
      "isEndpointMetadataUpdated": true,
      "endpointMetadataUpdated": {
        "endpointId": "b1857120-9e72-4886-b3c2-b1bddccbf475",
        "appVersionName": "smart-kettle-v1",
        "added": {
          "humidity": 47
        },
        "removed": {
          "pressure": "70"
        },
        "updated": {
          "temperature": {
            "newValue": 40,
            "oldValue": 30
          }
        }
      }
    }
  }
}
return ctx.trigger.endpointMetadataUpdated.updated.temperature.newValue === 40;
return ctx.trigger.isEndpointMetadataUpdated === true;
return ctx.trigger.endpointMetadataUpdated.added.humidity === 47;

Actions

Action - is a rule engine component that can be executed by rule and perform some action (e.g. send command to your device or email you). There are several action types:

  • Command invocation - sends a command to your device.
  • Metadata update - updates endpoint’s metadata.
  • Webhook - sends HTTP request to specified URL.
  • Rule execution - executes another specified rule. This action allows building chain of rules.
  • Data sample - sends data samples to an endpoint.
  • Time series - sends time series to an endpoint.
  • Alert activation - activates an alert.
  • Alert resolution - resolves an alert.
  • Send email - sends an email to specified recipients.

Usage example

Let’s say we have a device that can heat up and send data about its temperature. In that case, we can create a rule that will notify us via email if the temperature is too high.

First of all, we need to click on the ‘Rules’ tab and then on the ‘Create rule’ button.

create-rule

After that, we can see the rule creation window. Let’s name our rule.

create-rule

To trigger our rule let’s create a trigger first. Click on the ‘Create trigger’ button, enter the trigger name, and choose your app name, version, and endpoint ID. Also, we should choose a trigger type. In our case, it’s ‘Endpoint data sample updated’ because we are receiving the device’s temperature via data samples.

create-rule

The next step - is writing the rule’s expression. In our case, we are returning true (that will execute positive actions) if the trigger that triggered the rule has ‘endpointDataSamplesReceived’ type and the temperature in the data sample is more or equal to 50.

create-rule

Next step - attaching the action. Click on the ‘Create action button’. Enter the action name and choose the action type. In our case, the type is ‘Send email’. Enter the email sender and add email recipients. Please, note that recipients should verify their emails to receive the emails.

create-rule

After that, we should choose the email subject and enter the email body. To make email the body contains some dynamic values, switch the body from ‘Static’ to ‘Script’ and then we can use the context in the body. Let’s add the device’s name (we can add it to metadata) and the last temperature on the endpoint to the email body.

create-rule

After that, when the device sends the data with a temperature over 50, we receive an email.

create-rule