[SOLVED] Could someone help on this? I use minimalmodbus on python 3.11.1 to query a USB<->RS485 transceiver (see picture below) that is connected to a PZEM-016 (for measuring AC power consumption: voltage, current, power, energy, frequency...).
When used with the Simply Modbus Master 8.1.2, I can read the data without any problem.
With Python and minimalmodbus, I can only get up to 7 registers and of course the data is wrong (I can't pass the 7th register).
Here is the code
import minimalmodbus
#######################################
# CONSTANTS declaration
#######################################
# Communication constants
PORT_NAME ='COM3'
BAUD_RATE = 9600
BYTE_SIZE = 8
STOP_BITS = 1
TIMEOUT_VAL = 0.7
SLAVE_ADDR = 1
READ_MODE_NB = 4 # minimalmodus default to 3 PZEM requires 4 or it issues an error
WRITE_FCT_NB = 16 #HEX: 0x10
DEBUG_VAL = True
ECHO_VAL = False # Changed back from True to False after solution found
# Register constants
BASE_REG = 0
VOLT_REG = 0 #0x0000
CURR_LOW_REG = 1 #0x0001
CURR_HIGH_REG = 2 #0x0002
POWER_LOW_REG = 3 #0x0003
POWER_HIGH_REG = 4 #0x0004
ENGY_LOW_REG = 5 #0x0005
ENGY_HIGH_REG = 6 #0x0006
FREQCY_REG = 7 #0x0007
POWER_FACTOR_REG = 8 #0x0008
ALARM_REG = 9 #0x0009
#######################################
# Variables initialization
#######################################
instrument = ''
response = ''
voltage = ''
current_high = ''
current_low = ''
power_high = ''
power_low = ''
energy_high = ''
energy_low = ''
frequency = ''
power_factor = ''
alarm_status = ''
#######################################
# Set up the instrument
#######################################
instrument = minimalmodbus.Instrument(PORT_NAME, SLAVE_ADDR)
#######################################
# Explicit instrument settings
#######################################
instrument.serial.baudrate = BAUD_RATE # baud rate
instrument.serial.bytesize = BYTE_SIZE # data bits
instrument.serial.parity = minimalmodbus.serial.PARITY_NONE # parity
instrument.serial.stopbits = STOP_BITS # stop bit
instrument.serial.timeout = TIMEOUT_VAL # seconds
instrument.mode = minimalmodbus.MODE_RTU # communication protocol
# instrument.address = SLAVE_ADDR # slave address when only one slave in the bus
instrument.debug = DEBUG_VAL
instrument.handle_local_echo = ECHO_VAL
instrument.close_port_after_each_call = True
instrument.clear_buffers_before_each_transaction = True
#######################################
# Typical request format of the master
# Slave address: x001
# Command type: 0x04
# First register address high = left bytes: 0x00
# First register address low = right bytes: 0x00 (=> 0x0000 = 0)
# Number of registers high = left bytes: 0x00
# Number of registers low = right bytes: 0x0A (=> 0x000A = 10)
# CRC check high = left bytes: 0x70
# CRC check low = right bytes: 0x0D (=> 0x700D)
# 01 04 00 00 00 0A 70 0D
# Typical reply format of the slave
# Slave address: 0x01
# Command type: 0x04
# Number of bytes: 0x14 (= 20 bytes = 2 bytes per requested register)
# Register 1: Voltage 8 bits
# Register 1 data high byte = left byte: 0x09
# Register 1 data low byte = right byte: 0x2E (=> 0x092E = 2350 = 235.0V)
# Register 2 + 3: Current 16 bits
# Register 2 data low byte = right bits: 0x01
# Register 2 data high byte = left bits: 0x78
# Register 3 data low byte = right bits: 0x00
# Register 3 data high byte = left bits: 0x00 (=> 0x00000178 = 376 = 0.376A)
# Register 4 + 5: Power 16 bits
# Register 4 data low byte = right bits: 0x01
# Register 4 data high byte = left bits: 0xE7
# Register 5 data low byte = right bits: 0x00
# Register 5 data high byte = left bits: 0x00 (=> 0x000001E7 = 487 = 48.7W)
# Register 6 + 7: Energy 16 bits
# Register 6 data low byte = right bits: 0x02
# Register 6 data high byte = left bits: 0xEA
# Register 7 data low byte = right bits: 0x00
# Register 7 data high byte = left bits: 0x00 (=> 0x000002EA = 746 = 746Wh)
# Register 8: Frequency 8 bits
# Register 8 data high byte = left byte: 0x01
# Register 8 data low byte = right byte: 0xF4 (=> 0x01F4 = 500 = 50.0Hz)
# Register 9: Power factor 8 bits
# Register 9 data high byte = left byte: 0x00
# Register 9 data low byte = right byte: 0x37 (=> 0x0037 = 55 = 0.55)
# Register 10: Alarm status 8 bits
# Register 10 data high byte = left byte: 0x00
# Register 10 data low byte = right byte: 0x00 (=> 0x0000 = 0 = No alarm)
# CRC check high = left bytes: 0xE5 (= 229)
# CRC check low = right bytes: 0xFD (= 253) (=> 0xE5FD)
# LED lights turned on
# 01 04 14 09 2E 01 78 00 00 01 E7 00 00 02 EA 00 00 01 F4 00 37 00 00 39 51
# LED lights turned off
# 01 04 14 09 34 00 00 00 00 00 05 00 00 02 E4 00 00 01 F3 00 64 00 00 E5 FD
#######################################
print('instrument: ', instrument)
#######################################
# Read and print registers' data
#######################################
response = instrument.read_registers(VOLT_REG, 10, READ_MODE_NB)
print('Response raw: ', response)
With the wrong read mode value, I get an error message with the read_registers() command
>>> ReadSerial.py
< MinimalModbus debug mode. Will write to instrument (expecting 25 bytes back): 01 03 00 00 00 0A C5 CD (8 bytes)
MinimalModbus debug mode. Clearing serial buffers for port COM3
MinimalModbus debug mode. No sleep required before write. Time since previous read: 167521078.00 ms, minimum silent period: 4.01 ms.
MinimalModbus debug mode. Closing port COM3
MinimalModbus debug mode. Response from instrument: 01 83 02 C0 F1 (5 bytes), roundtrip time: 0.8 ms. Timeout for reading: 700.0 ms.
< Traceback (most recent call last):
File "...\ReadSerial.py", line 127, in <module>
response = instrument.read_registers(VOLT_REG, 10, READ_MODE_NB)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "...\minimalmodbus.py", line 904, in read_registers
returnvalue = self._generic_command(
^^^^^^^^^^^^^^^^^^^^^^
File "...\minimalmodbus.py", line 1245, in _generic_command
payload_from_slave = self._perform_command(functioncode, payload_to_slave)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "...\minimalmodbus.py", line 1329, in _perform_command
payload_from_slave = _extract_payload(
^^^^^^^^^^^^^^^^^
File "...\minimalmodbus.py", line 1880, in _extract_payload
_check_response_slaveerrorcode(response)
File "...\minimalmodbus.py", line 3538, in _check_response_slaveerrorcode
raise error
minimalmodbus.IllegalRequestError: Slave reported illegal data address
I matched everything I could with the Simply Modbus Master example, except for the query mode, which value should be 4 (minimalmodbus default read mode is 3).
Update from above
I finally found the error in my code, which was very stupid, but errors are often stupid like a missing ";".
I still have to figure out why the read_register() command doesn't work (without the "s" for reading one register at a time). I can't pass the 7th register without errors and the returned data is wrong.
I leave the question and the answer for the community, in case someone uses the same PZEM-014 -> PZEM0-17 and looks for a python solution to retrieve the data