A device reports its board, screen, camera and ports from its own credential (16 KB, schema 1, replacing the last report), and the flows are validated against it again. The node panel turns a reported port's config schema into a form, a reported screen is a canvas preset and a touch screen's first report turns Touch friendly on. An offline device node is degraded: amber on the canvas, a warning on Home, never a fault.
161 lines
6.8 KiB
Markdown
161 lines
6.8 KiB
Markdown
# Flows, nodes and messages
|
|
|
|
A **flow** is a group of **nodes** that exchange **messages**. Nodes declare
|
|
what they consume (`requires`) and produce (`provides`); matching message names
|
|
connect them. No wires to draw.
|
|
|
|
## How nodes connect
|
|
|
|
For a Function node, declare input and output ports in its panel, then write
|
|
`process(...)`. Arguments use input port names; the returned dictionary uses
|
|
output port names:
|
|
|
|
```python
|
|
# Node "read": provides temperature
|
|
def process():
|
|
return {"temperature": 18.5}
|
|
|
|
# Node "decide": consumes temperature, provides heat
|
|
def process(temperature, setpoint=21.0):
|
|
return {"heat": temperature < setpoint}
|
|
```
|
|
|
|
Bind both temperature ports to the same message and `decide` follows `read`.
|
|
Here `setpoint` uses a Python default; you can also add it as a node
|
|
[setting](values.md#settings-constants-of-this-node).
|
|
|
|
- Several nodes can produce the same message. Consumers use the latest value.
|
|
- Publishing an input wakes its consumers once their required values are
|
|
available. An upstream node that publishes nothing leaves downstream nodes
|
|
waiting for a new publication.
|
|
- The editor arranges the graph automatically. Keep flows focused and share
|
|
messages between them when needed.
|
|
|
|
### Message names are namespaced
|
|
|
|
In flow `house`, `temperature` becomes `house.temperature`. A dotted name is
|
|
used as written, so another flow can consume it directly. Bind an input port
|
|
named `temperature` to `house.temperature`:
|
|
|
|
```python
|
|
def process(temperature):
|
|
return {"shown": temperature}
|
|
```
|
|
|
|
The canvas shows cross-flow messages as labelled endpoints.
|
|
|
|
## Node types and payloads
|
|
|
|
Function nodes run your Python code. Built-in nodes handle MQTT, HTTP,
|
|
InfluxDB, schedules, filtering and more through forms in their panels. See
|
|
[Node types](../reference/node-types.md).
|
|
|
|
Every port declares a payload type (`dtype`). Values are checked against it,
|
|
and dashboard widgets offer compatible messages. Scalars, structured JSON and
|
|
media references are covered in [Payload types](../reference/payload-types.md).
|
|
|
|
Messages carry JSON. For binary data, store the bytes as an **artifact** and
|
|
publish its reference. `image`, `audio` and `video` are artifact references
|
|
restricted to their media family.
|
|
|
|
### Streaming ports
|
|
|
|
Mark an output **streaming** when it publishes during an execution: progress,
|
|
training loss or media chunks. A Function node can yield values or call
|
|
`fluksio.emit`.
|
|
|
|
Downstream nodes receive each publication in order; message state holds the
|
|
latest value. A batch run records the full series. An output `interval` limits
|
|
live publication without thinning the run's recorded series.
|
|
|
|
### Keeping node code predictable
|
|
|
|
Write Function nodes as functions of their declared inputs and settings.
|
|
Fluksio provides no hidden `context` or global flow store. To remember a value
|
|
between executions, use a message the node reads and writes; see
|
|
[Keeping state in a flow](state.md).
|
|
|
|
## Live and batch flows
|
|
|
|
Choose **Mode** in the flow settings:
|
|
|
|
| | `live` (default) | `batch` |
|
|
|---|---|---|
|
|
| Runs | reacts continuously | once per requested run |
|
|
| Started by | subscriptions, schedules, webhooks or manual execution | Run in the editor, SDK or API |
|
|
| Finishes | stays active until stopped | when its work finishes |
|
|
| Keeps | latest message values | parameters, results, metrics and artifacts |
|
|
| Example | thermostat | experiment or build job |
|
|
|
|
Batch flows use the same editor and validation, but do not activate background
|
|
subscriptions, schedules or webhooks. See [Runs](runs.md).
|
|
|
|
## Flow inputs
|
|
|
|
Declare messages supplied by dashboard controls, the API or run parameters as
|
|
the flow's **Inputs**. Give live inputs a starting value:
|
|
|
|
```json
|
|
{"inputs": [{"spec": {"name": "setpoint", "dtype": "float"}, "initial": 21.0, "origin": "panel"}]}
|
|
```
|
|
|
|
This seeds `house.setpoint` in flow `house` if it has no value yet. Later
|
|
publications replace it. Batch inputs are run parameters, and batch outputs
|
|
select the run's result. See [Where a node's values come from](values.md).
|
|
|
|
`origin` says what writes an input: `run` (the default) for a parameter a run
|
|
passes in, `panel` for a dashboard or panel control. The canvas labels each
|
|
input with it, and the run form leaves panel inputs out, so a run keeps their
|
|
starting value. The engine treats both the same.
|
|
|
|
## Drafts and publishing
|
|
|
|
- **Saving** stores a draft; the engine keeps running the published version.
|
|
- **Publishing** promotes the draft and reloads the flow.
|
|
- **Discarding** removes the draft.
|
|
|
|
Shared node code is an exception: saving it updates every flow using it
|
|
immediately. See [The flow editor](../interface/flow-editor.md#code-and-reuse).
|
|
|
|
Flows are stored in a git repository: `flow.json` describes the graph and
|
|
`nodes/*.py` holds code. Saves are versioned, and stale versions return a
|
|
conflict instead of overwriting another editor's changes.
|
|
|
|
Python installations need Git on the host to record history. Without it,
|
|
flows still save as files; Docker includes Git.
|
|
|
|
## When a flow needs attention
|
|
|
|
The canvas reports issues on the affected nodes:
|
|
|
|
| Issue | Meaning |
|
|
|---|---|
|
|
| `unconnected_input` | no node or declared flow input supplies the message |
|
|
| `missing_initial_value` | a live input has no starting value |
|
|
| `cycle` | nodes depend on each other in a loop |
|
|
| `self_loop_needs_initial` | a node reads and writes a message with no starting value |
|
|
| `missing_source` | a Function node has no saved code |
|
|
| `node_error` | code or configuration could not load |
|
|
| `unauthenticated_hook` | a webhook or served websocket has no shared secret; advisory |
|
|
| `ignored_worker` | a node other than a Function node names a worker, which nothing reads; advisory |
|
|
| `unknown_device` | a Device node names no device, or one that does not exist |
|
|
| `device_port` | a device port is wired in two places, or against the device's report the wrong way or type; a port the report does not list is advisory |
|
|
| `node_unhealthy` | a loaded node reports a runtime problem, such as a lost connection |
|
|
| `node_degraded` | a loaded node works but not as it should, such as a device being offline; advisory, amber on the canvas |
|
|
|
|
Build issues prevent the affected flow from running. `node_unhealthy` and
|
|
`node_degraded` are runtime issues: other work continues, and they clear when
|
|
the node recovers. A degraded node is a warning on Home rather than a fault.
|
|
|
|
You can **stop** a live flow to remove its subscriptions and schedules, or
|
|
**pause** it to hold pending work while values still arrive. **Step** releases
|
|
one held item. Repeated background crashes can quarantine a flow; publishing
|
|
a change gives it another chance.
|
|
|
|
## Where to next
|
|
|
|
- [Where a node's values come from](values.md) — ports, settings and flow inputs
|
|
- [Keeping state in a flow](state.md) — remembering a value
|
|
- [Runs](runs.md) — batch flows
|
|
- [Writing node code](../code/nodes.md) — practical Python examples
|