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.
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:
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:
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.
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;
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;
Examples:
return ctx.endpoint.getAggregation()
.max("temperature","2017-04-19T00:00:00.000Z", "2017-04-22T00:00:00.000Z") >= 50;
Each object in the returned list has the next methods:
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 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 - it’s an ID of the endpoint’s tenant.
return ctx.tenantId === "tenant-id-1";
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.
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;
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;
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;
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:
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.
After that, we can see the rule creation window. Let’s name our 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.
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.
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.
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.
After that, when the device sends the data with a temperature over 50, we receive an email.