Skip to content

Functions' definitions

In order to support the creation of sensors, triggers, charts or reports, Layrz provides a standardized structure to invoke the functions, and the return will change according to the function invoked.

Disclaimer!

Our systems only watch for a single function, the name depends on the implementation, but you cannot define another function outside of that. If you need to declare other functions implement them inside of the main function!

DON'T do this:

python
def square(a: float): # Function defined outside of the main function
    return a * a

def calculate(asset, message, previous_message):
  """ Return the current squared speed of the asset """
  return square(message.position.speed) or 0

Do this instead:

python
def calculate(asset, message, previous_message):
  """ Return the current squared speed of the asset """
  def square(a: float): # Function defined inside the main function
    return a * a
  return square(message.position.speed) or 0

Let's dive into the structure of the functions.

For basic sensors

Python in sensors is very straightforward, you just need to create a function called calculate with three arguments:

ArgumentTypeDescription
assetAssetThe asset that the sensor is attached to
messageMessageThe data that the sensor will use to calculate the value
previous_messageMessageThe previous message that the sensor used to calculate the value

The return of the function can be anything you want to, feel free to return a str, a int, a float, a list, a dict, or any other type of data.

Let's look an example:

Disclaimer

This example is equivalent to this LCL formula:

lcl
GET_PARAM(
  CONCAT(
    PRIMARY_DEVICE(),
    ".position.speed"
  ),
  CONSTANT(0)
)
python
def calculate(asset, message, previous_message):
  """ Return the current speed of the asset """
  return message.position.speed or 0

Be careful!

previous_message can be None if the sensor is being executed for the first time, so you need to check if it's None before using it.

For dynamic sensors

What is a dynamic sensor? Well, in some cases, you need to filter or standardize the value using median or average, or maybe you need to predict some things using statistical models. In those cases, you need to use a dynamic sensor.

Different from the basic sensor, the dynamic sensor, the function name is calculate_dynamic with two arguments:

ArgumentTypeDescription
assetAssetThe asset that the sensor is attached to
messageslist[Message]The last 20 messages to analyze, sorted by received_at ascending

Note

This 20 messages depends of the configuration of the sensor and the messages available in the system. By default we only scan for the last hour to get the last 20 messages, but you can change this search time up to 6 hours.

The return of the function can be anything you want to, feel free to return a str, a int, a float, a list, a dict, or any other type of data.

Let's look an example:

python
def calculate_dynamic(asset, messages):
  return sum([message.position.speed for message in messages]) / len(messages)

For triggers

For Triggers, is similar to a basic sensor, but you need to create a function called validate with three arguments:

ArgumentTypeDescription
assetAssetThe asset that the sensor is attached to
messageMessageThe data that the sensor will use to calculate the value
previous_messageMessageThe previous message that the sensor used to calculate the value

The return of the function must be a bool, True if the trigger is activated, False if not.

Let's look an example:

python
def validate(asset, message, previous_message):
  """ Return True if the speed is greater than 100 """
  return message.position.speed > 100

Be careful!

If the return is not a bool, the trigger will not work in any scenario.

For fixed execution triggers

For fixed execution Triggers, instead you need to create a function called validate_fixed with only one argument:

ArgumentTypeDescription
last_messagesList[LastMessage]The last messages that the sensor used to calculate the value

The return of the function must be a list of IDs (List[int]) of the assets that were positive.

Let's look an example:

python
def validate_fixed(last_messages):
  # Do a positive only for assets that engine.ignition.status is true
  
  positives = []
  for message in last_messages:
    if message.sensors is None:
      continue
    
    if message.sensors.get('engine.ignition.status', False):
      positives.append(message.asset_id)
      
  return positives

For charts

Charts are a little bit different, the function name is calculate_series with two common arguments:

ArgumentTypeDescription
assetslist[Asset]The list of assets submitted in the render request
configurationChartConfigurationThe configuration of the chart

And, also, depending of the chart data source, whe third argument will change:

Data SourceArgumentType
For messages as a sourcemessageslist[Message]
For events as a sourceeventslist[Event]
For cases as a sourcecaseslist[Case]
For checkpoints as a sourcecheckpointslist[Checkpoint]

The return statement must be the chart type:

Chart TypeClass
LineLineChart
ColumnColumnChart
AreaAreaChart
RadialBarRadialBarChart
PiePieChart
BarBarChart
RadarRadarChart
ScatterScatterChart
TimelineTimelineChart
HTMLHTMLChart
MapMapChart
TableTableChart
NumberNumberChart

Let's look an example of each data source returning a LineChart:

For messages as a source

python
def calculate_series(assets, configuration, messages):
  return LineChart(
    title='Example chart',
    x_axis=[],
    y_axis=[]
  )

For events as a source

python
def calculate_series(assets, configuration, events):
  return LineChart(
    title='Example chart',
    x_axis=[],
    y_axis=[]
  )

For cases as a source

python
def calculate_series(assets, configuration, cases):
  return LineChart(
    title='Example chart',
    x_axis=[],
    y_axis=[]
  )

For checkpoints as a source

python
def calculate_series(assets, configuration, checkpoints):
  return LineChart(
    title='Example chart',
    x_axis=[],
    y_axis=[]
  )

Be careful!

This examples are just to show the structure of the function, checkout the definition of each chart type to understand how to use it.

Checkout our examples!

We have a lot of examples of charts in our Python examples

For reports

For reports, is similar to the chart function, the main difference is the function name, that is process_report with two common arguments:

ArgumentTypeDescription
assetslist[Asset]The list of assets submitted in the render request
configurationReportConfigurationThe configuration of the report

And, also, depending of the report data source, whe third argument will change:

Data SourceArgumentType
For messages as a sourcemessageslist[Message]
For events as a sourceeventslist[Event]
For cases as a sourcecaseslist[Case]
For checkpoints as a sourcecheckpointslist[Checkpoint]
For broadcasts' results as a sourcebroadcastslist[BroadcastResult]

The return statement must be the ReportPage class, this class will be appended to the report.

Let's look an example of each data source returning a ReportPage:

For messages as a source

python
def process_report(assets, configuration, messages):
  return ReportPage(
    name='Example page',
    headers=[],
    rows=[],
    freeze_header=False
  )

For events as a source

python
def process_report(assets, configuration, events):
  return ReportPage(
    name='Example page',
    headers=[],
    rows=[],
    freeze_header=False
  )

For cases as a source

python
def process_report(assets, configuration, cases):
  return ReportPage(
    name='Example page',
    headers=[],
    rows=[],
    freeze_header=False
  )

For checkpoints as a source

python
def process_report(assets, configuration, checkpoints):
  return ReportPage(
    name='Example page',
    headers=[],
    rows=[],
    freeze_header=False
  )

For broadcasts' results as a source

python
def process_report(assets, configuration, broadcasts):
  return ReportPage(
    name='Example page',
    headers=[],
    rows=[],
    freeze_header=False
  )

Be careful!

This examples are just to show the structure of the function, checkout the definition of the report class to understand how to use it.

Checkout our examples!

We have a lot of examples of charts in our Python examples