← All documentation
Guide

Logic Modules

Download PDF

A merger: when an input changes, its filter decides on the new value, and an accepted value is written to the output

Some modules never talk to the outside world. They work on the variables inside an instance, doing what a formula cannot. This guide covers them: what each one is for, how to configure it, and what to watch out for.

Module What it does Typical use
Merger Writes to one output the value of whichever input changed last, when a filter accepts it A setpoint written from several places; redundant meters; the latest of several messages

Merger

A formula recomputes from all of the variables it reads whenever one of them changes, but it never learns which one changed. "Take the value of whichever input changed last" therefore cannot be written as a formula. The MERGER module does exactly that: the engine tells it which of its inputs changed, it asks its filter about the new value, and when the filter accepts it, the value is written to the output.

Setting Meaning
Inputs The variables whose changes the merger takes
Filter An expression that decides whether a change is taken. Empty means every change is taken
Output The variable that receives the accepted values

The filter

While the filter runs, the new value of the input that changed is available as _VALUE_. Every other variable is read by its own code, the output included, so a filter can compare the new value with the current output or depend on a mode variable.

The filter returns What happens
true The value is written to the output
false, or no value Nothing is written
Anything else Nothing is written, and a warning is logged
An error Nothing is written, and a warning is logged

A filter that reads a variable which has never held a value fails, as a formula would. Give such a variable an initial value.

Rules

Messages

A merger logs its problems as [name][LEVEL][CODE] text, once when a problem first appears and again only when its text changes. After a warning, the next change handled without a problem logs [name][INFO][RECOVERED] Recovered. All texts are in English.

When Level Text
Start: the merger does not run ERROR No inputs
ERROR No output
ERROR Input {input} is not a variable
ERROR Output {output} is not a variable
ERROR Filter does not compile: {reason}
Start: the merger runs WARNING Variable _VALUE_ has the name of the bound value, so the filter cannot read it
WARNING Input {input} ({type}) cannot be assigned to output {output} ({type})
While running WARNING Filter failed for {input}: {reason}
WARNING Filter returned {type}, not a boolean
WARNING Output {output} refused {value}: {reason}
WARNING Writing output {output} failed: {reason}
WARNING Processing {input} failed: {reason}

A merger that cannot run never stops the engine: the other modules start as usual.

[!WARNING] A merger has no loop protection. A loop that writes the same value back ends by itself, because an unchanged value goes no further. A loop that changes the value on the way, such as a formula SP + 1 feeding one of the merger's own inputs, never ends. Check that the output does not lead back to an input.

Also keep in mind:

Example. A level setpoint written from a panel and by a remote system, taken only when it is within the tank's limits:

Inputs   SP_LIT_301_HMI, SP_LIT_301_REMOTE
Filter   _VALUE_ != null && to_double(_VALUE_) >= 0 && to_double(_VALUE_) <= 4.5
Output   SP_LIT_301

Writing 2.0 from the panel sets SP_LIT_301 to 2.0. A remote 5.0 is out of range and changes nothing; a remote 3.5 then sets it to 3.5.

Example. Two redundant flow meters, keeping only plausible readings:

Inputs   FIT_501_A, FIT_501_B
Filter   _VALUE_ != null && to_double(_VALUE_) >= 0 && to_double(_VALUE_) < 500
Output   FIT_501

Example. The latest error from several modules, ignoring a message that was cleared:

Inputs   PLC1_ERROR, MQTT_ERROR, PUSH_ERROR
Filter   _VALUE_ != null && _VALUE_ != ""
Output   LAST_MODULE_ERROR

Example. A pump command from a local switch or from MQTT, where the last one given wins:

Inputs   CMD_LOCAL, CMD_MQTT
Filter   (empty)
Output   CMD_PUMP_1

Next steps