Logic Engine DSL Grammar

A rule is an asset (belongs to a context, is created by a user, has an access list, is audited) in WolkAbout IoT Platform and it is used to create a business logic as a set of conditions and actions. Once all rule conditions are satisfied, each action defined by the rule should be executed.

Logic Engine DSL is used to describe the rule’s conditions and actions. The DSL defines a total of four equally important parts:

  • Things - List of semantics, feeds, and actuators that will be used in the rule
  • Triggers - List of events that can occur on a ‘thing’ that can trigger the checking of conditions specified in the list of conditions. For now, only the UPDATE trigger can be used
  • Conditions - Conditions that must be satisfied for the rule to execute actions. If there are more conditions in the list, ALL must be satisfied
  • Actions - When ALL conditions (from the list of conditions) are satisfied, actions will be executed.

An example of the rule with things, triggers, conditions, and actions:

Things

Each thing is described by its name, its type, and, optionally, a set of descriptors.

Declaration
things:
Content
thing1name : feed [ propertyName = propertyValue, property2name = property2value]
thing2name : actuator [ property1name = thing1name.propertyName, property2name = thing1name]

An example of a thing definition:

In the previous example, a thing named “office” is defined and represents a semantic. It has exactly one descriptor - its semantic template is “Office”. If no descriptors are defined for a thing, the name descriptor is implicitly assigned (in the example, it would be [name=“office”]).

Name

A thing has a name by which it is referenced later in the rule. Name must start with a letter and can contain any combination of upper and lower case letters, numbers and underscores. Name cannot be the same as keyword.

Property

A thing can have one or more properties that will be used to uniquely identify it. If no property is defined for a thing then the name property is set to thing’s name.

PropertyValue can be numeric literal, string literal, or a reference to the property of another thing.

Descriptors

Descriptors are defined by property, matcher, and value:

  • Properties are defined based on thing type.
  • Matcher can be an exact matcher “=” or a partial matcher “starts with”.
  • Value is any numerical or textual value.

In case a thing type is a semantic, descriptors can be:

  • ID of the semantic.
  • Name of the semantic
  • ID of the parent. Alias: “parent”
  • Hierarchical path
  • Semantic template of the semantic

In case a thing type is a feed, descriptors can be:

  • Name of the feed
  • Value of the feed
  • ID of the parent. Alias: “parent”
  • Hierarchical path

In case a thing type is an actuator, descriptors can be:

  • Name of the actuator
  • Value of the actuator
  • ID of the parent. Alias: “parent”
  • Hierarchical path

Feed

Allowed properties:

  • name

Example of a rule with feed in things:

Example of a rule with multiple feeds in things:

Actuator

A thing that can be a target of actuation action.

Allowed properties:

  • name

Example of a rule with actuator in things:

Example of a rule with multiple actuators in things:

Semantic

Semantic things define additional descriptors based on their attributes represented as attribute name-value pairs. Attributes can also be defined as non-filtering so they can be referenced within actions. To define an attribute that does not filter semantics use an asterisk character in place of the value.

The linking of things is done in the following way:

  • When no semantic things are defined, all things are considered to belong to the same semantic (whichever one that might be).
  • When a single semantic thing is defined, all things are considered to belong to the defined semantic.
  • When multiple semantics are defined, each thing (except one semantic thing) must specify to which semantic they belong.

things: room: Semantic [template=‘Room’, color=‘blue’, size=*]

In the example above, a room is a semantic of type room that has an attribute “color” with a value “blue”, and has an attribute “size” with any value.

The value of the size attribute can be later referenced within actions as a “room.size” (if the attribute name contains spaces, they need to be replaced by an underscore).

Alternatively, the value of the attribute can be referenced in a placeholder (see actions chapter) as “${room.size}”.

Alarm

Example of a rule with alarm in things:

Example of a rule with multiple alarms in things:

Scope

Scope defines the boundaries of the rule. It defines them by providing the lowest possible semantic node in the hierarchy and restricts the rule evaluation for things in that branch of the semantic tree.

Only exact semantic matching is available. This means that exactly one semantic (and it’s elements) can be affected by the rule.

Declaration
scope:
Content

One or many strings separated by ‘/’.

An example of a scope definition:

Example of a rule whose scope matches the exact semantic and its elements:

Triggers

Triggers define what kind of an “event” can start rule evaluation.

Declaration
triggers:
Content

At least one definition of a trigger.

Trigger Events

Update events trigger ‘listens’ for events on specified things.

Supported events are: UPDATE, STATE NORMAL, STATE WARNING, and STATE ERROR.

Assuming the following things:

An appropriate trigger would be:

In the previous example, “trigger” is a keyword that defines the start of the trigger definition, “temperature” is a reference to the previously defined feed thing, and “UPDATE/STATE WARNING” is the type of event that the rule will listen for.

In the given example, any value update on any feed named “temperature” that belongs to any semantic of semantic template “Office” would start rule evaluation and potential execution of any actions defined by the rule.

Example of a rule that is triggered on updated value:

Example of a rule that is triggered on changed status:

Conditions

Conditions represent a logical expression that needs to be positively evaluated before a rule can execute its actions.

Logical expressions are always evaluated to be either “true” or “false”. The top-level expression MUST be a logical expression.

Value expressions are always evaluated to a specific value that can be compared with another value.

Expressions can be one of seven types:

  1. Value Mathematical expression
  2. Value String expression
  3. Logical Math expression
  4. Logical String expression
  5. Logical Not expression
  6. Logical Boolean expression

Basic value expression - Mathematical expression

Mathematical value expressions represent either a numeric value or a mathematical operation on one or more mathematical values.

Supported mathematical operations are:

  1. Addition: A+B
  2. Subtraction: A-B
  3. Multiplication: A*B
  4. Division: A/B
  5. To the power of: POW(A, B)
  6. Minimum: MIN(A, B, C…)
  7. Maximum: MAX(A, B, C…)
  8. Absolute: ABS(A), |A|
  9. Negative: -A
  10. Squared: SQUARE(A)

Assuming that this is the rule definition:

A few examples of mathematical values would be:

5
temp.value
temp.value + 5
(temp.value + temp2.value) / 2

Value expression - String expression

String value expressions represent textual values.

Assuming that this is the rule definition:

A few examples of string values would be:

“ON”
'OFF'
ac.value

Logical expression - Mathematical expression

Mathematical logical expressions represent a simple comparison between two mathematical value expressions.

Supported comparisons are:

  1. Equals: A==B
  2. Not Equals: A!=B
  3. Greater than: A>B
  4. Lesser than: A<B
  5. Greater or equal: A >= B
  6. Lesser or equal: A<=B

Assuming that this is the rule definition:

A few examples of mathematical comparisons would be:

bedroomTemperature.value > 30
bedroomTemperature.value > kitchenTemperature.value + 5
(bedroomTemperature.value + kitchenTemperature.value) / 2 > 30
|bedroomTemperature.value - kitchenTemperature.value| > 5

Logical expression - String expression

String logical expressions represent a simple validation between two string expressions.

Supported validations are:

  1. Equals: A==B
  2. Not Equals: A!=B
  3. Starts with: A starts with B
  4. Contains: A contains B

Assuming that this is the rule definition:

A few examples of string validation would be:

ac.value == 'OFF'
ac.value starts with 'O'
ac.name contains 'ac'

Logical expression - Boolean expression

Logical boolean expression is an amalgamation of any number of logical expressions connected by a logical operator.

Supported boolean operations are:

  1. AND: A and B, A && B
  2. OR: A or B, A || B
  3. XOR: A xor B, A ^ B

Assuming that this is the rule definition:

A few examples of logical expressions would be:

temperature.value > 25 and ac.value == 'OFF'
temperature.value <= 25 and ac.value == 'ON'
(temperature.value <= 10 or temperature.value >= 30) and ac.value == ‘OFF’

Logical expression - Not expression

Logical not expression reverses the evaluation result of any logical expression.

It is represented by a “!” symbol.

Example of a rule which uses value of feed state in the condition:

Rule

Inside the DSL editor, you will also come across a rule definition, which is identical to defining conditions and actions separately.

Declaration
rule:

or

condition:
actions:
Content

Zero or one definition of conditions followed by one or more actions

action
{ action1; action2 }
{ action1
  action2 }
if condition then action
if condition -> action
Condition
Numeric comparison

Comparison between variables, numeric values or expressions which yield numeric value:

value1 > value2
value1 < value2
value1 >= value2
value1 <= value2
value1 == value2
value1 != value2

Value can be a numeric literal, numeric expression, or variable.

A few examples:

temperature > 30
temperature.value < 25
abs(temp - temp2) >= 5
temp * 0.2 == 4
String comparison

Comparison between variables or string values

value1 == value2
value1 != value2
value1 contains value2
value1 starts with value2

Value is either a string literal or variable.

Example:

message == “test”
alarm1.value != alarm2.value
alarm contains “ERROR”
text starts with “Hello”
Logical expression

All comparison conditions evaluate to boolean value i.e. true or false, which can then be used in logical expressions. Expressions can be grouped using parentheses:

not condition
!condition
condition1 and condition2
condition1 && condition2
condition1 or condition2
condition1 || condition2
condition1 xor condition2
condition1 ^ condition2
condition1 and (condition2 or condition3)

Example:

not temperature > 30
temperature > 25 and AC == “OFF”
temperature > 25 and (AC == “OFF” or between 07:00 and 17:00)

Actions

Once a rule has been satisfied, all of its actions will be executed.

Actions are defined within the “Actions” part of the DSL, after the conditions.

Logic engine supports seven action types:

  1. Actuate
  2. Set state
  3. Generate message
  4. Send email
  5. Send push notification

Most actions require string parameters to work correctly.

String parameters also support value placeholders in the form of ${thing.property}.

High temperature in ${room.name}.
Flood detected at ${house.name}.

In the examples given above, “room” and “house” are semantic things.

A special placeholder “${currentTime}” exists, which will be replaced by the current time during action execution.

Time placeholders support optional formatting with timezone (defined by | sign):

| date-time-format | timezone

Examples:

'High temperature in ${room.name} at ${currentTime}.'
'High temperature in ${room.name} at ${currentTime|HH:mm}.'
'High temperature in ${room.name} at ${currentTime|HH:mm|GMT+2}.'
'Flood detected by ${sensor.name} at ${sensor.lastUpdate|HH:mm:ss|UTC}.'

Action - Actuate

Actuate action will attempt to actuate an actuator with the given value.

It requires a reference to an actuator thing and a new value.

Valid statements are:

thing = "newValue"
thing.value = "newValue"
SET thing to "newValue"
SET thing.value to "newValue"

Examples of rules that contain an actuate action:

Action - Set State

Set state action will change the state of a feed thing.

Set state action requires a reference to a feed thing, a new state, and a message.

Available states (case-sensitive) are NORMAL, WARNING, and ERROR.

Valid statements are:

thing.state = NEW_STATE message "newMessage"
SET thing to NEW_STATE message "newMessage"
SET thing.state to NEW_STATE message "newMessage"
SET thing.state to SELECTOR [
    STATE-1 WHEN logicalExpression1
    STATE-2 WHEN logicalExpression2
    …
    STATE-n WHEN logicalExpressionN
    STATE-default DEFAULT
]

Examples of rules that contain a “set state” action:

Action - Generate Message

Generate message action will create a new message based on the provided parameters.

It requires three parameters: message type, message body, and a list of recipients.

Message types (case-sensitive) are INFO, WARNING, ALARM.

Valid statements are:

send message TYPE "messageBody" to user "userEmail"
send message TYPE "messageBody" to users "userEmail1", "userEmail2"...
send message TYPE "messageBody" to group "userGroup"
send message TYPE "messageBody" to groups "userGroup1", "userGroup2"...
send message TYPE thing: "messageBody" to user "userEmail"

Example of a rule that contains a “generate message” action:

Action - Send Email

Send email will send a new email based on the provided parameters.

It requires three parameters: title, body, and a list of recipients.

Valid statements are:

send email "title", "emailBody" to user "userEmail"
send email "title", "emailBody" to users "userEmail1", "userEmail2"...
send email "title", "emailBody" to group "userGroup"
send email "title", "emailBody" to groups "userGroup1", "userGroup2"...

Examples of rules that contain a “send email” action:

Action - Send Push Notification

Send push notification action will attempt to send a push notification to Android and/or iOS devices.

It requires three parameters: title, body, and a list of recipients.

Valid statements are:

send notification "title" "emailBody" to user "userEmail"
send notification "title" "emailBody" to users "userEmail1", "userEmail2"...
send notification "title" "emailBody" to group "userGroup"
send notification "title" "emailBody" to groups "userGroup1", "userGroup2"...

Example of a rule that contains a “send push notification” action:

Types

String literal

String literal is any text surrounded by “double” or ‘single’ quotes.

Example:

“Some text” - Some text
‘Some other text’ - Some other text
“Some text containing ‘quotes’” - Some text containing ‘quotes’
‘Some other text containing “quotes”’ - Some other text containing “quotes”

Numeric literal

Example:

15
7.23
-0.06

Numeric expression

value
value1 + value2
value1 - value2
value1 * value2
value1 / value2
-value
abs(value)
|value|
square(value)
pow(value1, value2)
min(value1, value2)
max(value1, value2)

Value is a numeric literal, numeric expression or variable.

Example:

15 + 45.3
15 - 45.3
15 * 45.3
15 / 45.3
-temp
abs(temp)
square(temp)
pow(temp, 3)
min(temp, 25)
max(temp, 25)

Variable

Value of another thing’s property. The thing must be defined in things section.

thingName.propertyName
thingName

If property name is not specified then the ‘value’ property is used.

Example:

ac.value - Accesses the value property of thing ac
office.name - Accesses the name property of thing office
temperature - Accesses the value property of thing temperature

Keywords

Keywords are reserved for use and cannot be used for naming things. Keywords can be used normally in strings.

Case-Insensitive keywords

things, scope, triggers, rule, condition, actions, title, body, user, users, group, groups, actuator, feed, and, or, xor, not, contains, starts with, abs, pow, square, root, sqrt, min, max, if, then, else, set, send, to, on, message, email, notification

Case-Sensitive keywords

UPDATE, ERROR, WARNING, NORMAL, INFO, ALARM, OFF

Example:

things:
   JD_Building: semantic
   temperature: feed
   ac: actuator
scope:
   JD_Building.Offices
trigger:
   temperature UPDATE
rule:
   if temperature > 25 and ac == 'OFF' -> ac = 'ON'