sourceperl / pyModbusTCP

A simple Modbus/TCP library for Python
MIT License
297 stars 104 forks source link

_transaction_id too high integers for huawei sun2000 #82

Open volviq opened 5 months ago

volviq commented 5 months ago

I can successfully connect via https://github.com/wlcrs/huawei_solar and HomeAssistants with the PV inverter. I tried a similar connection with pyModbusTCP and the inverter just does not respond. Comparing the packages with Wireshark, it shows that HomeAssistants plugin starts with transaction id "0" and counts up incrementally. pyModbusTCP uses a random int between 0-65535. I do not find an interface to control this behavior. Hence I can not prove, this is the issue, but it would be good to be able to control this.

sourceperl commented 5 months ago

Hi,

For test purpose, you can use this code to replace transaction ID handling with custom handling:

import random
import struct
import time
from pyModbusTCP.client import ModbusClient

class CustomModbusClient(ModbusClient):
    # override _add_mbap method to manualy set transation_id before each request
    def _add_mbap(self, pdu):
        """Return full modbus frame with MBAP (modbus application protocol header) append to PDU.

        :param pdu: modbus PDU (protocol data unit)
        :type pdu: bytes
        :returns: full modbus frame
        :rtype: bytes
        """
        # build MBAP
        # neutralizes transaction ID increment
        #self._transaction_id = random.randint(0, 65535)
        protocol_id = 0
        length = len(pdu) + 1
        mbap = struct.pack('>HHHB', self._transaction_id, protocol_id, length, self.unit_id)
        # full modbus/TCP frame = [MBAP]PDU
        return mbap + pdu

# custom modbus client
c = CustomModbusClient(host='10.8.10.1', port=502, debug=True)

# read loop
while True:
    for tr_id in range(0, 0x10000):
        # set transaction id
        c._transaction_id = tr_id
        # request
        ret_read = c.read_holding_registers(0, 1)
        print(f'{ret_read}')
        # 2s before next request
        time.sleep(2)