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
Read your first Modbus device with mbpoll
Read a Modbus device in eight steps: adapter, serial parameters, address, register, sanity check. Includes a no hardware route with a free open simulator.
What this lesson covers
- Connecting the USB to RS485 adapter and finding the port name
- The mbpoll command line, argument by argument
- A check after each step, and back to volts or amps
Read first: How to read a Modbus datasheet, step by step, RS485 explained: A, B, common and termination, Baud rate and parity: why 8E1 is the default
Reading a Modbus device comes down to one command whose arguments are the four facts from the datasheet plus the port your adapter turned up on. Everything from the first eight lessons meets here, in a procedure that takes about half an hour on a cold panel. After this lesson you can go from an unopened cabinet to a register value in a real unit, with a check after each step that rules out exactly one source of error.
What you need before you start
A USB to RS485 adapter, a length of shielded twisted pair with a third conductor for the common, a device with power on it, and four facts off the datasheet. Without those four you are guessing, because the Modbus RTU transport negotiates none of them for you.
| Fact | Typical value | Where it bites |
|---|---|---|
| Server address | 1 to 247, default usually 1 | 0 is broadcast, 248 to 255 reserved |
| Baud rate | 9600 or 19200 | the only two the standard makes mandatory |
| Parity and stop bits | none or even, 1 stop bit | spec default is 19200 with even parity, devices often ship on something else |
| Register and function code | holding register 1 in datasheet numbering | input registers need FC04, holding registers FC03 |
An Eastron SDM630 energy meter ships on 9600 baud, no parity, one stop bit, address 1. Try that first on anything unknown. Getting the four facts off a datasheet is reading a Modbus register map; if the address is unknown, scanning a Modbus network is faster.
Connecting the adapter and finding the port
Your adapter turns up as a serial port, and the name depends on the operating system.
| System | Port name | How to find it |
|---|---|---|
| Linux | /dev/ttyUSB0 | ls /dev/ttyUSB* before and after plugging in |
| Windows | COM3 | Device Manager, under Ports (COM and LPT) |
| macOS | /dev/cu.usbserial-XXXXXXXX | ls /dev/cu.* |
On macOS the same adapter appears twice, as tty.* and as cu.*. Use cu.*: the tty.* variant waits for a carrier detect that an RS485 adapter never produces, so the command sits there looking like a dead bus.
You wire three conductors, not two: D0, D1 and the common. Leaving the common out is a classic source of intermittent faults, as RS485 explained covers.
The first command, argument by argument
Here is the whole thing: two holding registers from server 1, at 9600 baud with no parity.
mbpoll -m rtu -a 1 -b 9600 -P none -t 4 -r 1 -c 2 -1 /dev/ttyUSB0
| Argument | What it does |
|---|---|
-m rtu | Modbus RTU over a serial port |
-a 1 | server address 1 |
-b 9600 | baud rate 9600 |
-P none | no parity |
-t 4 | holding registers, FC03 on the wire |
-r 1 | start at register 1 in datasheet numbering |
-c 2 | read two registers |
-1 | poll once and stop |
/dev/ttyUSB0 | the serial port |
Change one argument and you cover the other common case. The measurements on an SDM630 sit in input registers, so -t 4 becomes -t 3, which puts FC04 on the wire instead of FC03. Grid frequency has PDU address 0x0046, decimal 70, so in the 1-based counting mbpoll uses that is -r 71.
mbpoll -m rtu -a 1 -b 9600 -P none -t 3 -r 71 -c 2 -1 /dev/ttyUSB0
Eastron requires an even number of registers per request on this meter, so -c 2 here is a condition and not a choice.
If you would rather have a window than a command line, the Register Explorer in ModbusCloud Diagnostics does the same read with fields for server address, port and register. This lesson stays on mbpoll, because the arguments show you exactly what goes out on the wire.
What you see when it works
Numbers, and a small statistic underneath them. mbpoll echoes the settings it will use, prints each register it read with its number in front, and on exit reports how many frames it sent and how many came back.
That statistic is the instrument you lean on in the next lesson: frames transmitted counts what went out, received what came back, and the gap between them is most of the diagnosis. Two values on screen prove the wiring, the baud rate, the parity, the address and the register in one go. Keep the request small while testing: FC03 and FC04 allow up to 125 registers, but many devices set a lower limit.
What you see when it does not
One of three pictures, and each points at a different part of the chain.
| What you see | What it means | Where to look |
|---|---|---|
| Silence, then a timeout | The frame never arrived, or was dropped unread | Wiring, baud rate, parity, address |
| An exception response | The frame arrived intact and was refused | Function code, register address, quantity |
| A value, but the wrong one | Communication is fine, interpretation is not | Data type, word order, scaling factor |
A response timeout of one second up to several seconds is normal at 9600 baud, so give the tool a moment. If you do not know the serial settings at all, sweep baud rate against framing and stop at the first combination that answers.
Working through the three in order is what Modbus RTU troubleshooting does next.
From register value to real unit
A register is 16 bits, so the number on your screen means whatever the datasheet says it means. An SMA inverter follows SunSpec and puts grid frequency in register 40202 as an integer, with the power of ten sitting in a scale register next to it. That scale register holds -2, so a raw 5001 is 5001 times 10 to the power -2, which is 50.01 Hz.
The same mechanism runs the other way. The same inverter publishes DC power with a scale factor of 2, so a raw value of 57 is 57 times 10 to the power 2, which is 5700 W and not 57 W.
An SDM630 solves it differently. Grid frequency arrives as an IEEE 754 float32 across two input registers, most significant register first. Read 42 48 in the first and 00 00 in the second, put them in that order, and the float is exactly 50.0 Hz. Swap the two registers and the number stops resembling a grid frequency at all. Why the same four bytes can yield four different numbers is worked out later in the course, in the lesson on word order and floats.
Then run the plausibility check. Mains voltage belongs roughly between 207 and 253 V, which is 230 V plus or minus 10 percent under EN 50160, and grid frequency sits around 50 Hz. A raw 5001 in a frequency field flags a missing factor instantly.
What to record before you close the panel
Four lines on a label at the terminal block, written the moment the reading works: baud rate, parity with stop bits, the server address, and which registers you read with which function code. The next engineer then skips the sweep you just did.
Once mbpoll reads the register, any other client will. That is the right order for connecting Modbus to Home Assistant too: prove the register on the command line, then write the configuration.
Common mistakes
Not knowing the tool's defaults. mbpoll starts from Modbus TCP at 19200 baud with even parity. Leave out -m rtu and you get a connection error that has nothing to do with the bus, after which people swap wires that were fine.
Choosing the tty.* port on macOS. The command looks hung, because it is waiting for a carrier detect that never comes. Use the cu.* name for the same adapter and it works.
Polling without -1 and assuming it crashed. Without that flag mbpoll keeps polling until you press Ctrl-C. That is the documented default, and the running counter is useful while you wiggle a terminal.
Changing several things at once. Swap the data pair, change the parity and try another address in one go, and you learn nothing from either outcome. One change, one attempt, one note.
Get hands-on
Eight steps, each with a check that rules out exactly one source of error.
- 1
Install mbpoll
Debian and Ubuntu:
sudo apt install mbpoll. macOS:brew install mbpoll. Check:mbpoll --helpprints the help text. - 2
Plug in the adapter
Check: the port appears, via
ls /dev/ttyUSB*or under Ports in Device Manager. - 3
Wire D0, D1 and the common
Check: measure the idle voltage across D0 and D1. D1 should sit positive, as RS485 explained describes.
- 4
Look up the four facts
Address, baud rate, parity with stop bits, register with function code. Check: you can write all four down.
- 5
Read two registers
Run the command below. Check: two numbers come back.
- 6
If nothing comes back, change one thing
Address first, then parity, then baud rate, then swap the data pair. Check: note what you changed each time.
- 7
Convert the value to its unit
Apply the scaling factor from the datasheet. Check: the order of magnitude is what you expected.
- 8
Label the terminal block
Check: someone else can read this device without phoning you.
mbpoll -m rtu -a 1 -b 9600 -P none -t 4 -r 1 -c 2 -1 /dev/ttyUSB0
Fill this in for your own device first:
server address ...... ____
baud rate ........... ____
parity, stop bits ... ____
register + FC ....... ____
raw value ____ x 10^____ = ____ unit: ____
No hardware. Install the simulator with python -m pip install "pymodbus[serial,simulator]==3.15.0" and start it with pymodbus.simulator --modbus_server server --modbus_device device. It listens on port 5020, so you need no root rights. Replace the serial arguments with -m tcp -p 5020 127.0.0.1 and take the same steps, without steps 2, 3 and 8.
mbpoll -m tcp -p 5020 -a 1 -t 4 -r 3 -c 1 -0 -1 127.0.0.1
The -0 switch makes mbpoll count from zero, so -r 3 is PDU address 3. The bundled dataset is built so you can practise all three pictures: PDU address 3 holds 17001 and returns it unchanged on every read, the float32 across PDU addresses 6 and 7 starts at 404.17 and climbs each time you ask, and PDU address 1 is configured as invalid and answers with a real exception. pymodbus is BSD-3 licensed and free to use, including commercially. On Linux and macOS, socat gives you a virtual serial pair so you can walk the RTU route end to end.
Expected result: two register values on screen, converted into a plausible unit, and a label on the panel.
Summary
- Reading a Modbus device needs four facts from the datasheet: server address, baud rate, parity with stop bits, and the register with its function code.
- mbpoll defaults to Modbus TCP at 19200 baud with even parity, so pass
-m rtu,-band-Pexplicitly rather than trusting the defaults. - One value on screen proves the wiring, the serial parameters, the address and the register at once.
- Silence points at the physical layer or the address, an exception points at the request, and a wrong number points at the data type or the scaling factor.
- Change one thing per attempt and note what you changed, because a fix you cannot reproduce is not a fix.
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.