Skip to main content
Version: 3.0 (next)

CoAP Observe Trigger Node

Start a pipeline each time an observed CoAP resource changes, with its decoded value, response code and Observe sequence number, without polling.

Starts on
Each notification of an observed resource
Function
Observe
Output
One event per notification
Dedup
A re-registration does not repeat the last value

Overview​

The CoAP Observe Trigger Node automatically initiates MaestroHub pipelines whenever an observed resource on a CoAP device or gateway sends a notification. Unlike the CoAP GET node, which reads a resource inside an already-running pipeline, the CoAP Observe Trigger starts a new pipeline execution for each notification, enabling fully event-driven automation without polling.

CoAP Observe (RFC 7641) turns a resource into a subscription: MaestroHub registers as an observer once, and the device sends a notification with the current value at registration and then on every change. Each notification carries its response code, its payload in a declared Content-Format, and an Observe sequence number.


Core Functionality​

What It Does​

1. Event-Driven Pipeline Execution Start pipelines automatically on every notification of the resource the Observe function names. Latency is set by the device, not by any polling interval.

2. Content-Format Aware Payloads The notification's payload is decoded by the Content-Format the device declared: text as a string, JSON and CBOR as a value, anything else (or no declared format) as base64, with valueEncoding saying which. A payload that does not parse as its declared format is reported as a failure, never guessed. See Content-Format: how payloads are read.

3. Automatic Subscription Lifecycle The observation is registered when the pipeline becomes enabled and cancelled when it's disabled. While it runs, it is registered again by itself whenever it is lost.

4. No Repeat on Re-Registration Every notification carries the time MaestroHub received it and its Observe sequence number, so two notifications of the same value are two distinct events, and each one starts a run. The one exception: when MaestroHub registers again (after a reconnect or an overdue notification), the device answers with its current value, and that value is not emitted again if it is the one already delivered.


How CoAP Observe Triggering Works​

CoAP Observe triggering is fundamentally different from on-demand reads:

AspectGETObserve (Trigger)
ModelRequest-response (pull)Event-driven (push)
ExecutionOne request per callOne event per notification
LifecycleStatelessAn observation registered on the device, kept alive by MaestroHub
Use CaseOn-demand reads, resources that cannot be observedReal-time change detection, telemetry

When you configure a CoAP Observe Trigger:

  1. MaestroHub sends a GET with the Observe option for the function's resource path, from the connection's own UDP socket.
  2. The device answers with the current value, which is the first event, and registers the observer. A path that does not exist or is refused fails the subscription with the device's code, and the subscription is retried. A resource that answers without the Observe option is not observable, and the subscription fails with that reason.
  3. The device sends a notification to the same socket on every change. MaestroHub never listens on a known port: notifications return to the ephemeral port the registration came from.
  4. Each notification that decodes is one trigger event, and the pipeline executes with it available as $trigger.

Reconnection Handling​

MaestroHub keeps the observation alive on its own.

Automatic Recovery​

The observation is registered again when:

  1. The connection is lost: the socket is replaced on reconnect, and the observation is registered on the new one.
  2. The device ends it: an error notification, or a final notification without the Observe option.
  3. A notification is overdue: nothing has arrived for the last notification's Max-Age (60 seconds when the device sends none) plus 10 seconds. RFC 7641 lets a client assume the observation was lost at that point; a device that restarted has forgotten its observers.

While the device stays away, registration is retried with backoff from 0.5 seconds up to 30 seconds.

When the observation cannot be kept (the link stays lost, a re-registration is refused or unanswered, the device ends it with an error code, or a notification does not parse as its Content-Format), the trigger fires once per outage with quality bad and the cause under error (see Output Data Structure). The first good notification afterwards is the recovery event, with quality good, delivered even when the value has not changed. A reconnect that restores the observation within half a second raises no event at all.

What This Means for Your Workflows​

ScenarioBehavior
Transient network errorOne bad event for the outage; a good event when the observation is back
Device restartThe device forgets its observers; MaestroHub registers again once the notification is overdue
Quiet resourceRegistered again about every Max-Age + 10 seconds; an unchanged value starts no run
Edited Observe functionSubscribing again replaces the observation, so the new path takes effect
MaestroHub restartAll triggers for enabled pipelines are restored on startup
Minimising data loss

Changes the device makes while the link is down are not notified. The re-registration after the outage delivers the resource's current value, so the pipeline catches up on state, but not on the intermediate changes.


Configuration Options​

Basic Information​

FieldTypeDescription
Node LabelString (Required)Display name for the node on the pipeline canvas. Must be non-empty (trimmed).
DescriptionString (Optional)Explains what this trigger initiates.

Configuration​

The trigger configuration is organized across two tabs in the UI: Parameters and Settings.

ParameterTypeDefaultRequiredDescription
ConnectionConnection ID""YesThe CoAP connection profile to observe through. Filtered to CoAP connections only.
Observe FunctionFunction ID""YesThe function that names the resource to observe. Filtered to coap.observe function types on the selected connection.
EnabledBooleantrueNoWhen disabled, the subscription is not created even if the pipeline is enabled.
Function Requirement

The selected function must be an Observe function type (coap.observe). GET, PUT, POST and DELETE functions cannot be used with CoAP Observe Trigger nodes.

If the selected connection has no Observe functions yet, the node configuration panel surfaces a link straight to the connection so you can author one.

Observe Function Configuration​

The selected function (authored in the Connect module) controls which resource fires the trigger:

SettingDescription
Resource PathPath of the observable resource, e.g. /sensors/temp
QueryOptional query sent with the registration, e.g. unit=C
AcceptAsk the device for this Content-Format in its notifications. Empty = the device's default.

See Observe for the full function reference.

Sample Payload​

The Parameters tab also holds a Sample Payload editor and a Sample Quality picker. When you run the node with Test Node in Sandbox mode, the trigger emits the sample payload as result instead of waiting for a real notification, so you can validate downstream nodes before a device is wired up. When the editor is empty, a built-in sample notification is used. Sample Quality sets the quality the sample reports in $trigger._metadata.quality, so a quality-aware pipeline can be tested with a good, uncertain or bad sample. The live subscription and the node's Fire Trigger action do not use the sample.

{
"path": "/sensors/temp",
"code": "2.05",
"status": "Content",
"contentFormat": "application/json",
"value": { "t": 21.5 },
"valueEncoding": "json",
"bytes": 10,
"observe": 17,
"etag": "a1b2",
"maxAge": 30,
"serverTimestamp": "2026-10-20T10:14:03.240Z"
}

Settings​

Description

A free-text area for documenting the node's purpose and behavior. Notes entered here are saved with the pipeline and visible to all team members.

Execution Settings

SettingOptionsDefaultDescription
On ErrorPipeline Default / Stop Pipeline / Continue ExecutionPipeline DefaultBehavior when the node fails.

Output Data Structure​

When the device sends a notification and triggers pipeline execution, the trigger produces a structured output with two top-level keys: _metadata and result. One event is emitted per notification.

Output Format​

{
"_metadata": {
"type": "coap_trigger",
"protocol": "coap",
"connectionId": "bf29be94-fc0a-4dc4-8e5c-092f1b74eb4b",
"functionId": "aef374c3-aa2b-454e-aabc-5657faac5950",
"path": "/sensors/temp",
"code": "2.05",
"contentFormat": "application/json",
"observe": "17",
"serverTimestamp": "2026-10-20T10:14:03.240Z",
"quality": "good",
"timestamp": "2026-10-20T10:14:03.240123456Z"
},
"result": {
"path": "/sensors/temp",
"code": "2.05",
"status": "Content",
"contentFormat": "application/json",
"value": { "t": 21.5 },
"valueEncoding": "json",
"bytes": 10,
"observe": 17,
"etag": "a1b2",
"maxAge": 30,
"serverTimestamp": "2026-10-20T10:14:03.240Z"
}
}

result Fields​

Keys that only some notifications carry are absent when the notification did not carry them, never filled with a placeholder.

FieldTypeDescription
pathstringThe observed resource path.
codestringThe notification's response code as class.detail, e.g. 2.05.
statusstringThe response code's name, e.g. Content.
contentFormatstringThe Content-Format the device declared. Present only when the notification carried a Content-Format option.
valueanyThe payload: text as a string, JSON and CBOR as a value, anything else (or no declared format) as base64. Present only when the notification carried a payload.
valueEncodingstringtext, json or base64: how value represents the payload. Present with value.
bytesnumberThe payload's size on the wire, in bytes.
observenumberThe Observe sequence number. Present on every notification but a final one, which ends the observation.
etagstringThe ETag option, as hex. Present when the notification carried one.
maxAgenumberThe Max-Age option: how many seconds the value stays fresh. Present when the device sent one other than the 60-second default.
serverTimestampstringWhen MaestroHub received the notification, UTC. CoAP carries no device time, so this is the only time.

_metadata Fields​

Every _metadata value is a string, including the numeric ones.

FieldTypeDescription
typestringAlways "coap_trigger".
protocolstringAlways "coap".
connectionIdstringThe CoAP connection profile ID.
functionIdstringThe Observe function ID.
pathstringThe observed resource path.
codestringThe notification's response code, e.g. "2.05".
contentFormatstringThe declared Content-Format. Present only when the device declared one.
observestringThe Observe sequence number, as a string ("17"). Present on every notification but a final one.
serverTimestampstringISO 8601 / RFC 3339, UTC; when MaestroHub received the notification.
qualitystringgood on a notification that arrived and decoded: CoAP itself carries no quality. bad on a failure event: once per outage, when the observation cannot be kept, the trigger fires with quality: "bad" and the cause under error. Its result is the last notification this trigger delivered (an empty object if none had arrived yet). The next good notification is the recovery event. A UNS Publish node downstream inherits the verdict.
quality_reasonstringOnly on a failure event: comm_error. A UNS Publish node downstream forwards it, so the stored sample reads bad · comm_error rather than just bad.
errorstringOnly on a failure event: why the observation was lost, e.g. connection to the CoAP server was lost, or the device's error code.
timestampstringISO 8601 / RFC 3339 (nanoseconds); when the trigger event was created, UTC.

Referencing in Downstream Nodes​

Use expressions to access trigger data in subsequent nodes:

  • $trigger.result.value: the decoded payload
  • $trigger.result.valueEncoding: text, json or base64
  • $trigger.result.contentFormat: the declared Content-Format
  • $trigger.result.code: the response code, e.g. 2.05
  • $trigger.result.status: the response code's name
  • $trigger.result.path: the observed resource path
  • $trigger.result.bytes: the payload's size
  • $trigger.result.observe: the Observe sequence number, as a number
  • $trigger.result.etag: the ETag, as hex
  • $trigger.result.maxAge: seconds the value stays fresh
  • $trigger.result.serverTimestamp: when MaestroHub received it
  • $trigger._metadata.path: the path as a string, handy for routing on a topic path
  • $trigger._metadata.quality: good, or bad on the once-per-outage failure event
  • $trigger._metadata.connectionId: connection profile used
  • $trigger._metadata.functionId: Observe function used

Validation Rules​

Parameter Validation​

Node Label

  • Must not be empty
  • Must not consist only of whitespace

Connection ID

  • Must be provided and non-empty
  • Must reference a valid CoAP connection profile

Function ID

  • Must be provided and non-empty
  • Must reference a valid Observe (coap.observe) function
  • Function must belong to the specified connection

Enabled Flag

  • Must be a boolean if provided

Usage Examples​

Sensor Telemetry to the UNS​

Key configuration

  • Label: Room Temperature
  • Connection: Building A Gateway
  • Function: Observe on /sensors/temp, Accept application/json
  • Enabled: true
  • Settings: on error continue

Downstream usage: $trigger.result.value for the reading, $trigger._metadata.path to build the topic path, $trigger._metadata.quality for the quality band. An outage arrives as one bad event that the UNS stores with its quality.

Alarm Resource Monitoring​

Key configuration

  • Label: Pump Alarms
  • Connection: Pump Station Controller
  • Function: Observe on /alarms/active
  • Enabled: true
  • Settings: on error stop

Downstream usage: $trigger.result.value for the alarm document, $trigger.result.serverTimestamp for when it arrived. Check $trigger._metadata.quality first, so a lost observation is not read as "no alarms".

Binary Payloads​

Key configuration

  • Label: Vibration Frames
  • Connection: Sensor Node 12
  • Function: Observe on /vibration/frame
  • Enabled: true

Downstream usage: a device that declares application/octet-stream, or no Content-Format, delivers $trigger.result.value as base64 with $trigger.result.valueEncoding base64; decode it in a JavaScript node.


Best Practices​

Subscription Design​

  • Observe what changes, poll what does not. A resource that is not observable fails the subscription; read it with a CoAP GET on a Schedule trigger instead.
  • Set Accept when a device can answer in more than one Content-Format, so value always has the same shape.
  • One resource per Observe function. Split unrelated resources into separate functions and pipelines.

Designing for Reliability​

PracticeRationale
Check quality before acting on a valuebad means the observation was lost, or a notification did not decode (the failure event)
Branch on valueEncoding, not on the value's typeIt always says how value represents the payload
Expect a re-registration about every Max-Age + 10 seconds on a quiet resourceIt keeps the observation alive across a device restart; an unchanged value starts no run

Error Handling Strategies​

For Critical Workflows:

  • Set On Error to stopPipeline
  • Monitor pipeline execution failures via the Health dashboard
  • Implement alerting for stopped pipelines

For Best-Effort Processing:

  • Set On Error to continueExecution
  • Log failed executions for later analysis
  • Ensure downstream nodes handle partial failures gracefully

Performance Considerations​

ScenarioRecommendation
Fast-changing resourcesEvery notification starts a run; ask the device for a minimum notification interval if it supports one (often a query such as pmin=5)
Many observed resourcesOne connection carries every observation of a device on its one socket; spread unrelated devices across connections

Enable vs. Disable​

  • Use the trigger's Enabled parameter to temporarily pause monitoring without changing pipeline state
  • Disable triggers during device maintenance to avoid the failure and recovery events a restart produces
  • Document the reason for disabled triggers in the node's Description field