Using time in Calculated Properties

CPs can work with timestamps as well as values, and even see the previous event in a stream


CPs can access the previous state of any property, and even the time when that state changed, using the $previous keyword.

For example, if we’re ingesting data into DevicePilot via a connection-oriented protocol such as MQTT then instead of heartbeats we’ll receive a simple "connected" property which flips between true each time the connection starts and false each time it stops. We can use $previous to detect the moment that the connection starts:


connected == true && $previous/connected == false

Converting state ←→ events

We can think of the above CP as turning a state property into an event property and now we can COUNT became_connected in a KPI to measure how many sessions started e.g. in a day.

We can also go the other way and turn event properties into state properties. Say our device emits two event properties: cashbox_opened and cashbox_closed (it doesn’t matter what value it sets these properties to, each event is defined as just sending the property with some value). We can define a CP thus:


$ts/cashbox_opened > $ts/cashbox_closed

The cashbox is open if it was opened more recently than it was closed. Now in a KPI we can measure e.g. percentage_of_time_where cashbox_is_open.

Calculated Properties (1)

Merging events

In a similar vein, you can use CP’s to merge event streams. If your device reports a variety of device errors on different properties, you can merge them into a single property for counting or other statistics:


tamper_detect || battery_low || sensor_fail

Note that here we don’t care what the value of the CP expression is, we’re just using the fact that it’ll get evaluated whenever any of its inputs changes to merge the event streams.

Measuring durations

By accessing the previous timestamp, we can report statistics such as:


connected == true && $previous/connected == false ?
$ts/connected - $previous/$ts/connected : undefined

In English this says "if we’re currently connected and were previously unconnected, then report the elapsed time since we became connected. Otherwise report nothing".

ASIDE: To better understand the difference between "null" and "undefined" values, see here.

Measuring machine-hours 

Many machines have an in-built "hours of operation" odometer. Even if we don't have remote access to this, we can still calculate it from any reported property from which operation can be inferred - for example when a fryer is up to operating temperature:


((fryer_temp > 300) && ($previous/fryer_temp > 300)) ? (($ts/fryer_temp - $previous/$ts/fryer_temp) / (1000 * 60 * 60)) : 0

This can then be summed in a KPI to provide total operating machine-hours per month, or per location etc.

Splitting time into components

You can use the following functions to get the components of a timestamp:

  • getSecond                           - gets the number of seconds: 0 - 59
  • getMinute                           - gets the number of minutes: 0 - 59
  • getHour                               -  gets the hour in day: 0 - 23
  • getDay                                 -  gets day in the year: 0 - 366
  • getWeek                              -  gets ISO week: 0 - 53
  • getMonth                            -  gets month: 0 - 11 - Months start at zero, so January is month 0.
  • getYear                                -  gets year: 2019
  • getDayOfWeek                  -  gets day in week: 0 = Sunday, 6 = Saturday
  • getDayOfMonth               -  gets day in the month: 1 - 31

They are used like this (to create a basic business hours filter of 9am-6pm, Mon-Fri):

getHour($ts) >= 9 && getHour($ts) < 18 && getDayOfWeek($ts) > 0 && getDayOfWeek($ts) < 6

These functions all work in UTC. If you want to work in a different timezone, you can use versions with suffixed with Tz, for example getHourTz, and pass the timezone string, from the IANA time zone database.

For a Greek customer, they would specify:

getHourTz($ts, "Europe/Athens") >= 9 && getHour($ts, "Europe/Athens") < 18 && 
getDayOfWeek($ts, "Europe/Athens") > 0 && getDayOfWeek($ts, "Europe/Athens") < 6



Learn more about Calculated Properties