Platform Notes · Connectivity

Connecting Existing PLCs and Meters to an IoT Platform with Modbus — Without Ripping Out Hardware

The Barquecon platform reads the Modbus registers your PLC, meter or VFD already exposes and decodes them into clean, engineering-accurate telemetry. Here is how the decoder works, and how we wire a specific device into your rollout.

By Barquecon Technologies Published August 6, 2026 8 min read

Most plants we talk to are not short on data — they are short on a path off the machine. A CNC line, a packaging cell, an energy meter on the incoming feeder: the PLC or meter has been faithfully counting cycles, current, and temperature for years, and none of it has ever left the panel. The instinct is to assume connecting it means new hardware, a controls-engineering project, and downtime to install it. It doesn’t. It means reading Modbus registers the device already exposes, and getting the decoding right.

The real hazard isn’t the wire — it’s the decode

Modbus is a simple, decades-old protocol: a client polls a server (the PLC, meter, or VFD) for blocks of 16-bit registers or single-bit coils, over TCP or an RS-485 serial line. Wiring it up is the easy part. The part that actually breaks industrial IoT integrations is turning those raw unsigned 16-bit words into a correct engineering value — a kW figure, a temperature, an RPM — without silently corrupting it.

That is where the Barquecon platform’s @bqt/modbus-adapter starts: not as a socket library, but as a decoder built specifically to survive the classic field-device hazard surface, with a test suite covering every path.

How the platform decodes Modbus data

  • Pure decode core, unit-tested. decodeRegisters and createModbusAdapter().map() map already-read registers plus a poll timestamp through a declared register map into a contract-valid telemetry event. Deterministic and replay-safe, matching the sibling adapters used elsewhere on the platform.
  • Signedness handled correctly. int16 sign-extension and int32 two’s-complement, so a negative reading (a reversed current flow, a sub-zero temperature) doesn’t wrap into a nonsense large positive number.
  • 32-bit width and word order. uint32/int32/float32 values span two registers; wordOrder selects ABCD (big, the default) versus CDAB (little) register ordering — a notorious source of "reads exactly double or exactly backwards" bugs on real meters.
  • IEEE-754 floats. float32 bit reinterpretation, with NaN/Infinity dropped rather than ever emitted as a metric.
  • Fixed-point scaling. Per-field scale (e.g. 0.1 for a one-decimal register), so a device that reports "215" for 21.5°C comes out correctly.
  • All four Modbus data banks, kept as separate address spaces. A field declares its bank — holding, input, coil, or discrete — mapping to read function codes 03, 04, 01 and 02 respectively. Coils and discrete inputs decode via type: "bool" to a clean 0/1 metric, with an optional invert flag for active-low signals (a normally-closed e-stop loop, for example). Because the four Modbus tables are numbered independently on the wire, the adapter keeps them independent internally too — coil 0 never aliases holding register 0.

Never fabricate a reading

The adapter’s discipline is the same one every Barquecon telemetry adapter follows: a missing or short register read, an out-of-range raw value, or a non-0/1 bit drops that specific metric as a structured skip — it does not get invented, interpolated, or defaulted to zero. An unprovisioned device is skipped rather than assigned a fabricated deviceId. For anything feeding a maintenance alert or a compliance record, a metric that silently goes missing is far safer than one that silently goes wrong.

A multi-bank example, as it looks in code

A single machine can mix register and bit banks in one map — a spindle RPM from an input register, a running state from a coil, and an inverted e-stop status from a discrete input:

const MACHINE_MAP = [ { name: "spindle_rpm", address: 0, type: "uint16", bank: "input", unit: "rpm" }, { name: "motor_run", address: 0, type: "bool", bank: "coil" }, { name: "estop_ok", address: 0, type: "bool", bank: "discrete", invert: true }, // active-low ]; adapter.map( { unitKey, ts, inputBlock: { startAddress: 0, values: [1200] }, // FC 04 coils: { 0: true }, // FC 01 discreteInputs: { 0: false }, // FC 02 -> estop_ok = 1 }, ctx, );

A field’s bank defaults to holding, so simpler pre-existing register maps are unaffected, and the bank/type pairing is validated at construction — a boolean declared on a register bank, or a numeric type declared on a bit bank, fails fast rather than silently misreading.

How we wire a specific PLC or meter into your rollout

Everything above happens once the registers are in hand. Reading them — opening a Modbus-TCP socket or an RS-485 serial line and polling register blocks on an interval — is the last mile, and it’s a build step our engineers own per device model as part of your rollout: we confirm the transport (TCP or serial), confirm the register map for your controller or meter model, and the same decode core takes it from there. We wire the live feed from your PLC as part of getting you connected — it isn’t something you have to solve yourself first.

Two things worth knowing up front: pulling individual bits out of a packed status or alarm word (bitmask decoding on a holding register) isn’t supported today — we use the coil/discrete banks for genuine bit tables. And the Modbus PDU’s maximum registers per read (roughly 125 for TCP, 123 for RTU) is enforced by the polling layer, not the decode core itself.

Where this leaves a plant that wants to connect a PLC today

PieceStatus
Register decoding (signedness, word order, scaling, IEEE-754, all four banks)Built in
Register map authoring per device modelStandard process
Modbus-TCP / RTU transport (opening the socket, polling on an interval)We build this for your rollout
Live data flow from your specific PLC or meterWe wire this during onboarding

The hardest and most bug-prone part of connecting an existing PLC — correctly decoding what it already sends — is built, tested, and reusable across device models by authoring one register map per model. Getting a specific device on your site talking to the platform is a scoped engineering task our team owns against that same decoder, not an open design question. If you run Siemens, Mitsubishi, Delta or Schneider controllers, or a Modbus-capable energy meter or VFD, that is the conversation worth having next.

Have a PLC or meter you want off the panel?

Tell us the make and register map and we will scope what it takes to get you connected — no rip-and-replace required.

Book a pilot Talk to our team

Let's Work Together

Contact Us and We'll Help You

Whether you have a question, an idea, or a project in mind, our team is ready to assist you every step of the way.