View all lessons
Part 1
Fundamentals
Part 2
Modbus RTU
- Lesson 5RS485 explained: A, B, common and termination20 min
- Lesson 6Baud rate and parity: why 8E1 is the default16 min
- Lesson 7The Modbus RTU frame byte by byte, plus CRC18 min
- Lesson 8Multiple Modbus devices on one RS485 bus16 min
- Lesson 9Read your first Modbus device with mbpoll22 min
- Lesson 10Modbus RTU troubleshooting: symptom to cause20 min
Part 3
Modbus TCP
Part 4
Advanced
- Lesson 16Writing to a Modbus device without breaking it18 min
- Lesson 17Word order and floats: same bytes, other value22 min
- Lesson 18Calculate your poll interval and bus load18 min
- Lesson 19Modbus security: the protocol will not help16 min
- Lesson 20Modbus integration: PLC, Home Assistant, cloud20 min
- Lesson 21Modbus commissioning checklist and cheat sheet18 min
Modbus integration: PLC, Home Assistant, cloud
Modbus integration runs through a PLC, Home Assistant or a cloud platform. Compare what each route asks of you and which alerting you need to add on top.
What this lesson covers
- Three routes for the same data: PLC, Home Assistant or cloud
- The five facts every route asks for: block, numbering, type, word order, scale
- An alerting rule that only fires after three failed polls
Read first: Practise Modbus TCP with a free simulator, rtuovertcp explained: what a gateway does to your frame, Word order and floats: same bytes, other value
Modbus integration is not learning the protocol a second time, it is deciding where the data goes and who maintains it afterwards. A PLC, Home Assistant and a cloud platform read exactly the same register from exactly the same device, and still all three ask something different of you. After this lesson you can compare the three routes, fill in the same five facts on whichever one you pick, and write an alerting rule that does not fire on a single hiccup.
Three routes for the same data
Take total system power from an Eastron SDM630 energy meter: input registers, FC04, two registers because it is a 32-bit float. Datasheet number 30053 is PDU address 52, hexadecimal 0x0034. This is the complete RTU request to server address 1, byte for byte.
| Byte | Value | Meaning |
|---|---|---|
| 1 | 01 | server address 1 on the RS485 bus |
| 2 | 04 | FC04, read input registers |
| 3 to 4 | 00 34 | start address 0x0034, PDU address 52 (datasheet number 30053) |
| 5 to 6 | 00 02 | number of registers: 2 |
| 7 to 8 | 30 05 | CRC-16, low byte first (value 0x0530) |
And the reply, nine bytes long.
| Byte | Value | Meaning |
|---|---|---|
| 1 | 01 | the same server address |
| 2 | 04 | the same function code, so no exception |
| 3 | 04 | byte count: 4 data bytes follow |
| 4 to 7 | 44 9A 50 00 | float32, most significant register first: 1234.5 W |
| 8 to 9 | F3 5B | CRC-16 over the reply (value 0x5BF3) |
That is the rule of this lesson: the five PDU bytes 04 00 34 00 02 are identical on every route. Only the envelope changes: a server address plus CRC-16 on RTU, a seven byte MBAP header with a unit id on TCP, and above all who maintains the translation from 44 9A 50 00 into 1234.5 W. Behind an RTU to TCP gateway the RTU frame including its CRC even travels on unchanged inside the TCP connection.
What each route asks of you
Technically they do the same thing. The difference is maintenance: who keeps the register map current, and who gets the call at three in the morning.
| PLC or SCADA | Home Assistant | Cloud platform | |
|---|---|---|---|
| Knowledge needed | the vendor programming environment | YAML and Linux | reading a register map |
| Maintained afterwards by | your programmer, under contract | you, usually without a contract | the vendor, while the contract runs |
| Works with the internet down | yes | yes | polling continues, sending waits |
| Handed over through | the project files | only to someone with the same knowledge | an account |
For a home or a small building the Home Assistant Modbus integration is a short path to the first reading. If a building management system is already in place, the question belongs with Modbus in home and building automation. If you have to reach twenty sites from an office, it becomes remote monitoring through the cloud, with the ModbusCloud Gateway or another gateway that connects outbound by itself.
From register to usable measurement
Every route needs the same five facts. Skip one and you get no error message, you get a wrong number. Two devices side by side show why none of them is optional.
| Fact | Eastron SDM630, total system power | NIBE S-series, outdoor sensor BT1 |
|---|---|---|
| Block and function code | input registers, FC04 | input registers, FC04 |
| Numbering | datasheet number 30053, PDU address 52 | input register 1 |
| Data type | float32 across two registers | signed 16 bit, one register |
| Word order | most significant register first, so ABCD | not applicable on a single register |
| Scaling factor | none, the value is already in W | divide by 10, a raw -47 is -4.7 degrees |
The rule behind it is short: these are properties of the device, not of the destination. Move from a PLC to a dashboard and only the place where you type them changes. They differ per manufacturer: NIBE divides temperatures by 10, Daikin by 100, and swapping the divisor puts you out by exactly a factor of ten. Read as an int16, 0x449A yields 17562, which looks like a plausible power reading. The four word order variants live in the lesson on data types and word order.
A minimal home automation configuration
This is everything Home Assistant needs to read the meter from the example above.
modbus:
- type: rtuovertcp
host: 192.168.1.50
port: 502
sensors:
- name: Total power
device_address: 1
address: 52
input_type: input
data_type: float32
Four fields carry the lesson. type is the connection type: rtuovertcp because an RS485 to ethernet gateway sits in between, tcp for a device with its own ethernet port. device_address is the server address on the bus, which behind a gateway also ends up in the unit id of the MBAP header. address is 0-based and goes into the frame unchanged as the PDU start address, so 52 and not 30053. input_type: input picks the block, and data_type: float32 glues the two registers together. If the word order is reversed, swap: word joins them.
The full configuration with sensors, switches and hub options lives in the guide to the Home Assistant Modbus integration.
How often do you read what?
The interval belongs to how fast the quantity moves, not to the project. Measure your cycle time, meaning how long one round past all devices takes, and divide it by the poll interval: that is your bus load. The rule of thumb of this course is to stay under 50 percent, so make the interval at least twice the cycle time. On the worked bus of ten meters at 9600 baud a cycle takes 0.98 seconds. A 1 second interval is then 97.9 percent, 5 seconds is 19.6 percent, 10 seconds is 9.8 percent and 60 seconds is 1.6 percent.
| Class of device | Interval | Why |
|---|---|---|
| SMA inverter | 10 s or slower | SMA asks for at least ten seconds between two transfers |
| kWh meter | 10 s | 9.8 percent bus load, ample for energy monitoring |
| Heat pump and BMS | 60 s | 1.6 percent bus load, and the flow temperature moves slower anyway |
| NIBE S-series | check the register budget | 100 registers per second allowed, 60 registers per second is already 60 percent |
Two side conditions come with it. SolarEdge closes an idle TCP connection after 2 minutes, so the interval has to stay under that to keep the session open. And behind a gateway the serial sum still applies in full: the ethernet side is fast, the bus behind it still runs at 9600 baud. The complete sum lives in the lesson on poll intervals and bus load.
Alerting without false alarms
A corrupted frame produces no exception but silence, and therefore a timeout. On a long bus that happens now and then with nothing being wrong. So raise an offline alarm only after three consecutive failed polling rounds.
Three rules keep the night quiet. First, keep "device does not answer" separate from "value out of range", because the first usually explains the second. Second, use a hysteresis pair on thresholds: alarm above 70 degrees and clear below 65. Count on 5 to 10 percent of the threshold; without that gap a value sitting on the limit crosses it dozens of times an hour. Third, let the client skip a dead device after three failed rounds, otherwise it waits out the full timeout every round.
That last one is measurable. One dead device stretches a cycle of 0.98 seconds to 1.88 seconds at a 1 second timeout, and to 3.88 seconds once the client waits out three full timeouts. The guide to automated Modbus alerts works both patterns out.
What you document for the next technician
The installation works now, and in two years someone else is standing there. Record per device: brand and model, server address or unit id, connection type, and per measurement the block, the address in both numberings, the data type, the word order and the scaling factor. Add the poll interval with its reason, and every alarm threshold with its clearing value. The reason is the part everyone leaves out and nobody can reconstruct later: 10 seconds looks arbitrary until it says next to it that the manufacturer does not want to be polled faster.
That is exactly what a preconfigured register map from a template library saves you, and exactly what is missing when someone configured by hand without notes. Check such a map once against the datasheet of your firmware version anyway. Turning this list into a handover checklist is the next lesson.
Common mistakes
Starting in the YAML or the dashboard. You fill in a configuration, the sensor stays empty, and you go hunting for a protocol fault inside a text file. Prove with a command line tool that the register reads first. Only then do you know an empty sensor is down to the configuration.
Filling in tcp where rtuovertcp is needed. Behind an RS485 to ethernet gateway this is a common reason a sensor stays empty. The TCP connection is established, port 502 is open, and still no answer ever comes back. The lesson on choosing between RTU and TCP shows the difference in bytes.
Copying deprecated field names out of an old forum post. In Home Assistant the field is device_address, not slave, and the data types are int16 and float32, not int and float. A deprecated name is ignored or rejected at restart, and the message about it sits in the log you did not have open.
Alarming on a single failed poll. You get notifications when nothing is wrong, and after a week someone switches the whole alerting off. Count three consecutive failures before you report, and keep "does not answer" separate from "value out of range".
Get hands-on
You connect one device to one system and check the value with a second method. Both mbpoll and the pymodbus simulator are free to use, including commercially.
- 1
Prove the register reads first
Read the value with a command line tool, separate from your system. For a float32 from PDU address 52 at server address 1:
mbpoll -m rtu -a 1 -b 9600 -P none -t 3:float -r 52 -c 1 -0 -1 /dev/ttyUSB0 - 2
Write down the five facts
Block, numbering, data type, word order and scaling factor. Note the sentinel values as well if the manufacturer publishes them. That note is your only handhold later when a value looks wrong.
- 3
Add the device with a minimal configuration
Host, port, connection type, unit id, register address, data type and interval only. No naming, no icons, no second sensor.
- 4
Restart and look the value up
Open the status view of your system and find the new entity. If it stays empty, the cause is in step 3 and not in the connection, because step 1 succeeded.
- 5
Compare the two readings
If the number differs from step 1, walk the five facts. A factor of 10 or 100 points at the scaling factor, an absurdly large one at the word order.
- 6
Set the alerting rule
Let the notification fire only after three consecutive failed polling rounds, and give every threshold a clearing value that sits well below it.
No hardware to hand. Start the pymodbus simulator and point your system at 127.0.0.1:5020 with connection type tcp. Every step except the first works identically.
Expected result: one value that reads the same in two independent tools, and an alarm that stays quiet through a single missed poll.
What you record about this route for the next engineer is the subject of the final lesson, the commissioning checklist and handover.
Summary
- The PDU does not change per destination: every route sends the same
04 00 34 00 02and gets the same04 04 44 9A 50 00back, only the envelope differs. - The three routes differ in maintenance and not in technology, so choose on who keeps the register map and who gets the night call.
- Block, numbering, data type, word order and scaling factor are properties of the device, so every route needs all five.
- In Home Assistant
addresscounts from 0, so datasheet number 30053 becomes 52, and behind a gateway the connection type isrtuovertcprather thantcp. - Match the poll interval to how fast the quantity moves and keep bus load under 50 percent: at a cycle of 0.98 seconds, 10 seconds is 9.8 percent.
- Report a device offline only after three consecutive failed polling rounds and give every threshold a clearing value, otherwise you are alarming on noise.
Check yourself
Four questions about this lesson. Every answer comes with an explanation.
Question 1 of 4
Want to see how it works?
The ModbusCloud Gateway reads the devices from this course without you programming a single register.