Azure IoT Edge Trigger Nodes
Overview
When MaestroHub runs as an Azure IoT Edge module, two triggers start pipelines from the local edge hub:
- Azure IoT Edge Input Trigger — one run per message an edge hub route delivers to one of MaestroHub's module inputs: results from an analytics or AI module, or data from a device behind the edge gateway.
- Azure IoT Edge Twin Trigger — one run per change to the desired properties of MaestroHub's module twin, for example configuration pushed to many devices through an IoT Hub deployment.
- Azure IoT Edge Method Trigger — one run per direct-method call a cloud application makes on MaestroHub's module; the pipeline answers with a Respond to Direct Method node.
All three keep working while the device is offline from Azure: the messages come from the edge hub on the device.
Core Functionality
Routes decide what arrives. An input receives a message only when a route delivers to it, for example FROM /messages/modules/anomaly-detector/outputs/alerts INTO BrokeredEndpoint("/modules/maestrohub/inputs/alerts"). Without a route the trigger never fires.
At-least-once delivery. MaestroHub acknowledges an input message only after the run's trigger event is stored, so the edge hub keeps a message until then and a message can arrive twice after a reconnect. Deduplicate on $trigger._metadata.sys_mid where that matters.
No missed configuration. With Sync Full Twin (the default), the twin trigger delivers the full desired properties when the pipeline is enabled, and again after a reconnect if they changed while MaestroHub was away. Each desired version is delivered once: a patch and a resync of the same version never both run.
Refused subscriptions are reported. If the edge hub refuses a subscription, it fails with an error naming the filter instead of silently never firing.
Configuration Options
Parameters
| Parameter | Type | Default | Required | Constraints | Description |
|---|---|---|---|---|---|
| Connection ID | string | "" | Yes | -- | Azure IoT Edge connection profile to use. |
| Function ID | string | "" | Yes | -- | A Receive on Input function (input trigger), a Module Twin Desired Changes function (twin trigger) or a Receive Direct Method function (method trigger) of the connection. |
| Trigger Mode | select | "always" | No | always / onChange | onChange: the input trigger suppresses a body identical to the last one on the same input; the twin trigger suppresses a repeated version. The method trigger has no Trigger Mode: every call runs. |
| Enabled | boolean | true | No | -- | Enable or disable the trigger. |
The function carries the rest: the Input Name (or * for every input), or the twin Property Filter and Sync Full Twin switch.
Output
Input trigger
The message body is under result; everything else is under _metadata, as strings.
{
"_metadata": {
"type": "azureiotedge_input_trigger",
"connectionId": "7b2a0cf0-c9f5-444c-835e-fc2cb957be07",
"functionId": "85bab7a5-70da-4bb3-9639-9a59a414c01f",
"protocol": "azureiotedge",
"inputName": "alerts",
"sys_mid": "m-8121",
"sys_cmid": "anomaly-detector",
"sys_cdid": "factory-edge-01",
"attr_line": "3",
"timestamp": "2026-09-28T10:30:00.123456789Z"
},
"result": { "anomaly": true, "line": 3 }
}
| Field | Expression | Description |
|---|---|---|
| Message Body | $trigger.result | The message body (parsed JSON object, or the raw value) |
| Input Name | $trigger._metadata.inputName | The input the route delivered to |
| System properties | $trigger._metadata.sys_<name> | One per system property: sys_mid (message id), sys_cid (correlation id), sys_cdid (sending device), sys_cmid (sending module), sys_ct (content type), sys_ce (content encoding) |
| Application properties | $trigger._metadata.attr_<name> | One per application property, for example $trigger._metadata.attr_line |
| Protocol | $trigger._metadata.protocol | Always azureiotedge |
| Connection ID | $trigger._metadata.connectionId | The connection profile used |
| Function ID | $trigger._metadata.functionId | The function that received the message |
| Trigger Type | $trigger._metadata.type | Always azureiotedge_input_trigger |
| Timestamp | $trigger._metadata.timestamp | When MaestroHub received the message |
Twin trigger
result is the desired-properties patch, or the full desired properties on a resync, including $version.
{
"_metadata": {
"type": "azureiotedge_twin_trigger",
"connectionId": "7b2a0cf0-c9f5-444c-835e-fc2cb957be07",
"functionId": "85bab7a5-70da-4bb3-9639-9a59a414c01f",
"protocol": "azureiotedge",
"version": "4",
"isFullTwin": "false",
"timestamp": "2026-09-28T10:30:00.123456789Z"
},
"result": { "sampling": { "line3": "5s" }, "$version": 4 }
}
| Field | Expression | Description |
|---|---|---|
| Desired properties | $trigger.result | The patch, or the full desired properties when isFullTwin is "true" |
| Version | $trigger._metadata.version | The desired-properties version |
| Full twin | $trigger._metadata.isFullTwin | "true" for the full desired properties delivered on enable or after a reconnect, "false" for a patch |
| Protocol | $trigger._metadata.protocol | Always azureiotedge |
| Connection ID | $trigger._metadata.connectionId | The connection profile used |
| Function ID | $trigger._metadata.functionId | The function that received the change |
| Trigger Type | $trigger._metadata.type | Always azureiotedge_twin_trigger |
| Timestamp | $trigger._metadata.timestamp | When MaestroHub received the change |
Method trigger
result is the call's JSON payload.
{
"_metadata": {
"type": "azureiotedge_method_trigger",
"connectionId": "7b2a0cf0-c9f5-444c-835e-fc2cb957be07",
"functionId": "85bab7a5-70da-4bb3-9639-9a59a414c01f",
"protocol": "azureiotedge",
"methodName": "setRecipe",
"requestId": "17",
"deadline": "2026-09-28T10:30:25Z",
"timestamp": "2026-09-28T10:30:00.123456789Z"
},
"result": { "recipe": "B7" }
}
| Field | Expression | Description |
|---|---|---|
| Call payload | $trigger.result | The JSON the caller sent |
| Method | $trigger._metadata.methodName | The method called |
| Request ID | $trigger._metadata.requestId | The call to answer — map it into the Respond to Direct Method node |
| Deadline | $trigger._metadata.deadline | When the response budget runs out |
| Protocol | $trigger._metadata.protocol | Always azureiotedge |
| Connection ID | $trigger._metadata.connectionId | The connection profile used |
| Function ID | $trigger._metadata.functionId | The function that received the call |
| Trigger Type | $trigger._metadata.type | Always azureiotedge_method_trigger |
| Timestamp | $trigger._metadata.timestamp | When MaestroHub received the call |
Answering in time. IoT Hub does not tell the module how long the caller waits, so the Receive Direct Method function has a Response Budget (25 s by default, below IoT Hub's default 30 s call timeout). If the pipeline has not answered within it, the caller gets 504 with the reason, unless Answer 504 When Late is off. A call for a method no pipeline handles is answered 501 at once. A call still waiting when MaestroHub's connection to the edge hub ends — including the reconnect that renews its token, at 80% of the token lifetime — is answered 503; retry it.
Every call runs its pipeline: the method trigger never suppresses a repeated call, whatever the Trigger Mode.
$trigger._metadata.isFullTwin is the string "false", which is truthy in an expression. Compare it explicitly: {{ $trigger._metadata.isFullTwin == "true" }}.
Usage Examples
Act on an AI module's results
Scenario: an anomaly-detection module sends {"anomaly":true,"line":3} on its output alerts.
Configuration: route FROM /messages/modules/anomaly-detector/outputs/alerts INTO BrokeredEndpoint("/modules/maestrohub/inputs/alerts"); a Receive on Input function with Input Name alerts. The pipeline writes a stop bit to the PLC when $trigger.result.anomaly is true.
Configuration from IoT Hub
Scenario: operations sets {"sampling":{"line3":"5s"}} in the module twin's desired properties on 200 devices.
Configuration: a Module Twin Desired Changes function with Sync Full Twin on. The pipeline applies $trigger.result.sampling and reports the applied value back with the Twin Report node.