Transform blocks change the message and send it on. They are how you rename keys, compute values, build texts and decode raw device data before Save telemetry. Each has an out output and an error output. None of them keeps state.
Change
Sets, edits, deletes or moves properties of the message and of flow or global variables, in steps done from top to bottom.
| Setting | Meaning | Values |
|---|---|---|
| ops | The steps | up to 16 rows |
Each step:
| op | Does | Fields |
|---|---|---|
set | Writes a value; missing parents are created | path, value (any value kind) |
change | Replaces every occurrence of from with to in text; non-text is left alone | path, from, to, regex (a pattern of at most 64 characters) |
delete | Removes the property or variable | path |
move | Copies to the path in to, then deletes the original. The editor does not show the to field yet, so use set and delete instead. | path, to |
copy keys | Copies every top-level key of the object at path whose whole name matches Keys matching into To object | path, Keys matching, To object |
delete keys | Deletes every top-level key whose whole name matches | path, Keys matching |
Paths are msg., flow. or global. paths (flow.persist:x for the persistent store). Engine fields (_…), msg.msgType and msg.originator cannot be written. Errors: invalid_value with invalid_path, read_only, invalid_key, limit (variable store full) or bad pattern; steps before the failing one are already applied.
Example: rename a device’s key before saving: step 1 set msg.payload.temperature to the path msg.payload.tmp; step 2 delete msg.payload.tmp.
Calculate
Works out an expression and writes the result.
| Setting | Meaning | Default | Values |
|---|---|---|---|
| expr | The expression | required | up to 512 characters |
| target | Where the result goes | msg.payload | a msg., flow. or global. path |
7 / 2 is 3.5; + joins text when either side is text; arithmetic on null or any text (even "21.5") fails with type: convert with number(). Errors: invalid_value, type, div_zero, steps, limit. See Condition blocks for the functions.
Examples: round(msg.payload.temperature * 1.8 + 32, 1); 10 * log10(msg.payload.ratio); clamp(msg.payload.level, 0, 100).
Scale
Maps a number linearly from one range to another, in place.
| Setting | Meaning | Default | Values |
|---|---|---|---|
| property | The number | msg.payload | a path |
| in_min, in_max | The input range | 0, 4095 | numbers, not equal |
| out_min, out_max | The output range | 0, 100 | numbers |
| mode | Outside the output range | clamp | clamp (limit), wrap (wrap around), free (leave) |
| round | Decimal places | none | 0 to 10 |
Formula: out_min + (value − in_min) × (out_max − out_min) / (in_max − in_min). Numeric text and true/false (1/0) count as numbers. Error invalid_value (“not a number”, or an empty input range).
Template
Builds text, or a JSON value, from {{ expression }} placeholders.
| Setting | Meaning | Default | Values |
|---|---|---|---|
| template | The text | {{ msg.payload }} | up to 4,096 characters |
| target | Where the result goes | msg.payload | a msg., flow. or global. path |
| format | text, or json (the result is parsed as JSON) | text | text, json |
null becomes empty, objects and arrays are written as JSON. For JSON output, put text placeholders in quotes yourself: {"temp": {{ msg.payload }}, "unit": "{{ flow.unit }}"}. The result is at most 64 KB of text.
JSON
Turns JSON text into a value, or a value into JSON text, in place.
| Setting | Meaning | Default | Values |
|---|---|---|---|
| mode | auto (parse text, pass the rest), parse, stringify | auto | |
| property | The property | msg.payload | a path |
Errors: invalid_value “not JSON: …” or “not a string”.
CSV
CSV text to records, or records to CSV text, in place.
| Setting | Meaning | Default | Values |
|---|---|---|---|
| mode | auto, decode, encode | auto | |
| property | The property | msg.payload | a path |
| sep | Field separator | comma | comma, semicolon, tab, pipe |
| header | Decode: the first line has the names. Encode: write a header line | off | on, off |
| columns | Column names, comma-separated | empty | up to 256 characters |
| numbers | Decode: number-like fields become numbers | off | on, off |
| output | Decode: one message with all records (array) or one per record (rows) | array | array, rows |
Quoting follows RFC 4180. Error queue_full over 10,000 lines or records.
XML
XML text to an object, or an object to XML text.
| Setting | Meaning | Default |
|---|---|---|
| Mode | parse, build, or auto | |
| Property | Where the conversion happens | msg.payload |
| Attribute prefix | Prefix of attribute keys | @ |
| Text key | Key of text next to child elements | #text |
| Arrays / array elements | Which elements are always arrays | |
| Numbers | Numeric text becomes numbers | off |
| Select | Keep only one element path, e.g. soap:Envelope/soap:Body/*/m:Price | |
| Root, Declaration | Building: the root element name, the <?xml …?> line | |
| Max bytes | Largest input | 64 KiB (1 to 256 KiB) |
A document with <!DOCTYPE is refused. At most 10,000 elements, 64 attributes per element, 128 characters per name. Errors: parse_error, dtd_refused, too_large, too_deep, bad_name, no_root.
Hex and Base64
Encode a property as hex (two lower-case digits per byte) or base64 text, or decode it back.
| Setting | Meaning | Default | Values |
|---|---|---|---|
| mode | Which way | auto | auto, encode, decode |
| property | The property | msg.payload | a msg., flow. or global. path |
In auto, text that looks like hex (or base64) is decoded and everything else encoded; short words such as test or digits such as 2024 are valid base64 or hex too, so choose encode or decode when you know the direction. Hex decoding ignores spaces and colons.
Bytes
Reads named numbers from binary data, or builds binary data from numbers.
| Setting | Meaning | Default | Values |
|---|---|---|---|
| mode | Read or build | decode | decode, encode |
| fields | One row per field | empty | up to 16 rows |
Each field:
| Field | Meaning | Default | Values |
|---|---|---|---|
| name | Key in the result | required | a letter or _ first, up to 32 characters |
| offset | First byte, from 0 | 0 | 0 to 4,095 |
| type | Size and kind | u16 | u8, i8, u16, i16, u32, i32, f32 |
| le | Little endian | off (big endian) | on, off |
| bits | A bit range start:length | whole field | e.g. 0:1, 4:3 |
| scale | Decode: × scale; encode: ÷ scale | 1 | a number |
Decode reads hex text (spaces and colons ignored) or an array of byte values in msg.payload and writes { name: value }. Encode writes hex text. Error invalid_value when the data is not hex or a field lies beyond its end.
Example: a raw payload 00d7ff9c with temp (offset 0, i16, scale 0.1) and pressure (offset 2, i16) gives { "temp": 21.5, "pressure": -100 }.
Decoding raw device data
A device that sends binary data arrives with the single key raw (base64 for binary). A typical decoder in the root flow, before Save telemetry:
Switch (msg.payload.raw nempty) → Change: set msg.payload to the path msg.payload.raw
→ Base64 (decode) → Hex (encode) → Bytes (decode fields) → Save telemetry
Check the result with Test before you deploy. For LoRaWAN devices, use codecs instead; see Codecs overview. For anything the blocks cannot express, use The script block.

