Previous
Export data
You can use triggers to send email notifications or webhook requests when data from the machine is synced, even captured from a specific component with a specified condition. For example, you can configure a trigger to send you a notification when your robot’s sensor collects a new reading.
Follow this guide to learn how to configure a trigger to send webhook requests or emails for the following events:
To configure a trigger:
Go to the CONFIGURE tab of your machine on the Viam app. Click the + (Create) button in the left side menu and select Trigger.
Name the trigger and click Create.
Select trigger Type. Configure additional attributes:
Select the data types for which the trigger should send requests.
Whenever data of the specified data types is ingested, a POST
request will be sent.
Select the component you want to capture data from and the method you want to capture data from. Then, add any conditions.
These can include a key, a value, and a logical operator.
For example, a trigger configured to fire when data is captured from the motor motor-1
’s IsPowered
method when is_on
is equal to True
:
For more information, see Conditions.
You must configure data capture for your component to use this trigger.
Click Add Webhook. Add the URL of your cloud function or lambda. Configure the time between notifications.
Click Add Email. Add the email you wish to be notified whenever this trigger is triggered. Configure the time between notifications.
To configure your trigger by using JSON mode instead of Builder mode, paste one of the following JSON templates into your JSON config.
"triggers"
is a top-level section, similar to "components"
or "services"
.
"triggers": [
{
"name": "<trigger name>",
"event": {
"type": "part_data_ingested",
"data_ingested": {
"data_types": ["binary", "tabular", "file"]
}
},
"notifications": [
{
"type": "webhook",
"value": "https://1abcde2ab3cd4efg5abcdefgh10zyxwv.lambda-url.us-east-1.on.aws",
"seconds_between_notifications": <number of seconds>
}
]
}
]
"triggers": [
{
"name": "<trigger name>",
"event": {
"type": "conditional_data_ingested",
"conditional": {
"data_capture_method": "<component>:<name-of-component>:<method>",
"condition": {
"evals": [
{
"operator": "<lt|gt|lte|gte|eq|neq>",
"value": <object, string, or int>
}
]
}
}
},
"notifications": [
{
"type": "email",
"value": "<fill-in-email-here>",
"seconds_between_notifications": <number of seconds>
}
]
}
]
{
"components": [
{
"name": "local",
"model": "pi",
"type": "board",
"namespace": "rdk",
"attributes": {},
"depends_on": []
},
{
"name": "my_temp_sensor",
"model": "bme280",
"type": "sensor",
"namespace": "rdk",
"attributes": {},
"depends_on": [],
"service_configs": [
{
"type": "data_manager",
"attributes": {
"capture_methods": [
{
"method": "Readings",
"additional_params": {},
"capture_frequency_hz": 0.017
}
]
}
}
]
}
],
"triggers": [
{
"name": "trigger-1",
"event": {
"type": "part_data_ingested",
"data_ingested": {
"data_types": ["binary", "tabular", "file"]
}
},
"notifications": [
{
"type": "webhook",
"value": "<https://1abcde2ab3cd4efg5abcdefgh10zyxwv.lambda-url.us-east-1.on.aws>",
"seconds_between_notifications": 0
}
]
}
]
}
The following attributes are available for triggers:
Name | Type | Required? | Description |
---|---|---|---|
name | string | Required | The name of the trigger |
event | object | Required | The trigger event object:
|
notifications | object | Required | The notifications object:
|
The conditional
object for the conditional_data_ingested
trigger includes the following options:
Name | Type | Required? | Description |
---|---|---|---|
data_capture_method | string | Required | The method of data capture to trigger on. Example: sensor:<name-of-component>:Readings . |
condition | object | Optional | Any additional conditions for the method to fire the trigger. Leave out this object for the trigger to fire any time there is data synced. Options:
|
Options for operator
:
Name | Description |
---|---|
lt | Less than |
gt | Greater than |
lte | Less than or equal to |
gte | Greater than or equal to |
eq | Equals |
neq | Does not equal |
Examples:
"condition": {
"evals": [
{
"operator": "lt",
"value": {
"Line-Neutral AC RMS Voltage": 130
}
}
]
}
This eval would trigger for the following sensor reading:
{
"readings": {
"Line-Neutral AC RMS Voltage": 100
}
}
"condition": {
"evals": [
{
"operator": "lt",
"value": {
"coordinate": {
"latitude": 50
}
}
}
]
}
This eval would trigger for the following sensor reading:
{
"readings": {
"coordinate": {
"latitude": 40
}
}
}
viam-server
.
You can use your cloud function or lambda to interact with any external API such as, for example, Twilio, PagerDuty, or Zapier.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)
When an event occurs, Viam sends a HTTP request to the URL you specified for the trigger:
Trigger type | HTTP Method |
---|---|
part_data_ingested | POST |
conditional_data_ingested | POST |
part_online | GET |
part_offline | GET |
The request includes the following headers:
Header Key | Description | Trigger types |
---|---|---|
Org-Id | The ID of the organization that triggered the request. | all |
Organization-Name | The name of the organization that triggered the request. | part_online , part_offline |
Location-Id | The location of the machine that triggered the request. | all |
Location-Name | The location of the machine that triggered the request. | part_online , part_offline |
Part-Id | The part of the machine that triggered the request. | all |
Machine-Name | The name of the machine that triggered the request. | part_online , part_offline |
Robot-Id | The ID of the machine that triggered the request. | all |
The request body includes the following data:
Data Key | Description | Trigger types |
---|---|---|
component_name | The name of the component for which data was ingested. | part_data_ingested , conditional_data_ingested |
component_type | The type of component for which data was ingested. | part_data_ingested , conditional_data_ingested |
method_name | The name of the method from which data was ingested. | part_data_ingested , conditional_data_ingested |
min_time_received | Indicates the earliest time a piece of data was received. | part_data_ingested |
max_time_received | Indicates the latest time a piece of data was received. | part_data_ingested |
method_name | The name of the method that triggered the request. | conditional_data_ingested |
machine_name | The name of the machine that triggered the request. | part_data_ingested , conditional_data_ingested |
location_name | The location of the machine that triggered the request. | part_data_ingested , conditional_data_ingested |
org_name | The name of the organization that triggered the request. | part_data_ingested , conditional_data_ingested |
file_id | The id of the file that was ingested. | part_data_ingested |
trigger_condition | The condition that triggered the request. | conditional_data_ingested |
data | The 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) |
Was this page helpful?
Glad to hear it! If you have any other feedback please let us know:
We're sorry about that. To help us improve, please tell us what we can do better:
Thank you!