Analytics system uses expressions everywhere — in intervals selectors, in interval counters, and even in message and interval validators. Expression operates with a message and the result of an expression is a number.

In the case of boolean-type expressions (e.g. validation or interval test expressions), non-zero resulting value means the expression is valid. An expression consists of numbers, operators, parameters references, and functions. If an expression contains a reference to a parameter that is not present in the message or division by zero, its result is undefined or OFF in most boolean expressions.

For example, we sequentially analyze the following messages from devices:

{

"device.name": "123456789012345",

"timestamp": 1490347944.893743,

"din": 9,

"channel_id": 123,

"altitude": 568.49,

"direction": 297,

"hdop": 0.9,

"speed": 10,

"lat": -21.328481,

"lng": 47.562136,

"accelerations": [1, 2, 3.3, 0],

...

}

In an expression, all references to message parameters that contain a number or a boolean value will equal to this value. All references to message parameters that contain textual value will equal to a 32-bit hash of the text. All references to other types of parameters (e.g. array or binary) will equal **1** if this parameter is defined for the message. For example expression **"channel_id + accelerations"** will equal 124.

For textual parameters that will put a 32-bit hash of their actual value, you can use compartments operators like '==' or '!=', for example: **"device.name == '123456789012345'"** to check actual value. Currently, there are no possibilities to compare the textual value with a wildcard mask, only direct value checks can be used.

If you need to access JSON objects or arrays, it is possible to use functions **json('object-key', 'subkey-name')** or **json('array-key', 0)**. See examples and explanations in the table below.

To reference the value of the same parameter in the previous message, you need to prepend hash (#) to the parameter name. For example, you can use **"speed - #speed"** to calculate the speed change from message to message.

** Important note on using references to previous message parameters:** as the system does not know the value of the previous parameter for the very first message, it means that the very first message in such reference will always return unknown or OFF value. In order to correctly and consistently calculate intervals we recommend to use

**merge_message_before=true**in selector configuration which expression using reference to previous message parameters.

Another form of parameters specification is by preceding them with a dollar sign ($). In that case, if the parameter is not present in the message, zero value will be put instead. For example **"abs($speed)>=0"** will be always valid and non-zero.

You can use mathematical operators in expression and add brackets to control the order of operations. The priority of operations is the same as in the C programming language and, moreover, all operation notation is also very similar to what C language defines. You can use the following operators:

operator | explanation |

+ | sum |

- | diff |

/ | divide |

* | multiply |

| | binary OR |

& | binary AND |

&& | logical AND |

|| | logical OR |

^ | binary XOR |

== | equal |

!= | not equal |

< | less |

<= | less or equal |

> | greater |

>= | greater or equal |

If you need more operators, please contact us.

Here are some sample expressions and their resulting values:

expression | evaluation |

1 + 2 * 4 / 2 | 5 |

(1 + 2) * 4 / 2 | 6 |

(4 & 1) > 0 | 0, cause 4 AND(binary) 1 is 0 |

(4 && 1) > 0 | 1, cause 4 AND(logical) 1 is 1 |

It is also possible to use some functions inside expressions, for example, **"abs(speed-#speed)>10"** will always equal 1 if the instant speed value change between two sequential messages is different by more than 10 km/h in any direction. Here is the full list of functions:

function | explanation |

abs(X) | an absolute value of X |

round(X) | round X to the closest integer |

ceil(X) | round X up to the largest integer |

floor(X) | round X down to the smallest integer |

min(X, Y) | return a minimum value between X and Y |

max(X, Y) | return a maximum value between X and Y |

if(X, Y, Z) | if X is non-zero, evaluate to Y otherwise evaluate to Z |

mileage() | mileage in kilometers from the previous message, calculated using position.latitude, position.longitude and position.altitude parameters |

month(X) | month value for X with ranges 1-12, where X is UNIX timestamp, e.g. month(timestamp) will return month number for the current message |

day(X) | day of month value for X with ranges 1-31, where X is UNIX timestamp |

hour(X) | hour for X with ranges 0-23, where X is UNIX timestamp |

minute(X) | minute value for X with ranges 0-59, where X is UNIX timestamp |

json('X', Y) | fetch the value from sub-element inside a JSON object or array. Sample: {"x":{"y":1, "z":2}, "a":[3, 5]} To fetch value under key "y" inside object under key "x" use json('x', 'y') or json('x', 0) for index-based access to keys (indices start from zero). Same applies to arrays: json('a', 0) will return 3. |

If you need more functions, please contact us.