# Node types Every type the canvas can place. Each is configured by filling in a form the editor generates from its parameter schema, so they all behave the same way. Anything here could be written as a **Function** node — that is what the function node is for. These exist because the same handful of shapes account for most of a real installation, and a rule you fill in is easier to read on a canvas, and to change, than five lines of code repeated eighty times. `GET /flows/node-types` returns this list with each type's full parameter schema, including any [connectors](#connectors) installed on your instance. ## Function **`python`** — your own code, run on every incoming message. The one type with a source file. Its arguments are its input ports and its own settings; its return value is a dict keyed by output ports. See [Writing node code](../code/nodes.md). Settings on a Function node are free-form: you add them by name, and they arrive as keyword arguments. ## Integrations ### MQTT **`mqtt`** — subscribe to topics, or publish what arrives on its inputs. A node with *outputs only* subscribes; a node with *inputs* publishes. | Setting | Default | Notes | |---|---|---| | `topic` | `*` | one topic for every port, or `{"message": "some/topic"}` per port | | `broker_host` | `localhost` | | | `broker_port` | `1883` | | | `username` / `password` | — | `password` takes a secret reference | | `client_id` | — | | | `qos` | `0` | 0, 1 or 2 | | `retain` | `false` | on published messages | | `keepalive` | `60` | seconds | Nodes sharing a broker share one connection. ### HTTP **`http`** — receive data on a webhook, or send it to a URL. Outputs only makes it a **webhook**: the engine mounts a route at `/hooks/{flow}/{url}/{secret}` while the flow runs. Inputs make it a **sender**. | Setting | Default | Notes | |---|---|---| | `url` | — | the route path in webhook mode, the full URL in sender mode | | `method` | `POST` | `GET` or `POST` | | `timeout` | `30` | seconds, sender mode | | `headers` | `{}` | | | `secret` | — | shared secret appended to the webhook URL; takes a secret reference | !!! warning "A webhook with no secret is open to anyone who can reach the host." The canvas flags this as an advisory issue rather than stopping the flow, because a webhook on a private network is a legitimate thing to want. ### InfluxDB **`influxdb`** — write measurements to a bucket, or read them back. | Setting | Notes | |---|---| | `url`, `token`, `org`, `bucket` | connection; `token` takes a secret reference | | `write_precision` | `ns`, `us`, `ms` (default) or `s` | | `query_range` | default window for queries, e.g. `-1h` | | `writes` | per-input: `measurement`, `field`, `tags` | | `queries` | per-output: `measurement`, `field`, `tags`, `range`, `aggregation` | ```json { "writes": { "living_temperature": { "measurement": "environment", "field": "temp_c", "tags": {"room": "living"} } } } ``` **Query passthrough.** An incoming message holding a `flux` key is run as written, and the rows come back on the first output port as `{"rows": [{ts, value, field, measurement, tags}], ...}`. That is what keeps a database node a database node: it holds the credentials and the connection and nothing else. Building a query and shaping its rows are ordinary Function nodes on either side, so a dashboard widget never learns which database answered it. ### Notification **`ntfy`** — push an incoming value to a phone through [ntfy](https://ntfy.sh). | Setting | Default | Notes | |---|---|---| | `server` | `https://ntfy.sh` | | | `topic` | — | required | | `title` | — | | | `priority` | `default` | `min`, `low`, `default`, `high`, `urgent` | | `tags` | — | comma-separated ntfy tags | | `token` | — | for a protected topic; takes a secret reference | This is a *flow* deciding something is worth saying. The engine reporting that it broke is [Alerts](../interface/operations.md#alerts), which is a different thing configured elsewhere. ## Timing ### Inject **`inject`** — emit a value on request, on a timer, or when the flow starts. | Setting | Default | Notes | |---|---|---| | `payload` | current time | what to emit | | `payloads` | `{}` | per-output-port payloads, keyed by port | | `interval` | `0` | emit every n seconds; 0 means never on its own | | `cron` | — | a five-field cron expression | | `at_start` | `false` | emit once when the flow starts | | `start_delay` | `1.0` | how long to wait before that first emission | The most-placed trigger in a real installation — mostly as a button someone presses. ### Delay & schedule **`delay`** — hold messages back, limit their rate, or emit on a schedule. | Setting | Default | Notes | |---|---|---| | `delay` | `0` | seconds to hold each message | | `interval` | `0` | minimum seconds between forwards | | `mapping` | `{}` | input port → output port; paired in order when empty | | `cron` | — | five-field expression | Order of operations: rate check → delay → forward. With a `cron` and no inputs it emits the current time on each tick; with inputs it emits the last value it received. !!! note "Not in a batch flow" A rate limit holds a value back for a timer to release, and a run has no timer — the value would be dropped rather than delayed. Submitting a batch flow with a rate-limited port is refused instead. ### Trigger **`trigger`** — send one value now and another once things go quiet. | Setting | Default | Notes | |---|---|---| | `first` | `true` | sent as soon as a value arrives | | `then` | `false` | sent when the wait expires; empty sends nothing | | `wait` | `60` | seconds of quiet before the second value | | `extend` | `true` | a value arriving during the wait starts it over | The shape this exists for: *the door opened — turn the light on, and off again in two minutes unless it opens again.* ## Logic ### Switch **`switch`** — send a value down one branch or another, by rule. Each rule names an output port; a matching value leaves through that port. Comparisons: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `contains`, `between`. | Setting | Default | Notes | |---|---|---| | `rules` | `[]` | checked in order; each names the output it routes to | | `stop_at_first` | `true` | leave through the first matching rule only | | `otherwise` | — | output for a value that matched nothing | Comparing a string to a number is a mistake in the rule, not a reason to take the flow down: the rule simply does not match. ### Change **`change`** — scale, offset, round or map a value on its way past. | Setting | Default | Notes | |---|---|---| | `scale` | `1.0` | multiply numbers by this | | `offset` | `0.0` | then add this | | `round_to` | — | decimal places | | `mapping` | `{}` | replace a value with another, looked up as text | | `default` | — | value when the lookup misses; empty passes it through | ### Filter unchanged **`rbe`** — pass a value on only when it has actually changed. | Setting | Default | Notes | |---|---|---| | `deadband` | `0.0` | ignore numeric changes smaller than this | | `deadband_percent` | `false` | read the deadband as a percentage | The cheapest fix for a sensor that reports every second and changes every hour. ### Join **`join`** — gather several inputs into one object or list. | Setting | Default | Notes | |---|---|---| | `mode` | `object` | `object` or `array` | ## System ### Command **`exec`** — run a command in the engine's container and read its output. | Setting | Default | Notes | |---|---|---| | `command` | — | the command to run | | `append_payload` | `false` | add the incoming value as one argument | | `timeout` | `30` | seconds | | `fail_on_error` | `false` | treat a non-zero exit as a node failure rather than output | Outputs the command's stdout, stderr and exit code. !!! warning "Inside the container, not on the host" A flow ported from something that read the host's journal, or poked a host script, needs either a mount or a small listener on the host side. This node cannot see the host. ### File **`file`** — read a file into the flow, or write one out of it. | Setting | Default | Notes | |---|---|---| | `path` | — | relative to the engine's files directory | | `mode` | `read` | `read`, `write` or `append` | | `format` | `text` | `text` or `json` | | `newline` | `true` | end each written record with a newline | Confined to a directory the engine owns. A flow that could name any path would be a way to read the secrets store or overwrite a node's source. ## Numeric ### Perceptron **`mlp`** — a small neural layer over its numeric inputs. `output = weights @ inputs + biases`, with weights drawn from `seed` so a node reloads identically. | Setting | Default | Notes | |---|---|---| | `seed` | `0` | | Kept as a worked example of numeric logic rather than as a modelling tool. If you are training something, that is a [batch flow](../concepts/runs.md) and a Function node. ## Connectors Anything else in the palette came from an installed **connector** package — a node type written against a published contract and discovered through the `fluksio.node_types` entry point group. The editor shows which package supplied it. A connector declares its contract version, and one written for a version this engine does not speak is ignored rather than half-loaded. Installing or upgrading one takes effect on the next engine restart, because Python does not re-import a changed module and a rescan would promise more than it delivers. ## See also - [Payload types](payload-types.md) — what a port may carry - [Writing node code](../code/nodes.md) — the Function node - [The flow editor](../interface/flow-editor.md) — placing and configuring them