diff --git a/docs/dev/tools/how-tos/_index.md b/docs/dev/tools/how-tos/_index.md deleted file mode 100644 index 91d523e83d..0000000000 --- a/docs/dev/tools/how-tos/_index.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: "How-to Guides" -linkTitle: "How-to Guides" -weight: 20 -type: "docs" -images: ["/registry/module-puzzle-piece.svg"] -description: "Follow instructions for common tasks and workflows." -no_list: true -notoc: true -hide_children: true -sitemap: - priority: 1.0 -aliases: - - /use-cases/ -date: "2024-09-17" -howtojs: true -# updated: "" # When the content was last entirely checked ---- - -
-

-The guides on this page provide solutions for common tasks and workflows. Browse the guides on this page or filter by product area: -

- -
- -
-
-
-
- -
- -
- -{{< how-to-expand title="Get started with Viam basics" tasks="5" level="BEGINNER-FRIENDLY" >}} -{{< cards >}} -{{% card link="/how-tos/drive-rover/" noimage="true" %}} -{{% card link="/how-tos/control-motor/" noimage="true" %}} -{{% card link="/how-tos/detect-people/" noimage="true" %}} -{{% card link="/how-tos/collect-data/" noimage="true" %}} -{{% card link="/how-tos/move-robot-arm/" noimage="true" %}} -{{< /cards >}} -{{< /how-to-expand >}} - -{{< how-to-expand "Configure a fleet, starting with one machine" "4" "BEGINNER-FRIENDLY" >}} -{{< cards >}} -{{% card link="/how-tos/configure/" noimage="true" %}} -{{% card link="/how-tos/one-to-many/" noimage="true" %}} -{{% card link="/how-tos/provision-setup/" noimage="true" %}} -{{% card link="/how-tos/provision/" noimage="true" %}} -{{< /cards >}} -{{< /how-to-expand >}} - -{{< how-to-expand "Work with sensor data" "4" "INTERMEDIATE" >}} -{{< cards >}} -{{% card link="/how-tos/collect-sensor-data/" noimage="true" %}} -{{% card link="/how-tos/sensor-data-visualize/" noimage="true" %}} -{{% card link="/how-tos/sensor-data-query-with-third-party-tools/" noimage="true" %}} -{{% card link="/how-tos/configure-teleop-workspace/" noimage="true" %}} -{{< /cards >}} -{{< /how-to-expand >}} - -{{< how-to-expand "Collect images and train machine learning models" "3" "INTERMEDIATE" >}} -{{< cards >}} -{{% card link="/how-tos/collect-data/" noimage="true" %}} -{{% card link="/how-tos/train-deploy-ml/" noimage="true" %}} -{{% card link="/how-tos/create-custom-training-scripts/" noimage="true" %}} -{{< /cards >}} -{{< /how-to-expand >}} - -{{< how-to-expand "Manage a large fleet of machines" "2" "INTERMEDIATE" >}} -{{< cards >}} -{{% card link="/how-tos/manage-fleet/" noimage="true" %}} -{{% card link="/how-tos/deploy-packages/" noimage="true" %}} -{{< /cards >}} -{{< /how-to-expand >}} - -{{< how-to-expand "Create and manage modular resources" "5" "INTERMEDIATE" >}} - -{{< cards >}} -{{% card link="/how-tos/hello-world-module/" noimage="true" %}} -{{% card link="/how-tos/sensor-module/" noimage="true" %}} -{{% card link="/how-tos/create-module/" noimage="true" %}} -{{% card link="/how-tos/upload-module/" noimage="true" %}} -{{% card link="/how-tos/manage-modules/" noimage="true" %}} -{{< /cards >}} -{{< /how-to-expand >}} - -
- -

If you're looking for examples of how Viam is being used in the world, have a look at customer stories, follow our step-by-step tutorials, or browse our blog posts.

-
diff --git a/docs/dev/tools/how-tos/configure-teleop-workspace.md b/docs/dev/tools/how-tos/configure-teleop-workspace.md deleted file mode 100644 index ee5a68c48e..0000000000 --- a/docs/dev/tools/how-tos/configure-teleop-workspace.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: "Configure a teleop workspace" -linkTitle: "Configure a teleop workspace" -weight: 10 -type: "docs" -description: "Create and configure a teleop workspace with widgets." -images: ["/how-tos/teleop/full-workspace.png"] -icon: true -tags: ["teleop", "configuration"] -languages: [] -viamresources: ["sensor", "camera", "movement sensor"] -platformarea: ["viz", "data"] -level: "Intermediate" -date: "2024-11-13" -# updated: "2024-08-26" # When the tutorial was last entirely checked -cost: "0" ---- - -You can use teleop to create a custom workspace where you can visualize and aggregate data from a machine. -You can currently visualize data from a camera, a sensor, or a movement sensor. - -{{% alert title="In this page" color="info" %}} - -- [Configure a workspace](#configure-a-workspace) - -{{% /alert %}} - -## Prerequisites - -{{% expand "A configured machine with teleoperable components" %}} - -Make sure your machine has at least one of the following: - -- A camera, movement sensor, sensor, base, arm, board, gantry, gripper, motor or servo - -See [configure a machine](/how-tos/configure/) for more information. - -{{% /expand%}} - -## Configure a workspace - -{{< table >}} -{{% tablestep %}} -**1. Create a workspace in the Viam app** - -Log in to the [Viam app](https://app.viam.com/). - -Navigate to the **FLEET** page's **TELEOP** tab. -Create a workspace by clicking **+ Create workspace**. -Give it a name. - -{{}} - -{{% /tablestep %}} -{{% tablestep %}} -**2. Add widgets** - -Click **Add widget** and select the appropriate widget for your machine. -Repeat as many times as necessary. - -Now your workspace setup is complete: - -{{}} - -{{% /tablestep %}} -{{% tablestep %}} -**3. Select a machine** - -Now, select a machine with which to make your teleop workspace come to life. -Select **Monitor** in the top right corner to leave editing mode. -Click **Select machine** and select your configured machine. - -Your dashboard now shows the configured widgets for the data from your machine: - -{{}} - -You can go back to **Edit** mode and drag and drop the widgets' panes around to edit their appearance. -For example: - -{{}} - -{{% /tablestep %}} -{{< /table >}} - -## Next steps - -Follow more of our how-to guides to do more with the Viam platform: - -{{< cards >}} -{{% card link="/how-tos/detect-people/" %}} -{{% card link="/how-tos/drive-rover/" %}} -{{% card link="/how-tos/train-deploy-ml/" %}} -{{< /cards >}} diff --git a/docs/manage/_index.md b/docs/manage/_index.md index ae09955b5a..87bc8dd361 100644 --- a/docs/manage/_index.md +++ b/docs/manage/_index.md @@ -9,25 +9,41 @@ open_on_desktop: true overview: true --- +You can use Viam's cloud-based fleet management tools to monitor and manage access to your fleet of {{< glossary_tooltip term_id="smart-machine" text="smart machines" >}}. +Use these tools as you create and scale a new fleet of smart machines, or integrate Viam to manage and add functionality like data management to your existing fleet. + +For example, you might have 30 robots in one warehouse and 500 in another. +You can monitor and teleoperate all of the robots from one online dashboard, and grant permission to other users to do the same. +You can grant users different levels of access to individual machines or to groups of machines. + +--- + +Viam fleet management allows you to organize, manage, and control any number of machines alone or in collaboration with others. +You can manage and control your fleet of {{< glossary_tooltip term_id="machine" text="smart machines" >}} from the [Viam app](https://app.viam.com), using the [CLI](/cli/), or using the [fleet management API](/appendix/apis/fleet/). + + {{< how-to-expand "Deploy software to machines" "4" "BEGINNER-FRIENDLY" >}} {{< cards >}} -{{% card link="/how-tos/configure/" noimage="true" %}} -{{% card link="/how-tos/one-to-many/" noimage="true" %}} -{{% card link="/how-tos/provision-setup/" noimage="true" %}} -{{% card link="/how-tos/provision/" noimage="true" %}} +{{% card link="/manage/deploy/provision/" noimage="true" %}} +{{% card link="/manage/deploy/one-to-many/" noimage="true" %}} +{{% card link="/manage/deploy/ota/" noimage="true" %}} +{{% card link="/manage/deploy/setup/" noimage="true" %}} +{{% card link="/manage/deploy/update/" noimage="true" %}} {{< /cards >}} {{< /how-to-expand >}} {{< how-to-expand "Manage a large fleet of machines" "2" "INTERMEDIATE" >}} {{< cards >}} -{{% card link="/how-tos/manage-fleet/" noimage="true" %}} -{{% card link="/how-tos/deploy-packages/" noimage="true" %}} +{{% card link="/manage/manage/organize/" noimage="true" %}} +{{% card link="/manage/manage/access/" noimage="true" %}} {{< /cards >}} {{< /how-to-expand >}} -{{< how-to-expand "Troubleshooting" "2" "INTERMEDIATE" >}} +{{< how-to-expand "Monitor & Troubleshooting" "4" "INTERMEDIATE" >}} {{< cards >}} -{{% card link="/how-tos/manage-fleet/" noimage="true" %}} -{{% card link="/how-tos/deploy-packages/" noimage="true" %}} +{{% card link="/manage/troubleshoot/monitor/" noimage="true" %}} +{{% card link="/manage/troubleshoot/teleoperate/" noimage="true" %}} +{{% card link="/manage/troubleshoot/alert/" noimage="true" %}} +{{% card link="/manage/troubleshoot/troubleshoot/" noimage="true" %}} {{< /cards >}} {{< /how-to-expand >}} diff --git a/docs/manage/deploy/ota.md b/docs/manage/deploy/ota.md index da0098f4e1..30576c4060 100644 --- a/docs/manage/deploy/ota.md +++ b/docs/manage/deploy/ota.md @@ -1,6 +1,6 @@ --- linkTitle: "Deploy packages" -title: "Deploy packages to machines (OTA)" +title: "Deploy software packages to machines (OTA)" weight: 10 layout: "docs" type: "docs" diff --git a/docs/manage/manage/_index.md b/docs/manage/manage/_index.md index 8f8045865b..1f5bf9141b 100644 --- a/docs/manage/manage/_index.md +++ b/docs/manage/manage/_index.md @@ -8,15 +8,3 @@ empty_node: true open_on_desktop: true header_only: true --- - -You can use Viam's cloud-based fleet management tools to monitor and manage access to your fleet of {{< glossary_tooltip term_id="smart-machine" text="smart machines" >}}. -Use these tools as you create and scale a new fleet of smart machines, or integrate Viam to manage and add functionality like data management to your existing fleet. - -For example, you might have 30 robots in one warehouse and 500 in another. -You can monitor and teleoperate all of the robots from one online dashboard, and grant permission to other users to do the same. -You can grant users different levels of access to individual machines or to groups of machines. - ---- - -Viam fleet management allows you to organize, manage, and control any number of machines alone or in collaboration with others. -You can manage and control your fleet of {{< glossary_tooltip term_id="machine" text="smart machines" >}} from the [Viam app](https://app.viam.com), using the [CLI](/cli/), or using the [fleet management API](/appendix/apis/fleet/). diff --git a/docs/manage/manage/access.md b/docs/manage/manage/access.md index 263c9bdbab..e3a96c8b40 100644 --- a/docs/manage/manage/access.md +++ b/docs/manage/manage/access.md @@ -5,11 +5,11 @@ weight: 20 layout: "docs" type: "docs" no_list: true -description: "TODO" +description: "To collaborate with others on your machines, you can grant users permissions for individual machines or entire locations." --- -To collaborate with others on your machines, you can grant individual collaborators or entire organizations granular permissions for individual machines or entire locations. -You can use the [Viam app](https://app.viam.com) or the [Viam mobile app](/fleet/control/#control-interface-in-the-viam-mobile-app) to grant or revoke organization owner or operator access to users on the go. +To collaborate with others on your machines, you can grant users permissions for individual machines or entire locations. +You can use the [Viam app](https://app.viam.com) or the [Viam mobile app](/fleet/control/#control-interface-in-the-viam-mobile-app) to grant or revoke organization owner or operator access to users or API keys. ## Grant access @@ -95,7 +95,14 @@ You can also remove the user by clicking on **Remove user**. You can remove any organization except the primary owner from the shared list by clicking the **X** to the right of the location in the shared list. -## Simultaneous configuration changes +## Rotate an API key + +If you ever need to rotate an API key, click on the **Generate Key** button on the organization setting page to generate a new key. + +Viam supports flexible key rotation with up to two keys in use at one time. +After generating a new secret key, update all references to the key in your code as soon as possible and then remove the old key. + +## Collaborate safely When you or your collaborators change the configuration of a machine or a group of machines in the Viam app, `viam-server` automatically synchronizes the configuration and updates the running resources within 15 seconds. This means everyone who has access can change a fleet's [configuration](machines/#configure), even while your machines are running. diff --git a/docs/manage/manage/organize.md b/docs/manage/manage/organize.md index 31dc4460ad..a069764ee0 100644 --- a/docs/manage/manage/organize.md +++ b/docs/manage/manage/organize.md @@ -5,7 +5,7 @@ weight: 10 layout: "docs" type: "docs" no_list: true -description: "TODO" +description: "Organize and manage access to your fleet by grouping machines into organizations and locations." aliases: - /fleet/account/ - /cloud/account/ @@ -26,6 +26,8 @@ You cannot move machines to other locations once created. {{}}

+## Create organizations and locations + {{< table >}} {{% tablestep link="/cloud/organizations/" %}} **1. Create organizations** @@ -67,6 +69,6 @@ You can nest locations up to three levels deep. {{% /tablestep %}} {{< /table >}} -{{< alert title="Tip" color="tip" >}} +## Example + If you'd like to look at an example, see [Monitor Air Quality with a Fleet of Sensors](/tutorials/control/air-quality-fleet/#example). -{{< /alert >}} diff --git a/docs/manage/reference/agent.md b/docs/manage/reference/agent.md index e1929495d9..7c211865f5 100644 --- a/docs/manage/reference/agent.md +++ b/docs/manage/reference/agent.md @@ -45,7 +45,9 @@ Your machine must have `curl` available in order to install `viam-agent`. 2. Navigate to the **CONFIGURE** tab and find your machine's card. An alert will be present directing you to **Set up your machine part**: -![Machine setup alert in a newly created machine](/installation/setup-part.png) +

+{{}} +

Click **View setup instructions** to open the setup instructions. Then navigate to the machine part's setup and follow the instructions to install `viam server` with `viam-agent`. @@ -81,7 +83,9 @@ For information on managing the service, see [Manage `viam-agent`](/installation Navigate to the **CONFIGURE** tab of your machine's page in the [Viam app](https://app.viam.com). Click the **+** icon next to your machine part in the left-hand menu and select **Agent**. -{{< imgproc src="/configure/agent.png" alt="Configuration of viam-agent" resize="1200x" style="width=600x" >}} +

+{{< imgproc src="/configure/agent.png" alt="Configuration of viam-agent" resize="1200x" style="width:600px" class="imgzoom aligncenter">}} +

Edit and fill in the attributes as applicable. @@ -343,11 +347,3 @@ You can find these messages on the [**LOGS** tab](/cloud/machines/#logs) of your If your machine is offline, log messages are queued and are sent to the Viam app once your machine reconnects to the internet. These log messages include when `viam-server` is stopped and started, the status of agent subsystems, and any errors or warnings encountered during operation. - -## Next Steps - -To see how to provision machines using `viam-agent`, see: - -{{< cards >}} -{{% card link="/fleet/provision/" %}} -{{< /cards >}} diff --git a/docs/manage/reference/processes.md b/docs/manage/reference/processes.md index b9c0d2618c..a4fac5752d 100644 --- a/docs/manage/reference/processes.md +++ b/docs/manage/reference/processes.md @@ -15,10 +15,6 @@ To run a program or control code when your machine is online, configure a _{{< g The process is managed by `viam-server`. You can configure processes to run once upon startup or indefinitely. -{{< alert title="In this page" color="note" >}} -{{% toc %}} -{{< /alert >}} - ## Configure a process Navigate to the **CONFIGURE** tab of your machine's page in the [Viam app](https://app.viam.com). diff --git a/docs/manage/reference/rbac.md b/docs/manage/reference/rbac.md index ce590fc01d..92b103ade2 100644 --- a/docs/manage/reference/rbac.md +++ b/docs/manage/reference/rbac.md @@ -1,6 +1,6 @@ --- title: "Role-Based Access Control" -linkTitle: "Manage Access" +linkTitle: "Permissions" description: "Fleet and data management permissions." weight: 30 type: "docs" @@ -12,62 +12,16 @@ date: "2022-01-01" # SME: Devin Hilly --- -Role-Based Access Control (RBAC) is a way to enforce security in the [Viam app](https://app.viam.com) by assigning organization members roles that confer permissions. -Users can have access to different fleet management capabilities depending on whether they are an owner or an operator of a given {{< glossary_tooltip term_id="organization" text="organization" >}}, {{< glossary_tooltip term_id="location" text="location" >}}, or {{< glossary_tooltip term_id="machine" text="machine" >}}. +Role-Based Access Control (RBAC) is a way to enforce security in the [Viam app](https://app.viam.com) by assigning organization members or API keys roles that confer permissions. +You can assign an owner or an operator role for an {{< glossary_tooltip term_id="organization" text="organization" >}}, {{< glossary_tooltip term_id="location" text="location" >}}, or {{< glossary_tooltip term_id="machine" text="machine" >}}. -- **Owner**: Can see and edit [every tab on the machine page](/cloud/machines/#navigating-the-machine-page). - Can manage users in the app. -- **Operator**: Can see and use only the [**CONTROL**](/fleet/control/) tab. +- **Owner**: Can see and edit [every tab on the machine page](/cloud/machines/#navigating-the-machine-page) and perform equivalent operations from the APIs. +- **Operator**: Can see and use only the [**CONTROL**](/fleet/control/) tab and perform equivalent operations from the APIs. Cannot see or edit the [**CONFIGURE**](/cloud/machines/#configure), [**LOGS**](/cloud/machines/#logs), or **CONNECT** tabs. -For more detailed information on the permissions each role confers for different resources, see [Permissions](/cloud/rbac/#permissions). - -## API keys - -API keys grant access to organizations, locations, and machines. -If at the organization level, they grant access to all locations and machines contained within that organization. -If at the location level, they grant access to all of the machines contained within that location. - -To view all API keys in use for your organization and the locations and machines inside it, click on the organization dropdown in the top navigation bar and click on **Settings**. - -View a table with each key, ID, name (if assigned), time created, and entities it provides access to: - -{{}} - -In each row, click the copy icon to copy the API key and key ID. -Click the duplicate icon to duplicate the API key. -Click the trash can icon to delete the API key. - -### Add an API key - -Click **Generate key** to generate a new key. -Optionally, give the key a name of your choice. -Click on the **Resource** menu and choose what organization, location, or machine you want the key to grant access to. -For **Role**, assign either an **Owner** or **Operator** role. -See [Permissions](#permissions) for information about the privilege each role entails at each resource level. - -### View an API key's details - -To view the role of an API key and what it grants access to, click on **Show details** in the key's row of the key table's **Resources** column: - -{{}} - -### Change an API key's access - -To edit an API key, click on **Show details** in the key's row of the key table's **Resources** column. - -To edit the role, click on the dropdown menu next to the role and select **Owner** or **Operator**. -See [Permissions](#permissions) for information about the privilege each role entails at each resource level. - -To change the entities it is able to access, click **+ Grant additional access**. -Select which organization, location, or machine you want the key to grant access to. -Click **Choose** to confirm your selection. - -## Permissions - The following sections describe the permissions for each user role when it comes to managing machines, locations, organizations, fragments, and data. -### Machines +## Machines Permissions for managing {{< glossary_tooltip term_id="machine" text="machines" >}} are as follows: @@ -83,7 +37,7 @@ Permissions for managing {{< glossary_tooltip term_id="machine" text="machines" | Restart the machine | **Yes** | No | **Yes** | No | **Yes** | No | | Edit a machine config (including data capture and sync) | **Yes** | No | **Yes** | No | **Yes** | No | -### Locations +## Locations Permissions for managing {{< glossary_tooltip term_id="location" text="locations" >}} are as follows: @@ -106,7 +60,7 @@ If a user is an owner of an organization with which a location was shared (that \*Users can only use Try Viam from within an organization they own because doing so creates a new location in the org. -### Organization settings and roles +## Organization settings and roles Only {{< glossary_tooltip term_id="organization" text="organization" >}} owners can edit or delete an organization, or see and edit the organization billing page. @@ -131,7 +85,7 @@ Permissions for managing org settings and user roles are as follows: \*For locations/machines they have access to -### Fragments +## Fragments Permissions for managing {{< glossary_tooltip term_id="fragment" text="fragments" >}} are as follows: @@ -142,7 +96,7 @@ Permissions for managing {{< glossary_tooltip term_id="fragment" text="fragments | See and use fragments in the {{< glossary_tooltip term_id="organization" text="org" >}} | **Yes** | No | **Yes** | No | **Yes** | No | | Edit and delete fragments | **Yes** | No | No | No | No | No | -### Data and machine learning +## Data and machine learning Permissions for [data management](/fleet/data-management/) and [machine learning](/services/ml/) are as follows: @@ -170,12 +124,3 @@ Permissions for [data management](/fleet/data-management/) and [machine learning \*For data from the location \*\*For data from the machine - ---- - -#### Rotate a secret key - -If you ever need to rotate this key, click on the **Generate Key** button to generate a new key. - -Viam supports flexible key rotation with up to two keys in use at one time. -After generating a new secret key, update all references to the key in your code as soon as possible and then remove the old key. diff --git a/docs/manage/reference/triggers.md b/docs/manage/reference/triggers.md deleted file mode 100644 index 3999e7cf1b..0000000000 --- a/docs/manage/reference/triggers.md +++ /dev/null @@ -1,495 +0,0 @@ ---- -title: "Configure a Trigger" -linkTitle: "Triggers" -weight: 10 -type: "docs" -description: "Configure a trigger to trigger actions when data is sent from your machine to the cloud, or when your machine's internet connectivity changes." -tags: ["triggers"] -aliases: - - /build/configure/webhooks/ - - /build/configure/triggers/ -date: "2024-10-17" -# updated: "" # When the content was last entirely checked ---- - -Triggers allow you to send webhook requests or emails for the following events: - -- **Data has been synced to the cloud**: trigger when data from the machine is synced -- **Part is online**: trigger continuously at a specified interval while the {{< glossary_tooltip term_id="part" text="machine part" >}} is online -- **Part is offline**: trigger continuously at a specified interval while the machine part is offline -- **Conditional data ingestion**: trigger any time data is captured from a specified component with a specified method and condition - -For example, you can configure a trigger to send you a notification when your robot's sensor collects a new reading. - -## Configuration - -To configure a trigger: - -{{< tabs >}} -{{% tab name="Builder mode" %}} - -1. Go to the **CONFIGURE** tab of your machine on the [Viam app](https://app.viam.com). - Click the **+** (Create) button in the left side menu and select **Trigger**. - - {{}} - -2. Name the trigger and click **Create**. - -3. Select trigger **Type**. - For some types you can configure additional attributes: - -{{< tabs name="Types of Triggers" >}} -{{% tab name="Data synced to cloud" %}} - -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. - -{{% /tab %}} -{{% tab name="Conditional data ingestion" %}} - -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](#conditions). - -{{% alert title="Note" color="note" %}} -You must [configure data capture](/services/data/) for your component to use this trigger. -{{% /alert %}} - -{{% /tab %}} -{{< /tabs >}} - -4. Add **Webhooks** or **Emails**. - -{{< tabs name="Notifications types" >}} -{{% tab name="Webhooks" %}} - -Click **Add Webhook**. -Add the URL of your cloud function or lambda. -Configure the time between notifications. - -![The trigger configured with an example URL in the Viam app.](/build/configure/trigger-configured.png) - -{{% /tab %}} -{{% tab name="Emails" %}} - -Click **Add Email**. -Add the email you wish to be notified whenever this trigger is triggered. -Configure the time between notifications. - -![The trigger configured with an example email in the Viam app.](/build/configure/trigger-configured-email.png) - -{{% /tab %}} -{{< /tabs >}} -{{% /tab %}} -{{% tab name="JSON mode" %}} - -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"`. - -{{< tabs >}} -{{% tab name="JSON Template: Data Synced" %}} - -```json {class="line-numbers linkable-line-numbers"} - "triggers": [ - { - "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": - } - ] - } - ] -``` - -{{% /tab %}} -{{% tab name="JSON Template: Part Online" %}} - -```json {class="line-numbers linkable-line-numbers"} - "triggers": [ - { - "name": "", - "event": { - "type": "part_online" - }, - "notifications": [ - { - "type": "webhook", - "value": "", - "seconds_between_notifications": - } - ] - } - ] -``` - -{{% /tab %}} -{{% tab name="JSON Template: Part Offline" %}} - -```json {class="line-numbers linkable-line-numbers"} - "triggers": [ - { - "name": "", - "event": { - "type": "part_offline" - }, - "notifications": [ - { - "type": "webhook", - "value": "", - "seconds_between_notifications": - } - ] - } - ] -``` - -{{% /tab %}} -{{% tab name="JSON Template: Conditional Data Ingestion" %}} - -```json {class="line-numbers linkable-line-numbers"} -"triggers": [ - { - "name": "", - "event": { - "type": "conditional_data_ingested", - "conditional": { - "data_capture_method": "::", - "condition": { - "evals": [ - { - "operator": "", - "value": - } - ] - } - } - }, - "notifications": [ - { - "type": "email", - "value": "", - "seconds_between_notifications": - } - ] - } -] - -``` - -{{% /tab %}} -{{% tab name="JSON Example" %}} - -```json {class="line-numbers linkable-line-numbers"} -{ - "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": "", - "seconds_between_notifications": 0 - } - ] - } - ] -} -``` - -{{% /tab %}} -{{< /tabs >}} - -{{% /tab %}} -{{< /tabs >}} - -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:
  • `type`: The type of the event to trigger on. Options: `part_online`, `part_offline`, `part_data_ingested`, `conditional_data_ingested`.
  • `data_types`: Required with `type` `part_data_ingested`. The data types that trigger the event. Options: `binary`, `tabular`, `file`, `unspecified`.
  • `conditional`: Required with `type` `conditional_data_ingested`. See [Conditions](#conditions) for more information.
| -| `notifications` | object | **Required** | The notifications object:
  • `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.
| - -#### Conditions - -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::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:
  • `evals`:
    • `operator`: Logical operator for the condition.
    • `value`: An object, string, or integer that specifies the value of the method of the condition, along with the key or nested keys of the measurements in data capture.
| - -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: - -{{< tabs >}} -{{% tab name="1 level of nesting" %}} - -```json {class="line-numbers linkable-line-numbers"} -"condition": { - "evals": [ - { - "operator": "lt", - "value": { - "Line-Neutral AC RMS Voltage": 130 - } - } - ] -} -``` - -This eval would trigger for the following sensor reading: - -```json {class="line-numbers linkable-line-numbers"} -{ - "readings": { - "Line-Neutral AC RMS Voltage": 100 - } -} -``` - -{{% /tab %}} -{{% tab name="2 levels of nesting" %}} - -```json {class="line-numbers linkable-line-numbers"} -"condition": { - "evals": [ - { - "operator": "lt", - "value": { - "coordinate": { - "latitude": 50 - } - } - } - ] -} -``` - -This eval would trigger for the following sensor reading: - -```json {class="line-numbers linkable-line-numbers"} -{ - "readings": { - "coordinate": { - "latitude": 40 - } - } -} -``` - -{{% /tab %}} -{{< /tabs >}} - -5. Write your cloud function or lambda to process the request from `viam-server`. - You can use your cloud function or lambda to interact with any external API such as, for example, Twilio, PagerDuty, or Zapier. - The following example function prints the received headers: - - {{< tabs >}} - {{% tab name="Flask" %}} - -```python {class="line-numbers linkable-line-numbers" } -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) -``` - -{{% /tab %}} -{{% tab name="functions_framework" %}} - -```python {class="line-numbers linkable-line-numbers"} -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) -``` - -{{% /tab %}} -{{< /tabs >}} - -## Returned headers - -When a trigger 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 | - -## Returned data - -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) | - -## Next steps - -To see an example project that uses triggers to send email notification, see the [Monitor Job Site Helmet Usage with Computer Vision tutorial](/tutorials/projects/helmet/#configure-a-trigger-on-your-machine). - -{{< cards >}} -{{% card link="/tutorials/projects/helmet/" %}} -{{< /cards >}} diff --git a/docs/manage/troubleshoot/alert.md b/docs/manage/troubleshoot/alert.md index 1aa164c402..aac4dc5052 100644 --- a/docs/manage/troubleshoot/alert.md +++ b/docs/manage/troubleshoot/alert.md @@ -5,5 +5,714 @@ weight: 20 layout: "docs" type: "docs" no_list: true -description: "TODO" +description: "Configure a trigger to trigger actions when data is sent from your machine to the cloud, or when your machine's internet connectivity changes." +tags: ["triggers"] +aliases: + - /build/configure/webhooks/ + - /build/configure/triggers/ +date: "2024-10-17" +# updated: "" # When the content was last entirely checked --- + +You can receive alerts for the following machine events: + +- **Data has been synced to the cloud**: receive an email or webhook when data from the machine is synced +- **Part is online**: receive an email or webhook continuously at a specified interval while the {{< glossary_tooltip term_id="part" text="machine part" >}} is online +- **Part is offline**: receive an email or webhook continuously at a specified interval while the machine part is offline +- **Conditional data ingestion**: receive an email or webhook any time data is captured that meets a certain condition + +For example, you can configure a trigger to send you a notification when your robot's sensor collects a new reading. + +## Data synced + +You must [configure data capture](/services/data/) for your machine to use this trigger. + +{{< tabs >}} +{{% tab name="Builder mode" %}} + +1. Go to the **CONFIGURE** tab of your machine on the [Viam app](https://app.viam.com). + Click the **+** (Create) button in the left side menu and select **Trigger**. + + {{}} + +2. Name the trigger and click **Create**. + +3. Select **Data synced to cloud** as the **Type**. + + Then, 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. + +4. Add **Webhooks** or **Emails** and configure the time between notifications. + For more information on webhooks, see [Webhooks](#webhooks). + +{{% /tab %}} +{{% tab name="JSON mode" %}} + +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"`. + +{{< tabs >}} +{{% tab name="JSON Template: Data Synced" %}} + +```json {class="line-numbers linkable-line-numbers"} + "triggers": [ + { + "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": + } + ] + } + ] +``` + +{{% /tab %}} +{{% tab name="JSON Example" %}} + +```json {class="line-numbers linkable-line-numbers"} +{ + "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": "", + "seconds_between_notifications": 10 + } + ] + } + ] +} +``` + +{{% /tab %}} +{{< /tabs >}} + +{{% /tab %}} +{{< /tabs >}} + +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:
  • `type`: `part_data_ingested`.
  • `data_types`: The data types that trigger the event. Options: `binary`, `tabular`, `file`, `unspecified`.
| +| `notifications` | object | **Required** | The notifications object:
  • `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.
| + +## Part is online + +{{< tabs >}} +{{% tab name="Builder mode" %}} + +1. Go to the **CONFIGURE** tab of your machine on the [Viam app](https://app.viam.com). + Click the **+** (Create) button in the left side menu and select **Trigger**. + + {{}} + +2. Name the trigger and click **Create**. + +3. Select **Part is online** as the trigger **Type**. + +4. Add **Webhooks** or **Emails** and configure the time between notifications. + For more information on webhooks, see [Webhooks](#webhooks). + +{{% /tab %}} +{{% tab name="JSON mode" %}} + +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"`. + +{{< tabs >}} +{{% tab name="JSON Template: Part Online" %}} + +```json {class="line-numbers linkable-line-numbers"} + "triggers": [ + { + "name": "", + "event": { + "type": "part_online" + }, + "notifications": [ + { + "type": "webhook", + "value": "", + "seconds_between_notifications": + } + ] + } + ] +``` + +{{% /tab %}} +{{% tab name="JSON Example" %}} + +```json {class="line-numbers linkable-line-numbers"} +{ + "components": [ + { + "name": "local", + "model": "pi", + "type": "board", + "namespace": "rdk", + "attributes": {}, + "depends_on": [] + } + ], + "triggers": [ + { + "name": "trigger-1", + "event": { + "type": "part_online" + }, + "notifications": [ + { + "type": "webhook", + "value": "", + "seconds_between_notifications": 10 + } + ] + } + ] +} +``` + +{{% /tab %}} +{{< /tabs >}} + +{{% /tab %}} +{{< /tabs >}} + +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:
  • `type`: `part_online`.
| +| `notifications` | object | **Required** | The notifications object:
  • `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.
| + +## Part is offline + +{{< tabs >}} +{{% tab name="Builder mode" %}} + +1. Go to the **CONFIGURE** tab of your machine on the [Viam app](https://app.viam.com). + Click the **+** (Create) button in the left side menu and select **Trigger**. + + {{}} + +2. Name the trigger and click **Create**. + +3. Select **Part is offline** as the trigger **Type**. + +4. Add **Webhooks** or **Emails** and configure the time between notifications. + For more information on webhooks, see [Webhooks](#webhooks). + +{{% /tab %}} +{{% tab name="JSON mode" %}} + +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"`. + +{{< tabs >}} +{{% tab name="JSON Template: Part Offline" %}} + +```json {class="line-numbers linkable-line-numbers"} + "triggers": [ + { + "name": "", + "event": { + "type": "part_offline" + }, + "notifications": [ + { + "type": "webhook", + "value": "", + "seconds_between_notifications": + } + ] + } + ] +``` + +{{% /tab %}} +{{% tab name="JSON Example" %}} + +```json {class="line-numbers linkable-line-numbers"} +{ + "components": [ + { + "name": "local", + "model": "pi", + "type": "board", + "namespace": "rdk", + "attributes": {}, + "depends_on": [] + } + ], + "triggers": [ + { + "name": "trigger-1", + "event": { + "type": "part_offline", + }, + "notifications": [ + { + "type": "webhook", + "value": "", + "seconds_between_notifications": 10 + } + ] + } + ] +} +``` + +{{% /tab %}} +{{< /tabs >}} + +{{% /tab %}} +{{< /tabs >}} + +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:
  • `type`: `part_offline`.
| +| `notifications` | object | **Required** | The notifications object:
  • `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.
| + +## Data meets condition + +You must [configure data capture](/services/data/) for your machine to use this trigger. + +{{< tabs >}} +{{% tab name="Builder mode" %}} + +1. Go to the **CONFIGURE** tab of your machine on the [Viam app](https://app.viam.com). + Click the **+** (Create) button in the left side menu and select **Trigger**. + + {{}} + +2. Name the trigger and click **Create**. + +3. Select **Conditional data ingestion** as the trigger **Type**. + + Then select the component you want to capture data from and the method you want to capture data from. + Next, 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](#conditions). + +4. Add **Webhooks** or **Emails** and configure the time between notifications. + For more information on webhooks, see [Webhooks](#webhooks). + +{{% /tab %}} +{{% tab name="JSON mode" %}} + +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"`. + +{{< tabs >}} +{{% tab name="JSON Template: Conditional Data Ingestion" %}} + +```json {class="line-numbers linkable-line-numbers"} +"triggers": [ + { + "name": "", + "event": { + "type": "conditional_data_ingested", + "conditional": { + "data_capture_method": "::", + "condition": { + "evals": [ + { + "operator": "", + "value": + } + ] + } + } + }, + "notifications": [ + { + "type": "email", + "value": "", + "seconds_between_notifications": + } + ] + } +] + +``` + +{{% /tab %}} +{{% tab name="JSON Example" %}} + +```json {class="line-numbers linkable-line-numbers"} +{ + "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": "conditional_data_ingested", + "conditional": { + "data_capture_method": "sensor:my_temp_sensor:Readings", + "condition": { + "evals": [ + { + "operator": "gt", + "value": { + "co2": 1000 + } + } + ] + } + } + }, + "notifications": [ + { + "type": "webhook", + "value": "", + "seconds_between_notifications": 10 + } + ] + } + ] +} +``` + +{{% /tab %}} +{{< /tabs >}} + +{{% /tab %}} +{{< /tabs >}} + +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:
  • `type`: `conditional_data_ingested`.
  • `conditional`: Condition object. See [Conditions](#conditions) for more information.
| +| `notifications` | object | **Required** | The notifications object:
  • `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.
| + +### Conditions + +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::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:
  • `evals`:
    • `operator`: Logical operator for the condition.
    • `value`: An object, string, or integer that specifies the value of the method of the condition, along with the key or nested keys of the measurements in data capture.
| + +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: + +{{< tabs >}} +{{% tab name="1 level of nesting" %}} + +```json {class="line-numbers linkable-line-numbers"} +"condition": { + "evals": [ + { + "operator": "lt", + "value": { + "Line-Neutral AC RMS Voltage": 130 + } + } + ] +} +``` + +This eval would trigger for the following sensor reading: + +```json {class="line-numbers linkable-line-numbers"} +{ + "readings": { + "Line-Neutral AC RMS Voltage": 100 + } +} +``` + +{{% /tab %}} +{{% tab name="2 levels of nesting" %}} + +```json {class="line-numbers linkable-line-numbers"} +"condition": { + "evals": [ + { + "operator": "lt", + "value": { + "coordinate": { + "latitude": 50 + } + } + } + ] +} +``` + +This eval would trigger for the following sensor reading: + +```json {class="line-numbers linkable-line-numbers"} +{ + "readings": { + "coordinate": { + "latitude": 40 + } + } +} +``` + +{{% /tab %}} +{{< /tabs >}} + +## Webhooks + +### 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: + +{{< tabs >}} +{{% tab name="Flask" %}} + +```python {class="line-numbers linkable-line-numbers" } +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) +``` + +{{% /tab %}} +{{% tab name="functions_framework" %}} + +```python {class="line-numbers linkable-line-numbers"} +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) +``` + +{{% /tab %}} +{{< /tabs >}} + +### Returned headers + +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 | + +### Returned data + +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) | + +## Example project + +To see an example project that uses triggers to send email notification, see the [Monitor Job Site Helmet Usage with Computer Vision tutorial](/tutorials/projects/helmet/#configure-a-trigger-on-your-machine). + +{{< cards >}} +{{% card link="/tutorials/projects/helmet/" %}} +{{< /cards >}} diff --git a/docs/manage/troubleshoot/monitor.md b/docs/manage/troubleshoot/monitor.md index 37538b9bb0..5e8d92010d 100644 --- a/docs/manage/troubleshoot/monitor.md +++ b/docs/manage/troubleshoot/monitor.md @@ -5,7 +5,7 @@ weight: 10 layout: "docs" type: "docs" no_list: true -description: "TODO" +description: "Monitor the status of all machines in an organization and investigate issues when needed." --- You can view all machines in an organization from a dashboard and access each machine from it.