Multilayer Analyzer
Use Multilayer Analyzer when one calculation supplies data to another. Each JavaScript stage has its own definition, enabled state and outputs, with DataStreams connecting the stages.
In this example, A converts a SubNode's 4–20 mA reading to 0–100 °C. B combines that result with an existing Celsius temperature and publishes true only when both are above 80 °C. The scale and threshold are illustrative.
Multilayer Analyzer currently supports JavaScript Analyzers only. Transfer Function is not supported for multilayer processing.
Understand Analyzer Dependencies
A dependency exists when one Analyzer's output DataStream ID is another Analyzer's input DataStream ID:
- A is upstream: It turns the current into a temperature and publishes it to
temperature_a. - The intermediate stream is the connection: B reads the number published to
temperature_a, not A's complete returned JavaScript object. - B is downstream: It combines
temperature_awithtemperature_band publishesboth_abnormal.
There is no separate chaining endpoint or Multilayer type. Both definitions use type: JavaScript; their outputs and inputParameters establish the dependency.
Multilayer connects stages; multi-input combines streams within a stage. A has one input. B has two and uses the waiting rules in Multi-Input Processing. Its paired readings need not have identical source timestamps.
Connect JavaScript Analyzers Through DataStreams
Keep all streams and Analyzers under the same Org and SubNode Device ID:
| Stream | Producer | Consumer |
|---|---|---|
analog_current, numeric mA | Existing SubNode source | A |
temperature_a, double, °C | A | B |
temperature_b, numeric °C | Existing source | B |
both_abnormal, boolean | B | Your application |
- Prepare the existing current and second-temperature inputs. Create unbound destinations for
temperature_aandboth_abnormal. - Configure A to read the current and write
temperature_a, selecting$.temperatureand$.timestampfrom its result. - Configure B so one input ID is exactly A's temperature output ID; bind the other to the existing second temperature. B writes a separate Boolean destination using
$.bothAbnormaland$.timestamp. - Enable each Analyzer through its own action. Check new values after both are enabled; enabling B does not enable A.
The JavaScript guide provides both scripts and mappings. End-to-End Scenario supplies the full resource preparation and creation requests.
Check the connection: Get Analyzer must show the same actual UUID in A's temperature output and B's corresponding input. Matching names alone does not connect the definitions.
Example: Calculate a Value and Classify the Result
Follow one illustrative set of readings through the stages:
| Point in the chain | Value | Why |
|---|---|---|
| Current input | 17 mA | The SubNode already reports mA. |
A's temperature_a | 81.25 °C | (17 - 4) * 100 / 16. |
Existing temperature_b | 90 °C | The second input to B. |
B's both_abnormal | true | Both temperatures are above 80 °C. |
If the current becomes 16 mA, A produces 75 °C. Paired with B's 90 °C input, the final indicator is false because only one temperature is abnormal.
These are evaluations of paired readings, not a historical aggregate or a guarantee of simultaneous sampling. The standalone Transfer Function example writes to temperature_tf; it is independent of A's temperature_a destination and is not a stage in this chain.
Check the Result and Troubleshoot
- GET both definitions and confirm
isEnabled: true. A successful enable response is not evidence of output. - Check the current input, A's temperature and the existing second temperature using Get Latest Value.
- Check the final Boolean. A preserves the current sample's timestamp; B's script uses the later of its two input timestamps. Match those sample times before comparing values from separate queries.
Check the result: 17 mA and 90 °C produce 81.25 °C and true; 16 mA and 90 °C produce 75 °C and false, for the corresponding paired samples.
| Observation | Check |
|---|---|
| A has no new temperature | Current reporting, mA units, the example's valid 4–20 mA range, A's state and mapping. |
| A has a result but B does not | The second temperature, B's state and input UUIDs, input-collection policy, script and paths. |
B publishes false | Compare the actual paired temperatures. false is a valid evaluated result; missing data does not imply false. |
| Results seem inconsistent | Match timestamps; separately fetched latest values can represent different samples. |
| A stored value remains after disabling A | Check its sample time. An existing value does not show that A continues to produce. |
For script and budget issues, follow the JavaScript troubleshooting checks. Disable a stage before updating it, review downstream stream references, then re-enable and verify new results at each stage.
Dependency Limits
The API checks the resulting dependencies when you create, update or partially update an Analyzer:
| Rule | What it means for your chain |
|---|---|
| JavaScript only | Use JavaScript Analyzers for the supported multilayer workflow. |
| Same Org and device | Each input and output stream must resolve under the target device. This workflow does not join streams from different devices. |
| At most five Analyzers on one path | Count Analyzers, not DataStreams or arrows. A -> B -> C -> D -> E is five stages; adding a sixth exceeds the limit. It is not a five-Analyzer total across unrelated chains. |
| Disabled definitions still count | Disabling a stage stops its evaluation but does not remove its saved dependency links. It does not make room for a sixth stage. |
| No feedback loops | An Analyzer cannot use its own output as its input, directly or through other Analyzers. A graph that loops back is rejected. |
| One producer per output stream | B can read a stream A produces, but B must write to its own available destination. A stream can be read by more than one downstream Analyzer. |
A dependency that exceeds the depth limit or closes a cycle is rejected with 400 Bad Request. An output that already has a source can cause 409 Conflict. Check the returned error details and saved stream bindings before changing the definition; disabling a conflicting producer alone does not release its output assignment.
Multilayer does not remove each stage's input, script or execution limits. Check those limits in the JavaScript guide when designing each stage, then verify the complete path through its intermediate DataStreams.