Trigger configuration

Triggers can alert you by email or webhook when the following events occur:

Trigger attributes

Triggers support the following attributes:

NameTypeRequired?Description
namestringRequiredThe name of the trigger
eventobjectRequiredThe trigger event object, which contains the following fields:
  • type: The type of the event to trigger on. Options: part_data_ingested, conditional_data_ingested.
  • data_types: Required with type part_data_ingested. An array of data types that trigger the event. Options: binary, tabular, file, unspecified.
  • conditional: Required when type is conditional_data_ingested. For more information about this field, see Conditional attributes.
notificationsobjectRequiredThe notifications object, which contains the following fields:
  • type: The type of the notification. Options: webhook, email
  • value: The URL to send the request to or the email address to notify.
  • seconds_between_notifications: The interval between notifications in seconds.
For more information on webhooks, see Webhook attributes.

Data sync trigger template

The following template demonstrates the form of a JSON configuration for a trigger that alerts when data syncs to the Viam cloud:

  "triggers": [
    {
      "name": "<trigger name>",
      "event": {
        "type": "part_data_ingested",
        "data_ingested": {
          "data_types": ["binary", "tabular", "file", "unspecified"]
        }
      },
      "notifications": [
        {
          "type": "<webhook|email>",
          "value": "<webhook URL or email address>",
          "seconds_between_notifications": <number of seconds>
        }
      ]
    }
  ]

Conditional attributes

The conditional object for the conditional_data_ingested trigger type includes the following attributes:

NameTypeRequired?Description
data_capture_methodstringRequiredThe method of data capture to trigger on.
Example: sensor:<name-of-component>:Readings.
conditionsobjectOptionalConditions that, when true, fire the trigger. Evaluated each time data syncs from the linked component. When this object is empty or not present, the trigger fires each time data syncs from the linked component.
Options:
  • evals:
    • operator: Logical operator for the condition.
    • value: An object containing a single field and value. The field specifies the path, in the synced data, to the left operand of the conditional. For nested fields, use periods as separators or define the nested structure in JSON. The value specifies an object, string, boolean, regular expression, or integer used as a right operand in the conditional.

The operator attribute supports the following values:

NameDescription
ltless than
gtgreater than
lteless than or equal to
gtegreater than or equal to
eqequal to
neqnot equal to
regexmatches regular expression

Conditional trigger template

The following template demonstrates the form of a JSON configuration for a conditional trigger:

"triggers": [
    {
      "name": "<trigger name>",
      "event": {
        "type": "conditional_data_ingested",
        "conditional": {
          "data_capture_method": "<component>:<name-of-component>:<method>",
          "conditions": {
            "evals": [
              {
                "operator": "<lt|gt|lte|gte|eq|neq|regex>",
                "value": <object, string, bool, regex, or int>
              }
            ]
          }
        }
      },
      "notifications": [
        {
          "type": "<webhook|email>",
          "value": "<webhook URL or email address>",
          "seconds_between_notifications": <number of seconds>
        }
      ]
    }
]

Example

The following condition defines a trigger that fires based on the value of the cpu field of synced data:

"conditions": {
  "evals": [
    {
      "operator": "gt",
      "value": {
        "cpu": 50
      }
    }
  ]
}

The following sensor reading fires the trigger, since 80 > 50 is true:

{
  "readings": {
    "cpu": 80
  }
}

Nested key example

The following condition defines a trigger that fires based on a value nested in the coordinate.latitude field of synced data:

"conditions": {
  "evals": [
    {
      "operator": "lt",
      "value": {
        "coordinate": {
          "latitude": 50
        }
      }
    }
  ]
}

The following sensor reading fires the trigger, since 40 < 50 is true:

{
  "readings": {
    "coordinate": {
      "latitude": 40
    }
  }
}

Webhook attributes

Request types

When an event occurs, Viam sends a HTTP request to the URL you specified for the trigger:

Trigger typeHTTP Method
part_data_ingestedPOST
conditional_data_ingestedPOST
part_onlineGET
part_offlineGET

Headers

The request includes the following headers:

Header KeyDescriptionTrigger types
Org-IdThe ID of the organization that triggered the request.all
Organization-NameThe name of the organization that triggered the request.part_online, part_offline
Location-IdThe location of the machine that triggered the request.all
Location-NameThe location of the machine that triggered the request.part_online, part_offline
Part-IdThe part of the machine that triggered the request.all
Machine-NameThe name of the machine that triggered the request.part_online, part_offline
Robot-IdThe ID of the machine that triggered the request.all

Body

The request body includes the following data:

Data KeyDescriptionTrigger types
component_nameThe name of the component for which data was ingested.part_data_ingested, conditional_data_ingested
component_typeThe type of component for which data was ingested.part_data_ingested, conditional_data_ingested
method_nameThe name of the method from which data was ingested.part_data_ingested, conditional_data_ingested
min_time_receivedIndicates the earliest time a piece of data was received.part_data_ingested
max_time_receivedIndicates the latest time a piece of data was received.part_data_ingested
method_nameThe name of the method that triggered the request.conditional_data_ingested
machine_nameThe name of the machine that triggered the request.part_data_ingested, conditional_data_ingested
location_nameThe location of the machine that triggered the request.part_data_ingested, conditional_data_ingested
org_nameThe name of the organization that triggered the request.part_data_ingested, conditional_data_ingested
file_idThe id of the file that was ingested.part_data_ingested
trigger_conditionThe condition that triggered the request.conditional_data_ingested
dataThe ingested sensor data. Includes metadata with received_at and requested_at timestamps and data in the form map[string]any.part_data_ingested, conditional_data_ingested (sensor data)

Example cloud function

If you are using a cloud function or lambda to process the request from viam-server, you can use this template.

The following example function prints the received headers:

from flask import Flask, request

app = Flask(__name__)


@app.route("/", methods=['GET', 'POST'])
def trigger():
    headers = request.headers
    data = {}
    if request.data:
        data = request.json
    payload = {
        "Org-Id": headers.get('org-id', 'no value'),
        "Organization-Name": headers.get('organization-name', '') or
        data.get('org_name', 'no value'),
        "Location-Id": headers.get('location-id', 'no value'),
        "Location-Name": headers.get('location-name', '') or
        data.get('location_name', 'no value'),
        "Part-Id": headers.get('part-id', 'no value'),
        "Part-Name": headers.get('part-name', 'no value'),
        "Robot-Id": headers.get('robot-id', 'no value'),
        "Machine-Name": headers.get('machine-name', '') or
        data.get('machine_name', 'no value'),
        "Component-Type": data.get('component_type', 'no value'),
        "Component-Name": data.get('component_name', 'no value'),
        "Method-Name": data.get('method_name', 'no value'),
        "Min-Time-Received": data.get('min_time_received', 'no value'),
        "Max-Time-Received": data.get('max_time_received', 'no value'),
        "Data-Type": data.get('data_type', 'no value'),
        "File-Id": data.get('file_id', 'no value'),
        "Trigger-Condition": data.get("trigger_condition", 'no value'),
        "Data": data.get('data', 'no value')
    }
    print(payload)

    return payload


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)
import functions_framework
import requests
import time


@functions_framework.http
def hello_http(request):
    headers = request.headers
    data = {}
    if request.data:
        data = request.json
    payload = {
        "Org-Id": headers.get("org-id", "no value"),
        "Organization-Name": headers.get("organization-name", "")
        or data.get("org_name", "no value"),
        "Location-Id": headers.get("location-id", "no value"),
        "Location-Name": headers.get("location-name", "")
        or data.get("location_name", "no value"),
        "Part-Id": headers.get("part-id", "no value"),
        "Part-Name": headers.get("part-name", "no value"),
        "Robot-Id": headers.get("robot-id", "no value"),
        "Machine-Name": headers.get("machine-name", "")
        or data.get("machine_name", "no value"),
        "Component-Type": data.get("component_type", "no value"),
        "Component-Name": data.get("component_name", "no value"),
        "Method-Name": data.get("method_name", "no value"),
        "Min-Time-Received": data.get("min_time_received", "no value"),
        "Max-Time-Received": data.get("max_time_received", "no value"),
        "Data-Type": data.get("data_type", "no value"),
        "File-Id": data.get('file_id', "no value"),
        "Trigger-Condition": data.get("trigger_condition", "no value"),
        "Data": data.get('data', "no value")
    }
    print(payload)

    return 'Received headers: {}'.format(payload)