> For the complete documentation index, see [llms.txt](https://docs.roboflow.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.roboflow.com/workflows/tutorials/integrate-with-ignition/live-data/trigger-an-inspection-from-ignition.md).

# Trigger an Inspection from Ignition

Let Ignition ask a Roboflow edge device to inspect a part on demand over HTTP, and write the Workflow's result back into Ignition tags.

Use this path when Ignition decides when to inspect (ex: a part-present sensor or an HMI button). Ignition calls the device over HTTP, the device runs its Workflow on the latest camera frame, and the reply carries the result back to Ignition.

{% hint style="info" %}
The OPC UA Writer Sink, the OPC UA Reader, and the OPC UA Server are available exclusively for Enterprise customers. [Contact the Roboflow sales team](https://roboflow.com/sales) to learn more.
{% endhint %}

{% hint style="info" %}
These steps and screenshots are from Ignition 8.1 (Designer 8.1.55). Menu names, dialogs, and property names can differ in other versions, including 8.3.
{% endhint %}

## Example Tags

This page uses five tags to show the pattern. They are an example for illustration: define your own names, folder, and data types to fit your line, and match them in the script.

<table data-search="false"><thead><tr><th>Tag</th><th>Data type</th><th>What it means</th></tr></thead><tbody><tr><td><code>Roboflow/Inspect</code></td><td>Boolean</td><td>Set it to <code>true</code> to ask for an inspection (ex: from a part-present sensor or an HMI button). The script sets it back to <code>false</code> when the result is in.</td></tr><tr><td><code>Roboflow/DeviceTriggerUrl</code></td><td>String</td><td>The stream's trigger address on the device</td></tr><tr><td><code>Roboflow/LastDetections</code></td><td>Integer (Int4)</td><td>How many objects the last inspection found, or <code>-1</code> if it failed</td></tr><tr><td><code>Roboflow/LastResult</code></td><td>String</td><td>The count of each class from the last inspection, as JSON (ex: <code>{"bottle":12}</code>)</td></tr><tr><td><code>Roboflow/LastError</code></td><td>String</td><td>Why the last inspection failed, or empty when it worked</td></tr></tbody></table>

## Add a Triggered Stream

In Deployment Manager, open the device and click "Add Stream". Pick your Workflow in "Workflow ID", set "Mode" to "Triggered", enter your camera's "RTSP URL", and click "Create Stream". A triggered stream keeps the camera open and the model loaded, but runs the Workflow only when triggered. Any Workflow works, because Ignition gets whatever the Workflow outputs, so leave out the OPC UA Writer Sink.

<figure><img src="https://1126624165-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoO0Ceoy9R0lHDZATcPyh%2Fuploads%2Fgit-blob-c659a1d5fbbdc157a8c0df330b310925ac344ab3%2Fignition-dm-add-stream-triggered.png?alt=media" alt="The Deployment Manager Add New Video Stream dialog with Name line-1-camera, the Workflow selected, Mode Triggered, Stream Type RTSP Stream, and an RTSP URL" width="400"><figcaption><p>A triggered stream waits for Ignition.</p></figcaption></figure>

The stream's trigger address is `http://<device-ip>:8000/inference_pipelines/<pipeline-id>/trigger`. Find the pipeline ID in the stream details in Deployment Manager.

## Create the Tags in Ignition

In Designer, pick the `default` provider in the Tag Browser. Create a folder named `Roboflow`, then add the example tags to it as memory tags with the data types above: right-click the folder, pick "New Tag" > "Memory Tag", and set "Name" and "Data Type" in the Tag Editor. Set the value of `DeviceTriggerUrl` to the stream's trigger address.

<figure><img src="https://1126624165-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoO0Ceoy9R0lHDZATcPyh%2Fuploads%2Fgit-blob-2dd6de0e5a8eedacbea39630449ba110c2074c15%2Fignition-designer-inspect-tags.png?alt=media" alt="The Ignition Designer Tag Browser with the Roboflow folder expanded, showing DeviceTriggerUrl set to the device trigger address, Inspect false, LastDetections 12, an empty LastError, and LastResult {&#x22;bottle&#x22;:12}"><figcaption><p>The example tags after an inspection. The folder also holds other tags.</p></figcaption></figure>

## Add the Inspect Script

Double-click `Inspect` to open the Tag Editor, go to "Scripting" > "Value Changed", and paste this into the body of the script. It assumes the Workflow has an object detection output named `predictions`:

```python
if initialChange or not currentValue.value:
    return
import java.lang
def run():
    log = system.util.getLogger("Roboflow")
    base = "[default]Roboflow/"
    try:
        url = system.tag.readBlocking([base + "DeviceTriggerUrl"])[0].value
        # HTTP/1.1: the device rejects the HTTP/2 upgrade Ignition sends by default.
        resp = system.net.httpClient(timeout=300000, version="HTTP_1_1").post(url, data="{}", headers={"Content-Type": "application/json"})
        body = resp.json if resp.good else None
        if not body or not body.get("success"):
            raise ValueError("HTTP %s: %s" % (resp.statusCode, resp.text[:300]))
        preds = body["data"]["workflow_output"][0]["predictions"]["predictions"]
        counts = {}
        for p in preds:
            counts[p["class"]] = counts.get(p["class"], 0) + 1
        system.tag.writeBlocking([base + "LastDetections", base + "LastResult", base + "LastError"], [len(preds), system.util.jsonEncode(counts), ""])
    except (Exception, java.lang.Exception) as e:
        system.tag.writeBlocking([base + "LastDetections", base + "LastResult", base + "LastError"], [-1, "", str(e)[:500]])
        log.warn("Roboflow inspect failed: %s" % e)
    finally:
        system.tag.writeBlocking([base + "Inspect"], [False])
# The HTTP call blocks until the Workflow finishes, so run it off the tag event thread.
system.util.invokeAsynchronous(run)
```

<figure><img src="https://1126624165-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoO0Ceoy9R0lHDZATcPyh%2Fuploads%2Fgit-blob-7cf6d0e9f1d15a439f53f4f81440406cbacef11a%2Fignition-designer-inspect-script.png?alt=media" alt="The Ignition Tag Editor for the Inspect tag, on Scripting > Value Changed, with the script that posts to the device trigger URL and writes LastDetections, LastResult, and LastError"><figcaption><p>The Value Changed script on <code>Inspect</code>.</p></figcaption></figure>

Set `Inspect` to `true` from an HMI button, a PLC tag change script, or any OPC UA client. When it is back to `false`, read the result tags (ex: `LastDetections` is `12` and `LastResult` is `{"bottle":12}` for twelve bottles). To pass per-run inputs (ex: a product code), send them in the request body as `{"workflows_parameters": {...}}`. Learn more about the [edge trigger](https://docs.roboflow.com/deployment/self-hosted/enterprise/deployment-manager/making-changes/trigger-a-stream#edge-trigger).

## Pass a Value into a Running Workflow

To pass a value from Ignition into a Workflow that already runs, use the OPC UA Reader block instead. The block needs `roboflow-workflows` 0.2.13 or later in the device's inference image, so update the device if the block is missing. It subscribes to one tag and returns its latest `value` on every run, with `is_new` and `error_status`. Pair it with a Continue If block to skip inference while a flag is off (ex: a `LineRunning` tag). Set its "Url", "Namespace", "Object Name", "Variable Name", and "Node Lookup Mode" the same way as the Writer Sink for that server: "direct" for an Ignition tag, "hierarchical" for a tag on the Roboflow OPC UA Server.

## Troubleshooting

<table data-search="false"><thead><tr><th>Symptom</th><th>Cause</th><th>Fix</th></tr></thead><tbody><tr><td><code>LastError</code> shows <code>HTTP 400: Invalid HTTP request received.</code></td><td>Ignition's HTTP client is using HTTP/2</td><td>Keep <code>version="HTTP_1_1"</code> in the script</td></tr><tr><td>The first trigger times out in Deployment Manager</td><td>The first run of a model builds its TensorRT engine, which can take minutes</td><td>Wait. The run still finishes, and the engine is cached for later runs.</td></tr></tbody></table>

## Security

The device's trigger endpoint on port 8000 has no authentication, so anyone who can reach it can trigger the stream. The request body also replaces the stream's Workflow inputs for that run. Limit who can reach port 8000.
