Functions

Functions are the core building blocks for application logic in Heisenware. They are visual representations of actual code that allow you to fetch data, process information, manage databases, and control devices.

All functions follow the same anatomy. Each part of it is represented by a colored box.

  • A function merging two (or more) objects
  • Input(s): Arguments the function needs to work (e.g., a number to calculate or a string to send). If a function does not require an input, the box is not shown.

  • Trigger: The signal that tells the function to execute (e.g., a button click or a data change).

  • Output: The result of the operation, also available for the next step in your flow.

  • Extensions (optional): Add-ons to filter, record, or modify data on the fly.

Types of functions

There are four main types of functions, defined by how they handle context (state).

Type
Description

Static functions

Standalone utilities that process data without needing context.

(e.g., mergeObjects, mapRange, echo)

Member functions

Actions linked to a specific Instance you have created. They use the unique connection settings stored in that instance. (e.g., read, write, publish)

Create function

Constructors used to configure and initialize a new instance.

(create)

Delete function

Destructors used to remove an instance and free up system resources. (delete)

circle-info

💡 Concept example: The OPC UA Client Class

  • Class: The generic blueprint for OPC UA Client.

  • Create function: You use the create function to configure a connection (IP, port, security), resulting in an instance named myMachine.

  • Member functions: You use the connect and read functions belonging to myMachine to get data. It works because it knows which server to talk to based on the instance.

Working with functions on the canvas

  • Add: Drag a function from the library in the left panel onto the canvas.

  • Link: Drag an output of one function to the input or trigger of another to create a flow.

  • Read docs: Click on the small info icon next to a function's name to open its built-in documentation panel.

  • Comment: Right-click a function and select Comment to add context for your team.

  • Delete: Select the function and press Delete on your keyboard or click the trash icon.

circle-exclamation

Status Indicators

Each function has a colored status indicator next to its name. Hover over the indicator for details.

  • 🟢 Green: Ready / OK.

  • 🔵 Blue: Execution is slow (> 2 seconds).

  • 🟡 Yellow: Object/Instance does not exist yet.

  • 🔴 Red: Error or exception occurred.

  • Gray: Function is offline/unavailable.

Inputs & data configuration

Inputs determine how a function behaves. You can provide data via three sources:

  1. Static data: Fixed values typed directly into the input box (configured via YAML) or set via a configuration panel (opened by clicking the blue arrow icon inside the input).

  2. Dynamic logic: Data passed from the output, modifier, or filter of a previous function.

  3. UI binding: Live data from a widget (e.g., a text field value).

Function with object input in YAML format

YAML input

We use YAML for configuration because it is human-readable and handles complex data structures easily.

chevron-rightA Quick Cheat Sheethashtag

This guide will help you provide data in the correct format.

Basic values (Scalars)

Simple data types can usually be typed without quotes.

  • Strings: Hello world. Use quotes if the text looks like a number or boolean (e.g., '123', 'true').

  • Numbers: 101 or 3.14159.

  • Booleans: true or false.

  • Null: null (represents an empty or non-existent value).

Lists (Arrays)

A collection of items.

  • Block Style: Start each item on a new line with a hyphen.

  • Compact Style: Enclose in brackets.

Objects (Key-Value Maps)

Data grouped under specific keys.

  • Block Style: Each key-value pair gets its line. Use indentation for nesting.

  • Compact Style: Enclose comma-separated key-value pairs in curly braces.

Multiline strings

Essential for large blocks of text, code, or templates.

  • Literal Style (|): Preserves every line break exactly. Perfect for code (e.g., ZPL).

  • Folded Style (>): Use the greater-than symbol to convert single newlines into spaces. This is great for writing long paragraphs that you want to be read as a single line of text. Blank lines will be kept as newlines.

circle-info

Right-click an input box to switch between YAML and HTML view, or to set an input as a Secret (masking the value).

Special inputs: Callbacks

Functions with an on prefix (e.g., onMessage) use Callback inputs. These listen for external events (like an incoming MQTT message) and provide that data via a specific output nested inside the input box.

A function with a callback listening for incoming MQTT messages in binary format

Triggers & execution logic

The trigger determines when a function runs.

Trigger sources

  • Data-driven: Link an output, modifier, or filter to a trigger to run on change, update, or true.

  • UI events: Link a widget event (like a button's onClick) to the trigger.

  • App lifecycle: Right-click the trigger box to set execution on App Start (once) or on App Stop.

  • Periodically: Right-click the trigger box to set a recurring execution interval.

  • Page load: Drag a page onto the trigger box to execute the function when that page loads.

  • Manual (Test): Click the trigger icon on the canvas to force-execute the function during development.

Use page load to execute a function
Use a button click to execute a function

Sequential processing (Looping)

To process an array item-by-item (like a for loop):

  1. Right-click the trigger.

  2. Select Process one by one.

  3. Choose the input containing the array. The trigger will change to a dotted line, indicating it will run once for every item in the list.

chevron-rightExample: Merging an element into an arrayhashtag

A common use case for sequential processing is merging a single element into each sub-array of a larger array.

The image below illustrates a combine function where the trigger is configured to Process One By One on its first input (On arg 1). As a result, the function executes for each sub-array, and the singular element from the second input is merged into both.

Delayed execution

You can add a delay (0.1s to 2.0s) to any trigger to manage timing, such as waiting for a UI animation to finish before fetching data.

Outputs & chaining

The output returns the result of the function's execution. It is the primary way to pass data and control logic in your application.

Return data types

Depending on the function, the output can be:

  • Standard data: JSON objects, strings, numbers, or arrays.

  • Binary content: Files or images (e.g., for PDF generation or camera captures).

  • Success flags: A simple true/false boolean indicating if an operation (like a database write) succeeded.

Backend logic (Flows)

You can link an output to another function to create a chain of logic:

  • Pass data: Connect Output → Input. The result of Function A becomes the argument for Function B.

  • Control flow: Connect Output → Trigger. Function B will only execute once Function A completes successfully.

UI interaction

You can link an output directly to the frontend to drive the user interface:

  • Visualize: Connect to a widget (e.g., a Chart or Value Box) to display the data.

  • Control: Connect to a widget (e.g., a Button) and select the specific property you want to control (e.g., disabled or toggle) to dynamically change its behavior.

  • Navigate: Connect to a Page Switch trigger to automatically change screens based on logic.

Function extensions

Extensions are tools attached directly to a function's output. They allow you to modify, filter, record, or handle errors on the fly without adding separate function blocks.

One function with three extensions

Working with extensions

  • Add: Click the + icon on an output and select the desired type. You can add multiple parallel extensions to the same output.

  • Chain: You can add an extension to the output of another extension to create a multi-step pipeline (e.g., filter data then modify it).

  • Delete: Right-click an extension and select Delete.

Adding extensions

Data binding (connecting to UI)

Functions communicate bidirectionally with the frontend widgets via data binding.

  • Input binding: Link a widget property (e.g., formData) to a function input.

  • Trigger binding: Link a user action (e.g., on button click) to a function trigger.

  • Output binding: Link a function result to a widget property (e.g., data) to update the UI.

Advanced addressing

Any function inherently addresses the corresponding backend code using a specific structure. To view or edit this, right-click the function name and select Use Dynamic Address.

Right click the function name and choose e.g. Use Dynamic Address

This reveals the "path" to the underlying code, consisting of up to three boxes:

<Agent/Service> <Class> [Instance]

  • Box 1 (Agent/Service): The program executing the function. This can be a generic internal service (e.g., "Utility Functions") or a specific Edge Agent running on a machine.

  • Box 2 (Class): The actual name of the underlying code class in the programming language (e.g., Busylight, Barcode, OpcuaClient).

  • Box 3 (Instance): The specific instance name (e.g., server1). This box only appears for member functions. Static functions (like generateBarcode) do not belong to an instance, so this box is hidden.

Addresses of a static function and a member function

You can edit this address to your liking. If you switch back to the regular (short) view, your changes are kept.

circle-info

💡 Use Case: Swapping Agents

This feature is essential when moving logic between environments (e.g., from a test device to a production machine).

Instead of rewiring your flow, simply update the Agent name (Box 1) to match the new Edge Agent.

You can even use search-and-replace to update the agent name across multiple functions at once. This works even on addresses that are not explicitly set to "Dynamic" view.

Last updated