In this lesson

What this lesson covers

  • The bytes that separate rtuovertcp from real Modbus TCP
  • What a gateway does to the unit id and the CRC, and what it leaves alone
  • The choice between RTU and TCP, and the fault pictures a gateway adds

Read first: The Modbus RTU frame byte by byte, plus CRC, Port 502, the MBAP header and the unit id, Modbus TCP on your network: IP, VLAN, firewall

rtuovertcp is a complete Modbus RTU frame, address byte and CRC included, pushed unchanged through a TCP connection, while real Modbus TCP wraps the same request in a seven byte MBAP header and drops the CRC. Both arrive on port 502 and carry an identical PDU, so the wrong setting in your client gives you silence instead of an error. After this lesson you can tell them apart from the bytes, and you know what a gateway changes on the way.

Two byte streams that look alike

Open a capture on port 502 and two very different things can carry exactly the same question. Both of these ask for three holding registers from PDU address 107, datasheet number 40108 in the manual.

Real Modbus TCPMBAP header, 7 bytes00 01 00 00 00 06 FFPDU: FC03, start address0x006B, 3 registers03 00 6B 00 03CRC-16RTU frame through a TCP connectionServer address,1 byte01PDU: FC03, start address0x006B, 3 registers03 00 6B 00 03CRC-16,2 bytes74 17Same PDU, different envelope

Home Assistant: type tcp versus type rtuovertcp

The difference sits at the front and at the back, not in the question itself.
PartReal Modbus TCPRTU over TCP
First bytes00 01 00 00 00 06 FF, the MBAP header01, the server address
Middle03 00 6B 00 0303 00 6B 00 03
Last bytesnothing, the PDU ends the frame74 17, the CRC-16, low byte first
Total length12 bytes8 bytes

The middle is identical, and that middle is the PDU. Everything that differs is envelope. The same five bytes turn up in the Modbus RTU frame byte by byte and in the MBAP header and unit id.

What a gateway actually does to your frame

A gateway unpacks every request and packs it again, which makes it the client on the RS485 bus, not a piece of wire between two networks.

RS485, Modbus RTUEnergy meterEV chargerHeat pumpRTU-to-TCP converterRTU ⇄ TCPEthernet, Modbus TCPHome Assistant, SCADA or cloudRS485RJ45 / Ethernet
The converter unpacks each request and packs it again, which makes it the client on the bus.

Send a request to a meter at RS485 address 1 behind that gateway: 00 01 00 00 00 06 01 03 00 6B 00 03. The unit id is 1, not the 255 you would use for a device straight on the network. The gateway then does four things:

  1. It drops the seven MBAP bytes and keeps the PDU 03 00 6B 00 03.
  2. It writes the unit id in front as the server address byte, so 1 becomes 01.
  3. It calculates the CRC-16 over address plus PDU and appends it low byte first: 74 17.
  4. It sends 01 03 00 6B 00 03 74 17 onto the bus and waits for the answer, or for its own timeout.

The meter replies 01 03 06 02 2B 00 00 00 64 05 7A, eleven bytes. The gateway drops the address byte and the CRC, keeps the eight PDU bytes, copies your transaction id, protocol id and unit id back, and recalculates only Length: 1 unit id plus 8 PDU is 9. You get 00 01 00 00 00 09 01 03 06 02 2B 00 00 00 64, fifteen bytes. The values 555, 0 and 100 never changed.

Why rtuovertcp exists

Because not every box between Ethernet and RS485 does that translation. A plain serial device server moves bytes and nothing else: whatever lands on the TCP socket goes out of the serial port, and whatever comes back goes into the socket. It never inspects a function code.

So your frame has to be a finished RTU frame already, with its own address byte and CRC, because nothing downstream will add them. There is no MBAP header, so no transaction id to match responses with and no Length field to mark where a message ends. The client falls back on the RTU rules: one request at a time, then the answer or a timeout. Software calls this mode rtuovertcp, and some tools label it "RTU over TCP" or "encapsulated".

Which setting do you choose in your client?

Match the setting to what the box on the other end actually speaks, not to the cable you plugged into it. In Home Assistant that is the type key of the modbus integration:

modbus:
  - name: gateway
    type: rtuovertcp
    host: 192.168.1.50
    port: 502
tcpnative Modbus TCPHAhubPV inverterEthernetPort 502
For devices with their own Ethernet port that speak Modbus TCP themselves, and for gateways that really translate. The frame carries an MBAP header and no CRC.
rtuovertcpRTU frames inside a TCP streamHAhubRS485 forwarderEthernetPort 502 (RTU framer)
For serial device servers that pass the frame through untouched. Recognisable by a server address at the front and a CRC at the back of the response.
serialstraight onto RS485HAhubUSB-RS485A/B/GND/dev/ttyUSB0
For a USB to RS485 adapter on the machine the client runs on. You supply port, baud rate and parity instead of an IP address.
The wrong type gives you timeouts, not an error message, which is why this one costs people a whole evening.

The address on the bus goes in the device_address field of the sensor, not in the hub block above. The symptom of the wrong choice is unmistakable once you have seen it: ping succeeds, a port test on 502 succeeds, and every entity stays unavailable. Nothing fails loudly, because a byte stream nobody understands still travels perfectly well. If both settings fail, the address or the serial parameters are wrong too, and the Modbus TCP gateway setup guide covers those in order.

When do you pick RTU, when TCP?

Six things decide it in practice, and on an existing installation most of them are already decided for you.

ConsiderationPoints to RTUPoints to TCP
Existing wiringa working RS485 bus is already in placestructured Ethernet cabling is already in place
Distanceup to 1000 m of trunk at 9600 baud with AWG26 or thickeranywhere the network reaches
Device countup to 32 devices per segment without a repeaterlimited by the devices, not by the bus
Network availabilityno switch, no VLAN and no IP plan neededneeds a managed, reachable network
Speedone request at a time, frame time is the ceilingseveral outstanding requests allowed, 1 to 16
Cost per devicetwo wires and a common conductoran Ethernet port, or one gateway per location

Most projects end up mixed: RS485 to the meters, one gateway, Ethernet from there. The full weighing of the two transports is in Modbus RTU versus Modbus TCP, and choosing the box itself is covered in the guide to buying a Modbus gateway.

What extra fault pictures a gateway brings

Two exception codes exist purely for gateways, and both come from the gateway rather than from the device you wanted to reach. Exception 0A, gateway path unavailable, means the gateway could not allocate an internal path from its input port to its output port, so it is misconfigured or overloaded. Exception 0B, gateway target device failed to respond, means the request did reach the bus and nothing answered. Both arrive as a short frame with the function code raised by 0x80, so a failed FC03 comes back as 83 0A or 83 0B.

Read that difference carefully. Exception 0B points at the serial side: wrong server address, wrong baud rate, wrong parity, or a dead device. Exception 0A points at the gateway itself, usually at how hard you are polling it.

Common mistakes

  1. Setting tcp where rtuovertcp is needed. Ping works, the port is open, and not a single read succeeds. That combination is the signature of this fault. Flip the connection type before you change anything else, and change only that.

  2. Using unit id 255 behind a gateway. There the unit id is the real server address, between 1 and 247. Fill in 255 and you get exception 0B or silence, because no device answers at that address. The value 0xFF belongs to devices directly on the network.

  3. Treating the gateway as invisible. It is a client on the RS485 bus, with its own timeout and its own polling behaviour. Point four clients at it at once and you can collect exception 0A while every device is healthy.

  4. Replacing RTU with TCP and leaving the bus alone. A gateway solves reach, not wiring. Meters that dropped frames on a poorly terminated bus yesterday keep dropping them today, only now over Ethernet.

Get hands-on

The aim is to see with your own eyes that one question fits in two envelopes. Steps 1 to 3 need no hardware.

  1. 1

    Write the request in RTU form

    Write down "read three holding registers from PDU address 107 at server address 1" as bytes: 01 03 00 6B 00 03 74 17. Mark the PDU, which is 03 00 6B 00 03.

  2. 2

    Write the same request in TCP form

    Now the same question as real Modbus TCP: 00 01 00 00 00 06 FF 03 00 6B 00 03. Mark the PDU again. It is the same five bytes in the same order.

  3. 3

    Account for every byte of the difference

    Count them: 8 against 12. The RTU frame spends 3 bytes on envelope (1 address plus 2 CRC), the TCP frame spends 7. Seven minus three is four, and 8 plus 4 is 12.

  4. 4

    Try both settings on a real gateway

    Configure your client once as tcp and once as rtuovertcp, changing nothing else, and note which one returns values. That experiment tells you what kind of box you bought.

  5. 5

    Ask for an address that is not there

    Request a unit id that is not on the bus and note whether you get exception 0B or a plain timeout. Exception 0B means the gateway translates and reports back; a bare timeout means it only passes bytes through.

No gateway available. Do steps 1 to 3 on paper, then put both byte strings into the frame decoder and the MBAP builder from the earlier lessons in this chapter and name every field out loud. Expected result: two frames with the PDU marked in both, and a clear idea of which connection type your hardware wants.

Summary

  • A real Modbus TCP frame opens with a seven byte MBAP header and carries no CRC; an rtuovertcp frame opens with a server address and ends with two CRC bytes, low byte first.
  • The same read is 12 bytes over Modbus TCP and 8 bytes over Modbus RTU, and the five PDU bytes in the middle are identical.
  • A gateway strips the MBAP header, adds the server address and the CRC, and rebuilds the header with only Length recalculated.
  • Behind a gateway the unit id is the real RS485 server address, so 255 is always wrong there.
  • Exception codes 0A and 0B come from the gateway, which extends reach without repairing the bus behind it.

Check yourself

Four questions about this lesson. Every answer comes with an explanation.

Question 1 of 4
Your capture on port 502 shows the payload 01 03 00 6B 00 03 74 17. What are you looking at?
Ping to the gateway works and port 502 is open, yet every register you request times out. What do you change first?
You request unit id 9 through a gateway while the RS485 bus behind it only holds addresses 1 to 4. What is the most likely outcome?
What does a gateway change about the PDU on its way through?

Stuck on a project?

Describe what you see and where it goes wrong. We will look at it and tell you what we would do.

Further reading in the knowledge base