Why Your Modbus TCP Gateway Reads the Wrong Slave
The Modbus unit identifier is 'useless' on TCP until a gateway is involved. How routing works behind serial gateways, and finding the slave that answered.
The connection is fine. The data is from the wrong meter.
You point the driver at 10.20.4.31:502, the channel goes green, values start flowing — and they're wrong. Not out-of-range wrong, just someone else's wrong. The kW reading tracks a compressor when the tag is supposed to be a boiler feed pump. Nothing in the driver log complains, because as far as TCP is concerned everything worked.
This is almost always the unit identifier. The Modbus Messaging Implementation Guide (V1.0b) is blunt about it: on TCP/IP the server is addressed by IP, so "the MODBUS Unit Identifier is useless" — recommended value 0xFF. That sentence gets quoted a lot and it's true right up until you put a gateway in front of a serial trunk. Then the unit ID in byte 7 of the MBAP header is the only thing telling the gateway which RS-485 slave to relay the request to. IP gets you to the gateway. Unit ID gets you to the device.
So a working ping and an open port 502 prove exactly one thing: the gateway is alive. They say nothing about whether the slave you wanted is on the bus, powered, addressed correctly, or answering.
Where this bites
It's the sites where one Ethernet gateway fans out to a daisy chain — a Moxa MGate, an Anybus, a Red Lion, whatever shipped in the panel:
- Power meters on one RS-485 loop, each with a different slave address set by DIP switch or keypad.
- VFDs behind a serial option card, where the drive's Modbus address and its keypad "station number" are two different settings people confuse.
- Remote I/O blocks and package skids that expose several internal controllers through a single gateway IP.
The gateway holds the mapping. Your job at commissioning is to make the SCADA side agree with it, one slave at a time.
Know which mode the gateway is in before you touch a tag
Gateways do not interpret the unit ID the same way, and the manual usually buries this under a name like "Modbus routing" or "slave ID map." Four behaviors cover most of them:
- Transparent bridge — unit ID is passed straight through as the RTU slave address. Unit ID 7 → slave 7 on the wire.
- Remapped — the gateway keeps a table (virtual ID → physical port + real slave address). Unit ID 7 might reach slave 3 on port 2. This is where "the values are from the wrong device" comes from: someone edited the table, or it reset to defaults after a firmware update.
- Single-device / server mode — the gateway ignores the unit ID and either always talks to one slave or answers from its own register table. Poll any unit ID, get the same data.
- Reject vs. drop on unknown ID — some gateways return exception 0x0B (gateway target device failed to respond) or 0x0A (gateway path unavailable) for an ID they don't route. Others just eat it and let you time out.
That last split is the one that wastes an afternoon. If unit ID 1 answers and unit ID 7 times out with no exception, the silent-drop gateway makes it look like a network fault. Don't go rewriting firewall rules — check the routing table and the slave's own address switch first. Valid RTU addresses are 1–247; 0 is broadcast and 248–255 are reserved, so an address someone "helpfully" set to 250 will never answer through a compliant gateway.
Prove one register before you import 400 tags
Unit ID faults and register-map faults wear each other's clothes. A wrong register looks like a wrong slave; a wrong slave looks like a wrong register. The only way out is to nail down one known-good read manually — a bench Modbus poller, mbpoll, whatever — before the bulk tag import.
Pick a register you can independently verify: a firmware/model register, line voltage on a meter you can read off the faceplate, a drive status word, a slowly-changing counter. Then, when it doesn't match, walk the usual suspects:
- One-based docs (
40001) vs. zero-based driver offset (0). Off-by-one on the base is the single most common map error I hit. - Holding registers (FC03) and input registers (FC04) are separate address spaces — 40001 and 30001 are not the same data.
- 32-bit values: word order and byte order. A meter reading 65536× too big or with swapped halves is a word-swap flag, not a wiring problem.
- Signed vs. unsigned vs. IEEE-754 float vs. scaled integer.
- Block reads that straddle an unsupported gap — the device rejects the whole block, so a range that "should" work returns nothing.
Prove the single read, then trust the import.
Two timeout worlds, and the one that overlaps retries
A TCP-to-serial gateway lives on two clocks. The driver is counting TCP milliseconds; the gateway is counting a serial request-and-response that includes the RTU t3.5 inter-frame gap (about 4 ms of dead air at 9600 8E1, longer as you slow down). Set the SCADA timeout shorter than the gateway's downstream serial timeout and you get the classic mess: the driver gives up, retries, and now two requests for the same slave are queued while the first is still on the wire. The logs fill with overlapping timeouts that look like a flaky slave.
So make the driver timeout comfortably longer than the gateway's serial timeout — not equal, longer. On a slow multi-drop trunk, back off the retry count too; hammering a chain where one meter is slow just starves the healthy ones. If several unit IDs share one RS-485 trunk, stagger the poll groups so the gateway isn't serializing everything into one queue — and when it is backing up, the request queue depth counter tells you before the bad-quality tags do.
One dead slave on a long chain can make every address look intermittent, because the gateway spends its serial timeout waiting on the corpse before it gets to anyone else. Scope the line or read the gateway's own CRC-error and no-response counters. Watching SCADA quality flags alone will send you chasing ghosts.
Writes: assume the ACK is lying
A read routed to the wrong slave is an annoyance. A write routed to the wrong slave moves an actuator you didn't mean to move. And a TCP acknowledgement is not a confirmation from the device — plenty of gateways ACK the moment they've queued the request, then let the serial write fail quietly into a diagnostic counter you're not watching.
Before enabling any write path through a gateway:
- Confirm the exact unit ID and register on a bench or in a maintenance window — not from the drawing.
- Check function-code support: single-register (FC06) vs. multiple-register (FC16). Some devices only accept one.
- Find out whether the gateway rewrites or blocks certain writes (a few do, for "safety").
- Put confirmation and command feedback on the HMI, not a bare write button.
- Log unit ID, register, value, operator, and result — all five.
- Force a write to fail on purpose and confirm the operator actually sees the failure. If they don't, your feedback path is broken and you found out cheaply.
Reading the symptom table
When values look wrong, resist changing five settings at once. Change one, re-test, and use the symptom to narrow the search:
| Symptom | Where to look first |
|---|---|
| TCP connects, every read times out | Unit ID route, serial wiring polarity, serial params (baud/parity/stop), gateway downstream timeout |
| Unit ID 1 works, others fail | Gateway routing table, slave address switches, duplicate RTU addresses on the trunk |
| Values are valid but from the wrong device | Remapped unit ID, duplicated register map, copied tag group pointing at the old ID |
| Some registers read, block reads fail | Unsupported address gap, max block size, FC03/FC04 mismatch |
| Data noisy or intermittent | RS-485 termination and biasing, shield grounding, baud mismatch, one failing slave stalling the chain |
| Write reports success, device unchanged | Gateway write handling, wrong function code, device write-protection, feedback tag pointing elsewhere |
If you can, capture one good request and one bad one off the wire. The diff in unit ID, function code, and starting address usually names the fault faster than an hour in the driver log.
What to leave for the next engineer
The routing table is control-system configuration, not a network detail — treat it that way in the handover. The person replacing this gateway at 2 a.m. two years from now should not have to rediscover the bus:
- Gateway IP, firmware version, config-backup location, and who holds admin access.
- Serial port settings and a physical description of the trunk (which panel, which meters, in what order).
- The unit ID list mapped to device names, panel locations, and register-map versions.
- Poll groups and timeouts as configured in the driver.
- Reserved or retired unit IDs that must not be reused without review.
- The test registers you used to commission — so the next person can prove one read the same way you did.