Timer New in 1.0.4
Puts time between messages. It can hold a message back, pulse a value and put it back, repeat a message on a cadence, count down to a deadline, or say something when a message that should have arrived did not.
Type: timer · Category: Common · Ports: one input · one output


When to use it
- Watching a heartbeat, so silence raises an alarm instead of passing unnoticed
- Pulsing a tag — set it to 1, then back to 0 five seconds later — from one message
- Waiting until a burst of messages settles before writing anything
- Counting down a permit, a cure time or a hold, with a warning before it expires
The Timer is the only node that defers. It never blocks the pipeline: it hands a deadline to the runtime and returns, and when that deadline matures the runtime re-enters the pipeline at this node and the message goes out. Every fire is its own independent run, which is why a repeating timer needs no loop in a graph that does not allow them.
Modes
| Mode | On input it… | Later it… |
|---|---|---|
Pulse (oneshot) | sends the first payload straight away | sends the second payload after the duration |
Watch for silence (watchdog) | sends nothing, and restarts the clock | sends an alert only if the duration passes with no message |
Wait until quiet (debounce) | holds the newest message and restarts the clock | sends that one message once things go quiet |
Delay every message (delay) | queues the message | sends each one, in order, after its own wait — nothing is discarded |
Count down / stopwatch (counter) | starts counting | sends a warning at the threshold, then zero — or, counting up, the elapsed time when stopped |
Repeat until stopped (loop) | starts repeating | re-sends the incoming message every duration, until a STOP or a limit |
Every mode except Delay holds at most one pending timer per key, so a fast input cannot accumulate work — a new message replaces the pending timer rather than adding to it. Delay is the exception because letting every message through is the whole point of it, which is also why it is the only mode with a queue depth to cap.
Settings
Timing
| Setting | Key | Default | Purpose |
|---|---|---|---|
| Mode | mode | oneshot | One of the six above. |
| Duration | duration / durationUnit | 5 seconds | How long the timer waits. Milliseconds, seconds, minutes or hours. |
| First payload | initialPayload | 1 | Pulse only. Sent immediately. |
| Second payload | finalPayload | 0 | Pulse only. Sent after the duration. |
| Keep alerting while silent | repeatWhileSilent | off | Watchdog only. On, it alerts every duration until traffic resumes; off, once per silent period. |
| Most messages held per topic | maxQueue | 1000 | Delay only. |
| Direction | direction | down | Counter only. Count down to zero, or up as a stopwatch. |
| Warn with this many seconds left | warningAt | 0 | Counter only. 0 = no warning. |
| Stop after this many repeats | maxIterations | 0 | Loop only. 0 = unlimited. |
| Stop after this long (seconds) | loopTimeout | 0 | Loop only. 0 = unlimited. |
A literal payload is converted on the way out: 1 becomes the number 1 and true becomes a
boolean, so a pulse can drive a numeric tag with no cast node in between. Anything else stays text.
Every node has a Timeout, which bounds how long that node may run. A Timer runs in microseconds and then waits, so the two are unrelated — a one-hour timer does not need a one-hour timeout.
Topics
| Setting | Key | Default | Purpose |
|---|---|---|---|
| Separate timer per topic | septopics | true | Each topic gets its own independent timer. Off, every message shares one. |
| Topic from | topicProperty | topic | What identifies a timer. A dotted path such as payload.device keys on something other than the topic. |
| Maximum topics | maxTopics | 1000 | The node refuses a new key past this, rather than quietly evicting one it is already watching. |
Control
A message can command the timer instead of feeding it. The command is read from a named property and is consumed — it never travels downstream, and a watchdog never counts it as activity.
| Setting | Key | Default | Purpose |
|---|---|---|---|
| Command read from | controlProperty | metadata.timerCmd | Where a command is read from. |
| Command target read from | targetProperty | (empty) | Which timer a command addresses. Empty = the command's own topic. A path such as payload.target lets a command name another one; the value * clears every timer on the node. |
| Duration read from | durationProperty | (empty) | Optional. A path such as payload.seconds lets a message set its own wait, read in the unit chosen under Timing. |
| Accept that duration on | durationOverrideOn | START commands only | Or any message, for a feed that carries its own cadence. |
| Longest allowed duration (seconds) | maxDuration | 86400 | The ceiling any message-supplied duration is held to. |
The five commands are START, STOP, RESET, PAUSE and CONTINUE. Rename any of them in
the config and the old name stops working — which is what makes the word safe to send as ordinary
data once you have. PAUSE holds the time remaining and CONTINUE resumes that; it never
starts a fresh full-length wait.
The default is metadata.timerCmd, not payload, on purpose. The payload is your data channel: a
device that happens to publish the literal text STOP would stop the timer instead of feeding it —
which lets a device silently switch off the watchdog monitoring it. The property panel warns you if
you point the command at the payload.
Example — a watchdog on a pump heartbeat
Each pump publishes to its own topic every few seconds. If one goes quiet for 30 seconds, raise it.
Mode: Watch for silence
Duration: 30 seconds
Keep alerting while silent: off
Separate timer per topic: on
Topic from: topic
Industrial I/O (subscribe Pumps/*) → Timer (watchdog 30s) → Alarm (raise) → Send Email
In — normal traffic. Each message restarts that pump's own clock, and the node emits nothing:
{ "topic": "Pumps/PMP-01", "payload": { "rpm": 1480 } }
{ "topic": "Pumps/PMP-02", "payload": { "rpm": 1502 } }
{ "topic": "Pumps/PMP-01", "payload": { "rpm": 1477 } }
Out — 30 seconds after PMP-01's last message, with PMP-02 still reporting normally:
{
"topic": "Pumps/PMP-01",
"payload": { "event": "elapsed", "durationSec": 30, "topic": "Pumps/PMP-01" },
"metadata": { "timerEvent": "elapsed" }
}
PMP-02 is untouched — its own timer is still running, because Separate timer per topic gives each pump an independent one. The alert synthesises a message rather than replaying the last good reading, which is the point: the interesting fact is that nothing arrived.
With Keep alerting while silent off that is one alert per silent period. The next real message from PMP-01 re-arms the watchdog, and the next silence alerts again.
Example — pulsing a tag for five seconds
Mode: Pulse (send, wait, send again)
Duration: 5 seconds
First payload: 1
Second payload: 0
Inject → Timer (pulse 5s) → Industrial I/O (write Line1/Horn)
Out — two messages from one input, five seconds apart:
{ "payload": 1, "metadata": { "timerEvent": "initial" } }
{ "payload": 0, "metadata": { "timerEvent": "final" } }
Both are numbers, not the strings "1" and "0", so the write lands on a numeric tag with no
conversion step in between.
Reading the output
Every emitted message carries metadata.timerEvent, saying why it fired. The node has one
output port, so route on that value with a Switch rather than looking for a second
socket.
timerEvent | Mode | Means |
|---|---|---|
initial | pulse | The leading edge, sent on input. |
final | pulse | The trailing edge, after the duration. |
elapsed | watchdog | Nothing arrived in time. |
release | debounce, delay | A held message is being let through. |
warning | counter | The countdown reached the warning threshold. |
zero | counter | The countdown reached zero. |
stopped | counter (up) | The stopwatch stopped, carrying the elapsed time. |
repeat | loop | One iteration. Also carries metadata.iteration, and metadata.loopEnded on the last one. |
Watching a timer on the canvas
An armed timer sends the Designer its deadline once, and the node card counts down locally from there. That costs one message per arm and nothing per second — there is no server-side tick, so a node watching 500 topics is as cheap as one watching a single tag.
Gotchas
- A watchdog needs traffic to arm it. It starts watching only once a first message arrives, so a device that never reports at all after a restart is not caught by a watchdog alone — pair it with a scheduled read if you need to detect that.
- CONTINUE only resumes a paused timer. If nothing was paused the node says so and does nothing. It deliberately never falls back to starting a fresh full-length timer, which would look like it worked and then wait the wrong amount of time.
- Watch
maxTopicswhen you key on a value rather than a topic. Keying on something high-cardinality — an order number, a batch id — reaches the limit, and the node then refuses new keys with a warning rather than quietly forgetting one it is already watching. - An unusable duration from a message is ignored and the configured duration is used instead. Refusing to arm because a payload was malformed would stop the monitoring, which is the failure the node exists to prevent. A duration that was clamped or rejected says so in the message metadata.
- A loop is the one mode that produces work with no further input. Set
maxIterationsorloopTimeoutunless you genuinely mean "until someone sends STOP".