Search code examples
pythonserial-portmodbuspymodbus

Pymodbus : Wrong byte count in response


We are requesting 14 responses from an RS485 device and sometimes the reply that we got doesn't have the 9 bytes that it is set-up. That is because it's replying sometimes in 3 arguments.

Normal: 
CALL->     01 04 00 00 00 02 71 CB 
RESPONSE-> 01 04 04 43 59 E6 66 F4 59


Error:
CALL->      01 04 00 00 00 02 71 CB 
RESPONSE -> 01 04 04 43
            59 CC CD AA 86 

When the error happens i get this msg from pymodbus:

DEBUG:pymodbus.transaction: Incomplete message received, Expected 9 bytes Recieved 4 bytes !!!!
DEBUG:pymodbus.transaction:Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
DEBUG:pymodbus.transaction:RECV: 0x1 0x4 0x4 0x3e
DEBUG:pymodbus.framer.rtu_framer:Frame check failed, ignoring!!
DEBUG:pymodbus.framer.rtu_framer:Resetting frame - Current Frame in buffer - 0x1 0x4 0x4 0x3e
DEBUG:pymodbus.transaction:Getting transaction 1
DEBUG:pymodbus.transaction:Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'

i've tried putting a sleep into the for so it dosn't colapse the device with calls but i get them either way. i've also read https://wingpath.co.uk/docs/modtest/troubleshoot.html and they say this:

"Wrong byte count in response: XXX when expecting XXX"

The byte count in the response sent by the slave is not what was expected for the count that ModTest sent in the request.

Turn on tracing to get more information.

Check that your slave is functioning correctly.

If you want ModTest to accept the response even though it is incorrect, you could deselect Strict Checking.

But i don't know how to active tracing on PYMODBUS, the function is correct and the other one is for a lib that i am not using i think

THE CODE LOOKS LIKE THIS

from __future__ import division
import pymodbus
import serial
from pymodbus.pdu import ModbusRequest
from pymodbus.client.sync import ModbusSerialClient as ModbusClient #initialize a serial RTU client instance
from pymodbus.transaction import ModbusRtuFramer
from time import sleep
from pymodbus.constants import Endian              # Nodig voor 32-bit float getallen (2 registers / 4 bytes)
from pymodbus.payload import BinaryPayloadDecoder  # Nodig voor 32-bit float getallen (2 registers / 4 bytes)
from pymodbus.payload import BinaryPayloadBuilder  # Nodig om 32-bit floats te schrijven naar register

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

#
method = "rtu"
port = "COM1"
baudrate = 2400
stopbits = 1
bytesize = 8
parity = "N"
timeout = 10 # I SET THIS TO 10 MAYBE IT WOULD HELP BUT DIDN'T
retries = 5  # SAME THING WITH THIS ONE
#
try:
    client = ModbusClient(method = method, port = port, stopbits = stopbits, bytesize = bytesize, parity = parity, baudrate = baudrate, timeout = timeout, retries = retries)
    connection = client.connect()
    print (connection)
except:
    print ("Modbus connectie error")
#
def 420 (y):
    variables = [0,6,12,18,24,30,36,70,72,74,76,78,342,344]
    labels = ["Voltage","Corriente","Potencia_Activa","Potencia_Aparente","Potencia_Reactiva","Factor_Potencia","Angulo_Fase","Frecuencia","Potencial_Activa_Consumida","Potencia_Activa_Inyectada","Potencia_Reactiva_Consumida","Potencia_Reactiva_Inyectada","Energia_Activa_Total","Energia_Reactiva_Total"]
    unidades = ["V","A","W","VA","VAr","%","Grados","HZ","kWh","kWh","kVArh","kVArh","kWh","kVArh"]
    LISTA = []
    h = 0
    hh = 0
    for xx in variables:
        try:
            data = client.read_input_registers(xx, 2, unit=1)
            decoder = BinaryPayloadDecoder.fromRegisters(data.registers, Endian.Big)
            eastron = round(decoder.decode_32bit_float(), 3)
            weaito = str(labels[h]) + " = " + str(eastron) + " " + str(unidades[hh])
            LISTA.append(weaito)
            h = h + 1
            hh = hh + 1
            sleep(0.5)
        except:
            print ("PICO")
            sleep(1)
    print(LISTA)

I Would love a way around the problem, maybe just consulting again until i get the right answer. I am not good with the try and except ones maybe there is the answer.


Solution

  • You seem to be experiencing a known issue with interchar spacing.

    There is an easy workaround though. First, make sure you're on pymodbus version 2.2.0 (you can do that opening a command line terminal on Windows and typing pip list if you have the path setup correctly, otherwise you have to move to your scripts Python folder where pip.exe is stored).

    Then change your code to add the strict argument declared to False:

    ....
    client = ModbusClient(method = method, port = port, stopbits = stopbits, bytesize = bytesize, parity = parity, baudrate = baudrate, timeout = timeout, retries = retries)
    client.strict = False    #Use Modbus interchar spacing as timeout to prevent missing data for low baudrates
    connection = client.connect()
    ...
    

    This will define the character spacing according to the Modbus spec, to 1.5 times the bit time at the selected baudrate, instead of using the default from socket.interCharTimeout:

    self._t0 = float((1 + 8 + 2)) / self.baudrate
    self.inter_char_timeout = 1.5 * self._t0
    

    If you can fix your issue with this solution, you should be able to reduce the overhead on your device reading the 28 registers you want in one go.

    If your issue is not solved, I think you might have a hardware issue. I would advise you to put your code aside for a while and try reading registers with QModMaster or something similar to make sure your hardware is performing as intended. (you might be getting noise or grounding issues that cut your frames short, if you want some pointers on that front please edit your question to include more details on your hardware, i.e.: kind of devices and how you're connecting them).