ModPackQTModPackQT
Node-RED ExamplesResourcesSign up
HomeResourcesNode-RED ExamplesRead Coils (FC01) and Discrete Inputs (FC02)
ReadsNode-RED Modbus Example

Read Coils (FC01) and Discrete Inputs (FC02)

Digital I/O over Modbus. Coils are read/write outputs (relays, solenoids); discrete inputs are read-only (sensors, switches). Both return 1-bit values packed into bytes. This example reads 8 coils and 8 discrete inputs and unpacks them into individual boolean values.

What you need

  • Node-RED v3+
  • node-red-contrib-modbus installed
  • Modbus device with digital I/O (coils and/or discrete inputs)

Flow Overview


                       ┌────────────────────────────┐
                   ┌──▶│ Modbus FC01 (Coils)         │──▶ [true,false,true,true,…]
┌──────────────┐   │   │ addr:0, qty:8               │
│ Inject (1s)  │───┤   └────────────────────────────┘
└──────────────┘   │   ┌────────────────────────────┐
                   └──▶│ Modbus FC02 (Disc. Inputs)  │──▶ [false,true,false,…]
                       │ addr:0, qty:8               │
                       └────────────────────────────┘

Node-RED Flow JSON

Node-RED Flow JSON
[
  {"id":"inj3","type":"inject","name":"Poll 1s","repeat":"1","once":true,"wires":[["req3a"],["req3b"]],"x":120,"y":300},
  {"id":"req3a","type":"modbus-flex-getter","name":"FC01 Coils","dataType":"Coil","adr":0,"quantity":8,"server":"srv1","wires":[["fn3a"],[]],"x":320,"y":280},
  {"id":"req3b","type":"modbus-flex-getter","name":"FC02 Inputs","dataType":"DiscreteInput","adr":0,"quantity":8,"server":"srv1","wires":[["fn3b"],[]],"x":320,"y":320},
  {"id":"fn3a","type":"function","name":"Unpack coils","func":"msg.payload = Array.from(msg.payload.data).map(Boolean);
return msg;","wires":[["dbg4"]],"x":530,"y":280},
  {"id":"fn3b","type":"function","name":"Unpack inputs","func":"msg.payload = Array.from(msg.payload.data).map(Boolean);
return msg;","wires":[["dbg5"]],"x":530,"y":320},
  {"id":"dbg4","type":"debug","name":"Coil states","active":true,"wires":[],"x":720,"y":280},
  {"id":"dbg5","type":"debug","name":"Input states","active":true,"wires":[],"x":720,"y":320},
  {"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

// Coils (FC01):  [true, false, true, true, false, false, false, false]
// Inputs (FC02): [false, true, false, true, false, false, false, false]

Common Gotchas

  • node-red-contrib-modbus packs coil bits into Buffer bytes — use msg.payload.data (an array) not msg.payload directly.
  • Each element of msg.payload.data is 0 or 1, not a Buffer byte; the node already unpacks bits for you.
  • dataType string is 'Coil' for FC01 and 'DiscreteInput' for FC02 — exact match required.
  • Firing two parallel requests to the same server is fine; they queue on the modbus-client connection.
  • If you're reading more than 8 coils the response will be multiple Buffer bytes; the node handles this automatically.

Same in ModPackQT — in 30 seconds

ModPackQT handles FC01 and FC02 alongside FC03/FC04 in the same register table. Toggle the function code in the row dropdown and poll — no separate flow branches needed.

Was this example helpful?

More Reads examples

All Node-RED Modbus Examples (30)

ModPackQT · Node-RED Modbus Examples · Updated 2026