pymodbus-dev / pymodbus

A full modbus protocol written in python
Other
2.16k stars 889 forks source link

Build Proper Payload and write into register using Pymodbus #2168

Closed PythonLearnerV1 closed 2 months ago

PythonLearnerV1 commented 2 months ago

Hi,

I am pretty much new to Python and have working experience of around 6 months. I am using Pymodbus Package for Modbus communication. I have primarily 2 issues to deal with and it would be great if the PyModbus experts help me to resolve the issue.

Pymodbus Specific: Client TCP

Issue 1 : Scenario without using the Payload Builder:

I have to send an data ("142570XXXXX") to one of the register. I use "write.register" option to try & write the value to that register. But I get an error when trying to write this data. I try to write the value in hex (0x54fa8xxx). The code I try to use is

read = client.write_register(address=0xfxxx, value=0x54fa8xxx,unit=254) also tried read = client.write_register(address=0xfxxx, value=14257xxxxx,unit=254)

When I try either one above, I get an error from "register_write_message.py"

class WriteSingleRegisterRequest(ModbusRequest): . . def encode(self): packet = struct.pack('>H'. self.address) if self.skip_encode: packet += self.value else: packet += struct.pack('>H', self.value)

Error Message: 'H' format requires 0<= number <= 65535 and it exits out.

I researched and found I should be able to send data using Payload Builder. So I tried that.

Issue 2: Scenario using Payload Builder

Code example below:

client = ModbusTcpClient('x.x.x.x',502) client.connect()

builder = BinaryPayloadBuilder(byteorder = Endian.Big, wordorder = Endian.Big) builder.add_32bit_uint(0x54fa8xxxx)

payload = builder.build() address = 0xFxxx result = client.write_register(address, payload, unit=xxx, skip_encode=True)

When I try this, I get an error from "register_write_message.py"

class WriteSingleRegisterRequest(ModbusRequest): . . def encode(self): packet = struct.pack('>H'. self.address) if self.skip_encode: packet += self.value

I get an error from this location cant concat list to bytes When they payload is built the value is getting transformed to "xT\xfa,\x80\x00" and then throwing this error. Its not even sending this data to the Test Device. Not sure why I am getting T instead of 54 for the first 2 bytes there and get an error here. I should be able to send x54 x FA xXX xXX. I have tried various scenarios of this type below just to verify, but it doesnt work.

builder = BinaryPayloadBuilder(byteorder = Endian.Little, wordorder = Endian.Little) builder = BinaryPayloadBuilder(byteorder = Endian.Big, wordorder = Endian.Little) builder = BinaryPayloadBuilder(byteorder = Endian.Little, wordorder = Endian.Big)

It would be really great if Pymodbus/Modbus experts assist me in resolving this scenario. I would be glad to ask any questions, share queries required.

Exact Source Code:

**#!/usr/bin/env python

import pymodbus.client as modbusClient from pymodbus import Modbus Exception from pymodbus.constants import Endian from pymodbus.payload import BinaryPayloadDecoder from pymodbus.payload import BinaryPayloadBuilder from pymodbus.client.tcp import ModbusTcpClient from pymodbus.framer import ModbusSocketFramer

import logging logging.basicConfig() log = logging.getLogger() log.setLevel(logging.INFO)

client = ModbusTcpClient('192.168.xxx.xxxx', xxx) client.connect()

builder = BinaryPayloadBuilder() builder.add32bit_uint(0x54faxxxx)

payload = builder.build() address = 0xXXXX result = client.write_register(address, value = payload, slave=1, skip_encode=True)

print(result.registers) client.close()**

This is simple program I am having trouble to send the data. I know the data I have to send is 32bit uint because I have that working from windows from an different software. I need to have this implemented in python. Any assistance would be great.

FYI I have tried it without the binary payload builder with the same result.

Thank you Vignesh Sakthivelen

janiversen commented 2 months ago

We do not support version 2.5.3 that is very old please upgrade to version 3.6.8

PythonLearnerV1 commented 2 months ago

We do not support version 2.5.3 that is very old please upgrade to version 3.6.8

Thanks Jani. I have updated my Python and Pymodbus version to the latest ones.

Python: 3.12.0 Pymodbus: 3.6.8.

Same error is showing up.

Exception has occurred: TypeError can't concat list to bytes File "/home/pi/Projects/UR-DSP/pymodbus/register_write_message.py", line 48, in encode packet += self.value File "/home/pi/Projects/UR-DSP/pymodbus/framer/socket_framer.py", line 127, in buildPacket data = message.function_code.to_bytes(1, 'big') + message.encode() ^^^^^^^^^^^^^^^^ File "/home/pi/Projects/UR-DSP/pymodbus/transaction.py", line 296, in _transact packet = self.client.framer.buildPacket(packet) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/pi/Projects/UR-DSP/pymodbus/transaction.py", line 180, in execute response, last_exception = self._transact( ^^^^^^^^^^^^^^^ File "/home/pi/Projects/UR-DSP/pymodbus/client/base.py", line 396, in execute return self.transaction.execute(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/pi/Projects/UR-DSP/pymodbus/client/mixin.py", line 150, in write_register return self.execute( ^^^^^^^^^^^^^ File "/home/pi/Projects/UR-DSP/Modbus_Write_1.py", line 54, in result = client.write_register(address, payload, unit=254, skip_encode=True) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: can't concat list to bytes

Thank you Vignesh

janiversen commented 2 months ago

Did you remember to update your program, I do not see the updated source.

PythonLearnerV1 commented 2 months ago

Did you remember to update your program, I do not see the updated source.

Yes please. Kindly check the starting post. Its updated to accomodate the latest revision.

janiversen commented 2 months ago

But the write_register() is not updated to 3.6 standard.

Apart from that if you want to write 32bit, that is 2 registers which you do not specify.

Please take a look of our examples that seems the easier way.

PythonLearnerV1 commented 2 months ago

But the write_register() is not updated to 3.6 standard.

Apart from that if you want to write 32bit, that is 2 registers which you do not specify.

Please take a look of our examples that seems the easier way.

My apologies again. But I want to write 32 bit to one register, not 2 for my testing. Yes i have updated my write_register(address, value, slave) as per 3.6.8 standard for your reference.

Thank you Vignesh

janiversen commented 2 months ago

Modbus standard defines a register to be 16bit, so that is not possible.

If you have a device that defines a register to be 32bit, it does not follow the modbus standard and is not supported by pymodbus.

PythonLearnerV1 commented 2 months ago

Modbus standard defines a register to be 16bit, so that is not possible.

If you have a device that defines a register to be 32bit, it does not follow the modbus standard and is not supported by pymodbus.

Thank you for the response.

PythonLearnerV1 commented 2 months ago

It appears Pymodbus cannot be modified to send values outside the modbus standard. Again thanks for the help.

janiversen commented 2 months ago

Well at least not how you do it, but yes pymodbus follows the standard with the standard API, but allows for custom adaptations which would you allow to implement 32bit registers.