ModPackQTModPackQT
Node-RED ExamplesResourcesSign up
HomeResourcesNode-RED ExamplesRead FLOAT32 Across All Four Byte Orders
ReadsNode-RED Modbus Example

Read FLOAT32 Across All Four Byte Orders

Reading a 32-bit float is straightforward once you know the byte order. The problem is every manufacturer picks a different one — and some datasheets don't tell you. This example reads 2 consecutive holding registers and decodes them as a FLOAT32 in all four common byte orders so you can identify the correct one.

What you need

  • Node-RED v3+
  • node-red-contrib-modbus installed
  • A device that exposes at least one FLOAT32 value (e.g. temperature or voltage)

Flow Overview


┌─────────┐   ┌───────────────────────┐   ┌──────────────────────────────────────────┐
│ Inject  │──▶│ Read 2 Holding Regs   │──▶│ Function: try all 4 byte orders          │
│         │   │ addr:10, qty:2        │   │  AB-CD → float (big-endian)              │
└─────────┘   └───────────────────────┘   │  CD-AB → float (word-swap)              │
                                          │  BA-DC → float (mixed)                  │
                                          │  DC-BA → float (little-endian)          │
                                          └──────────────────────────────────────────┘
                                                          ▼
                                              Debug: { raw:[…], AB-CD: …, … }

Node-RED Flow JSON

Node-RED Flow JSON
[
  {"id":"inj4","type":"inject","name":"Poll once","once":true,"wires":[["req4"]],"x":120,"y":400},
  {"id":"req4","type":"modbus-flex-getter","name":"Read 2 regs","dataType":"HoldingRegister","adr":10,"quantity":2,"server":"srv1","wires":[["fn4"],[]],"x":310,"y":400},
  {"id":"fn4","type":"function","name":"Try all byte orders","func":"const d = msg.payload.data;
const b = Buffer.alloc(4);
b.writeUInt16BE(d[0], 0); b.writeUInt16BE(d[1], 2);
const AB_CD = b.readFloatBE(0);
b.writeUInt16BE(d[1], 0); b.writeUInt16BE(d[0], 2);
const CD_AB = b.readFloatBE(0);
b.writeUInt16BE(d[0], 0); b.writeUInt16BE(d[1], 2);
const BA_DC = b.swap16().readFloatBE(0);
const buf2 = Buffer.alloc(4);
buf2.writeUInt16BE(d[1], 0); buf2.writeUInt16BE(d[0], 2);
buf2.swap16();
const DC_BA = buf2.readFloatBE(0);
msg.payload = { raw: d, 'AB-CD': AB_CD, 'CD-AB': CD_AB, 'BA-DC': BA_DC, 'DC-BA': DC_BA };
return msg;","wires":[["dbg6"]],"x":530,"y":400},
  {"id":"dbg6","type":"debug","name":"All interpretations","active":true,"complete":"payload","wires":[],"x":740,"y":400},
  {"id":"srv1","type":"modbus-client","name":"My Slave","clienttype":"tcp","tcpHost":"192.168.1.100","tcpPort":502,"unit_id":1}
]

To import: open Node-RED → Hamburger menu → Import → paste this JSON → Deploy.

Expected Output

msg.payload = {
  raw: [17224, 0],          // registers 10 and 11
  "AB-CD": 200.0,          // ← most likely correct if device is big-endian
  "CD-AB": 2.8e-43,
  "BA-DC": 3.1e-38,
  "DC-BA": 1.4e-45
}
// The value that makes physical sense is your byte order.

Common Gotchas

  • The correct byte order is the one that produces a physically plausible value — pick the one closest to what the sensor should read.
  • Registers are read MSB-first within each 16-bit word regardless of byte order — that is fixed.
  • Some vendors document byte order as '3412' or '1234' — 3412 = AB-CD, 2143 = CD-AB, 4321 = DC-BA, 1234 = BA-DC.
  • Buffer.swap16() swaps bytes within each 16-bit pair — use it to implement BA-DC and DC-BA.
  • Use float32 with the SAME byte order for all registers on the same device (they don't mix).

Same in ModPackQT — in 30 seconds

ModPackQT's Float-to-Register tool decodes any pair of register values as FLOAT32 in all four byte orders side by side, so you can visually confirm the right order in one click.

Was this example helpful?

More Reads examples

All Node-RED Modbus Examples (30)

ModPackQT · Node-RED Modbus Examples · Updated 2026